mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-14 17:12:08 +00:00
Audio Module: format messages better
This commit is contained in:
parent
6c84b3f01c
commit
3cde75f97b
@ -71,27 +71,22 @@ void run_codec2(void* parameter)
|
|||||||
// 4 bytes of header in each frame hex c0 de c2 plus the bitrate
|
// 4 bytes of header in each frame hex c0 de c2 plus the bitrate
|
||||||
memcpy(audioModule->tx_encode_frame,&audioModule->tx_header,sizeof(audioModule->tx_header));
|
memcpy(audioModule->tx_encode_frame,&audioModule->tx_header,sizeof(audioModule->tx_header));
|
||||||
|
|
||||||
|
DEBUG_MSG("Starting codec2 task\n");
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
uint32_t tcount = ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(10000));
|
uint32_t tcount = ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(10000));
|
||||||
|
|
||||||
if (tcount != 0) {
|
if (tcount != 0) {
|
||||||
if (audioModule->radio_state == RadioState::tx) {
|
if (audioModule->radio_state == RadioState::tx) {
|
||||||
|
|
||||||
// Apply the TX filter
|
|
||||||
for (int i = 0; i < audioModule->adc_buffer_size; i++)
|
for (int i = 0; i < audioModule->adc_buffer_size; i++)
|
||||||
audioModule->speech[i] = (int16_t)hp_filter.Update((float)audioModule->speech[i]);
|
audioModule->speech[i] = (int16_t)hp_filter.Update((float)audioModule->speech[i]);
|
||||||
|
|
||||||
// Encode the audio
|
|
||||||
codec2_encode(audioModule->codec2, audioModule->tx_encode_frame + audioModule->tx_encode_frame_index, audioModule->speech);
|
codec2_encode(audioModule->codec2, audioModule->tx_encode_frame + audioModule->tx_encode_frame_index, audioModule->speech);
|
||||||
|
|
||||||
//increment the pointer where the encoded frame must be saved
|
|
||||||
audioModule->tx_encode_frame_index += audioModule->encode_codec_size;
|
audioModule->tx_encode_frame_index += audioModule->encode_codec_size;
|
||||||
|
|
||||||
//If it this is reached we have a ready trasnmission frame
|
|
||||||
if (audioModule->tx_encode_frame_index == (audioModule->encode_frame_size + sizeof(audioModule->tx_header)))
|
if (audioModule->tx_encode_frame_index == (audioModule->encode_frame_size + sizeof(audioModule->tx_header)))
|
||||||
{
|
{
|
||||||
//Transmit it
|
DEBUG_MSG("Sending %d codec2 bytes\n", audioModule->encode_frame_size);
|
||||||
DEBUG_MSG("♪♫♪ Sending %d codec2 bytes\n", audioModule->encode_frame_size);
|
|
||||||
audioModule->sendPayload();
|
audioModule->sendPayload();
|
||||||
audioModule->tx_encode_frame_index = sizeof(audioModule->tx_header);
|
audioModule->tx_encode_frame_index = sizeof(audioModule->tx_header);
|
||||||
}
|
}
|
||||||
@ -99,10 +94,8 @@ void run_codec2(void* parameter)
|
|||||||
if (audioModule->radio_state == RadioState::rx) {
|
if (audioModule->radio_state == RadioState::rx) {
|
||||||
size_t bytesOut = 0;
|
size_t bytesOut = 0;
|
||||||
if (memcmp(audioModule->rx_encode_frame, &audioModule->tx_header, sizeof(audioModule->tx_header)) == 0) {
|
if (memcmp(audioModule->rx_encode_frame, &audioModule->tx_header, sizeof(audioModule->tx_header)) == 0) {
|
||||||
// Make a cycle to get each codec2 frame from the received frame
|
|
||||||
for (int i = 4; i < audioModule->rx_encode_frame_index; i += audioModule->encode_codec_size)
|
for (int i = 4; i < audioModule->rx_encode_frame_index; i += audioModule->encode_codec_size)
|
||||||
{
|
{
|
||||||
//Decode the codec2 frame
|
|
||||||
codec2_decode(audioModule->codec2, audioModule->output_buffer, audioModule->rx_encode_frame + i);
|
codec2_decode(audioModule->codec2, audioModule->output_buffer, audioModule->rx_encode_frame + i);
|
||||||
i2s_write(I2S_PORT, &audioModule->output_buffer, audioModule->adc_buffer_size, &bytesOut, pdMS_TO_TICKS(500));
|
i2s_write(I2S_PORT, &audioModule->output_buffer, audioModule->adc_buffer_size, &bytesOut, pdMS_TO_TICKS(500));
|
||||||
}
|
}
|
||||||
@ -112,10 +105,8 @@ void run_codec2(void* parameter)
|
|||||||
codec2_set_lpc_post_filter(tmp_codec2, 1, 0, 0.8, 0.2);
|
codec2_set_lpc_post_filter(tmp_codec2, 1, 0, 0.8, 0.2);
|
||||||
int tmp_encode_codec_size = (codec2_bits_per_frame(tmp_codec2) + 7) / 8;
|
int tmp_encode_codec_size = (codec2_bits_per_frame(tmp_codec2) + 7) / 8;
|
||||||
int tmp_adc_buffer_size = codec2_samples_per_frame(tmp_codec2);
|
int tmp_adc_buffer_size = codec2_samples_per_frame(tmp_codec2);
|
||||||
// Make a cycle to get each codec2 frame from the received frame
|
|
||||||
for (int i = 4; i < audioModule->rx_encode_frame_index; i += tmp_encode_codec_size)
|
for (int i = 4; i < audioModule->rx_encode_frame_index; i += tmp_encode_codec_size)
|
||||||
{
|
{
|
||||||
//Decode the codec2 frame
|
|
||||||
codec2_decode(tmp_codec2, audioModule->output_buffer, audioModule->rx_encode_frame + i);
|
codec2_decode(tmp_codec2, audioModule->output_buffer, audioModule->rx_encode_frame + i);
|
||||||
i2s_write(I2S_PORT, &audioModule->output_buffer, tmp_adc_buffer_size, &bytesOut, pdMS_TO_TICKS(500));
|
i2s_write(I2S_PORT, &audioModule->output_buffer, tmp_adc_buffer_size, &bytesOut, pdMS_TO_TICKS(500));
|
||||||
}
|
}
|
||||||
@ -128,8 +119,15 @@ void run_codec2(void* parameter)
|
|||||||
|
|
||||||
AudioModule::AudioModule() : SinglePortModule("AudioModule", PortNum_AUDIO_APP), concurrency::OSThread("AudioModule")
|
AudioModule::AudioModule() : SinglePortModule("AudioModule", PortNum_AUDIO_APP), concurrency::OSThread("AudioModule")
|
||||||
{
|
{
|
||||||
|
// moduleConfig.audio.codec2_enabled = true;
|
||||||
|
// moduleConfig.audio.i2s_ws = 13;
|
||||||
|
// moduleConfig.audio.i2s_sd = 15;
|
||||||
|
// moduleConfig.audio.i2s_din = 22;
|
||||||
|
// moduleConfig.audio.i2s_sck = 14;
|
||||||
|
// moduleConfig.audio.ptt_pin = 39;
|
||||||
|
|
||||||
if ((moduleConfig.audio.codec2_enabled) && (myRegion->audioPermitted)) {
|
if ((moduleConfig.audio.codec2_enabled) && (myRegion->audioPermitted)) {
|
||||||
DEBUG_MSG("♪♫♪ Setting up codec2 in mode %u", (moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE) - 1);
|
DEBUG_MSG("Setting up codec2 in mode %u", (moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE) - 1);
|
||||||
codec2 = codec2_create((moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE) - 1);
|
codec2 = codec2_create((moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE) - 1);
|
||||||
memcpy(tx_header.magic,c2_magic,sizeof(c2_magic));
|
memcpy(tx_header.magic,c2_magic,sizeof(c2_magic));
|
||||||
tx_header.mode = (moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE) - 1;
|
tx_header.mode = (moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE) - 1;
|
||||||
@ -141,7 +139,7 @@ AudioModule::AudioModule() : SinglePortModule("AudioModule", PortNum_AUDIO_APP),
|
|||||||
DEBUG_MSG(" using %d frames of %d bytes for a total payload length of %d bytes\n", encode_frame_num, encode_codec_size, encode_frame_size);
|
DEBUG_MSG(" using %d frames of %d bytes for a total payload length of %d bytes\n", encode_frame_num, encode_codec_size, encode_frame_size);
|
||||||
xTaskCreate(&run_codec2, "codec2_task", 30000, NULL, 5, &codec2HandlerTask);
|
xTaskCreate(&run_codec2, "codec2_task", 30000, NULL, 5, &codec2HandlerTask);
|
||||||
} else {
|
} else {
|
||||||
DEBUG_MSG("♪♫♪ Codec2 disabled (AudioModule %d, Region %s, permitted %d)\n", moduleConfig.audio.codec2_enabled, myRegion->name, myRegion->audioPermitted);
|
DEBUG_MSG("Codec2 disabled (AudioModule %d, Region %s, permitted %d)\n", moduleConfig.audio.codec2_enabled, myRegion->name, myRegion->audioPermitted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +173,7 @@ int32_t AudioModule::runOnce()
|
|||||||
esp_err_t res;
|
esp_err_t res;
|
||||||
if (firstTime) {
|
if (firstTime) {
|
||||||
// Set up I2S Processor configuration. This will produce 16bit samples at 8 kHz instead of 12 from the ADC
|
// Set up I2S Processor configuration. This will produce 16bit samples at 8 kHz instead of 12 from the ADC
|
||||||
DEBUG_MSG("♪♫♪ Initializing I2S SD: %d DIN: %d WS: %d SCK:%d\n", moduleConfig.audio.i2s_sd, moduleConfig.audio.i2s_din, moduleConfig.audio.i2s_ws, moduleConfig.audio.i2s_sck);
|
DEBUG_MSG("Initializing I2S SD: %d DIN: %d WS: %d SCK: %d\n", moduleConfig.audio.i2s_sd, moduleConfig.audio.i2s_din, moduleConfig.audio.i2s_ws, moduleConfig.audio.i2s_sck);
|
||||||
i2s_config_t i2s_config = {
|
i2s_config_t i2s_config = {
|
||||||
.mode = (i2s_mode_t)(I2S_MODE_MASTER | (moduleConfig.audio.i2s_sd ? I2S_MODE_RX : 0) | (moduleConfig.audio.i2s_din ? I2S_MODE_TX : 0)),
|
.mode = (i2s_mode_t)(I2S_MODE_MASTER | (moduleConfig.audio.i2s_sd ? I2S_MODE_RX : 0) | (moduleConfig.audio.i2s_din ? I2S_MODE_TX : 0)),
|
||||||
.sample_rate = 8000,
|
.sample_rate = 8000,
|
||||||
@ -191,7 +189,7 @@ int32_t AudioModule::runOnce()
|
|||||||
};
|
};
|
||||||
res = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
|
res = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
|
||||||
if(res != ESP_OK)
|
if(res != ESP_OK)
|
||||||
DEBUG_MSG("♪♫♪ Failed to install I2S driver: %d\n", res);
|
DEBUG_MSG("Failed to install I2S driver: %d\n", res);
|
||||||
|
|
||||||
const i2s_pin_config_t pin_config = {
|
const i2s_pin_config_t pin_config = {
|
||||||
.bck_io_num = moduleConfig.audio.i2s_sck,
|
.bck_io_num = moduleConfig.audio.i2s_sck,
|
||||||
@ -201,16 +199,16 @@ int32_t AudioModule::runOnce()
|
|||||||
};
|
};
|
||||||
res = i2s_set_pin(I2S_PORT, &pin_config);
|
res = i2s_set_pin(I2S_PORT, &pin_config);
|
||||||
if(res != ESP_OK)
|
if(res != ESP_OK)
|
||||||
DEBUG_MSG("♪♫♪ Failed to set I2S pin config: %d\n", res);
|
DEBUG_MSG("Failed to set I2S pin config: %d\n", res);
|
||||||
|
|
||||||
res = i2s_start(I2S_PORT);
|
res = i2s_start(I2S_PORT);
|
||||||
if(res != ESP_OK)
|
if(res != ESP_OK)
|
||||||
DEBUG_MSG("♪♫♪ Failed to start I2S: %d\n", res);
|
DEBUG_MSG("Failed to start I2S: %d\n", res);
|
||||||
|
|
||||||
radio_state = RadioState::rx;
|
radio_state = RadioState::rx;
|
||||||
|
|
||||||
// Configure PTT input
|
// Configure PTT input
|
||||||
DEBUG_MSG("♪♫♪ Initializing PTT on Pin %u\n", moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN);
|
DEBUG_MSG("Initializing PTT on Pin %u\n", moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN);
|
||||||
pinMode(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN, INPUT);
|
pinMode(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN, INPUT);
|
||||||
|
|
||||||
firstTime = false;
|
firstTime = false;
|
||||||
@ -219,19 +217,19 @@ int32_t AudioModule::runOnce()
|
|||||||
// Check if PTT is pressed. TODO hook that into Onebutton/Interrupt drive.
|
// Check if PTT is pressed. TODO hook that into Onebutton/Interrupt drive.
|
||||||
if (digitalRead(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN) == HIGH) {
|
if (digitalRead(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN) == HIGH) {
|
||||||
if (radio_state == RadioState::rx) {
|
if (radio_state == RadioState::rx) {
|
||||||
DEBUG_MSG("♪♫♪ PTT pressed, switching to TX\n");
|
DEBUG_MSG("PTT pressed, switching to TX\n");
|
||||||
radio_state = RadioState::tx;
|
radio_state = RadioState::tx;
|
||||||
e.frameChanged = true;
|
e.frameChanged = true;
|
||||||
this->notifyObservers(&e);
|
this->notifyObservers(&e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (radio_state == RadioState::tx) {
|
if (radio_state == RadioState::tx) {
|
||||||
|
DEBUG_MSG("PTT released, switching to RX\n");
|
||||||
if (tx_encode_frame_index > sizeof(tx_header)) {
|
if (tx_encode_frame_index > sizeof(tx_header)) {
|
||||||
// Send the incomplete frame
|
// Send the incomplete frame
|
||||||
DEBUG_MSG("♪♫♪ Sending %d codec2 bytes (incomplete)\n", tx_encode_frame_index);
|
DEBUG_MSG("Sending %d codec2 bytes (incomplete)\n", tx_encode_frame_index);
|
||||||
sendPayload();
|
sendPayload();
|
||||||
}
|
}
|
||||||
DEBUG_MSG("♪♫♪ PTT released, switching to RX\n");
|
|
||||||
tx_encode_frame_index = sizeof(tx_header);
|
tx_encode_frame_index = sizeof(tx_header);
|
||||||
radio_state = RadioState::rx;
|
radio_state = RadioState::rx;
|
||||||
e.frameChanged = true;
|
e.frameChanged = true;
|
||||||
@ -260,7 +258,7 @@ int32_t AudioModule::runOnce()
|
|||||||
}
|
}
|
||||||
return 100;
|
return 100;
|
||||||
} else {
|
} else {
|
||||||
DEBUG_MSG("♪♫♪ Audio Module Disabled\n");
|
DEBUG_MSG("Audio Module Disabled\n");
|
||||||
return INT32_MAX;
|
return INT32_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +266,7 @@ int32_t AudioModule::runOnce()
|
|||||||
|
|
||||||
MeshPacket *AudioModule::allocReply()
|
MeshPacket *AudioModule::allocReply()
|
||||||
{
|
{
|
||||||
auto reply = allocDataPacket(); // Allocate a packet for sending
|
auto reply = allocDataPacket();
|
||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,7 +284,7 @@ void AudioModule::sendPayload(NodeNum dest, bool wantReplies)
|
|||||||
p->to = dest;
|
p->to = dest;
|
||||||
p->decoded.want_response = wantReplies;
|
p->decoded.want_response = wantReplies;
|
||||||
|
|
||||||
p->want_ack = false; // Audio is shoot&forget. TODO: Is this really suppressing retransmissions?
|
p->want_ack = false; // Audio is shoot&forget. No need to wait for ACKs.
|
||||||
p->priority = MeshPacket_Priority_MAX; // Audio is important, because realtime
|
p->priority = MeshPacket_Priority_MAX; // Audio is important, because realtime
|
||||||
|
|
||||||
p->decoded.payload.size = tx_encode_frame_index;
|
p->decoded.payload.size = tx_encode_frame_index;
|
||||||
|
Loading…
Reference in New Issue
Block a user