|
@@ -29,7 +29,7 @@
|
|
|
#include "esp_g711_enc.h"
|
|
#include "esp_g711_enc.h"
|
|
|
#include "esp_g711_dec.h"*/
|
|
#include "esp_g711_dec.h"*/
|
|
|
|
|
|
|
|
-#define ESP32_IP ""
|
|
|
|
|
|
|
+#define ESP32_IP "192.168.68.67"
|
|
|
#define RTP_PORT 4000
|
|
#define RTP_PORT 4000
|
|
|
|
|
|
|
|
#define WIFI_SSID ""
|
|
#define WIFI_SSID ""
|
|
@@ -47,11 +47,13 @@
|
|
|
#define TONE_FREQ 1000
|
|
#define TONE_FREQ 1000
|
|
|
|
|
|
|
|
|
|
|
|
|
-#define MIC_FRAME_SAMPLES 160
|
|
|
|
|
|
|
+#define MIC_FRAME_SAMPLES 320
|
|
|
|
|
+#define AEC_MAX_FRAME_SAMPLES 512
|
|
|
|
|
+#define FAR_END_FIFO_SAMPLES 2048
|
|
|
|
|
|
|
|
static int32_t mic_buffer[320];
|
|
static int32_t mic_buffer[320];
|
|
|
-static int16_t mic_pcm16[MIC_FRAME_SAMPLES];
|
|
|
|
|
-static uint8_t payload[MIC_FRAME_SAMPLES];
|
|
|
|
|
|
|
+static int16_t mic_pcm16[SAMPLES_PER_PACKET];
|
|
|
|
|
+static uint8_t payload[SAMPLES_PER_PACKET];
|
|
|
|
|
|
|
|
static uint8_t rx_packet[172];
|
|
static uint8_t rx_packet[172];
|
|
|
static int16_t speaker_pcm[160];
|
|
static int16_t speaker_pcm[160];
|
|
@@ -65,6 +67,16 @@ static uint16_t s_rtp_peer_port = 0;
|
|
|
static volatile bool call_active = false;
|
|
static volatile bool call_active = false;
|
|
|
static volatile bool s_audio_hw_ready = false;
|
|
static volatile bool s_audio_hw_ready = false;
|
|
|
|
|
|
|
|
|
|
+static int16_t far_end_fifo[FAR_END_FIFO_SAMPLES];
|
|
|
|
|
+static size_t far_end_read = 0;
|
|
|
|
|
+static size_t far_end_write = 0;
|
|
|
|
|
+static portMUX_TYPE far_end_mux = portMUX_INITIALIZER_UNLOCKED;
|
|
|
|
|
+static int16_t aec_mic_pending[AEC_MAX_FRAME_SAMPLES];
|
|
|
|
|
+static int16_t aec_ref_pending[AEC_MAX_FRAME_SAMPLES];
|
|
|
|
|
+static size_t aec_pending_samples = 0;
|
|
|
|
|
+static int16_t aec_output_fifo[FAR_END_FIFO_SAMPLES];
|
|
|
|
|
+static size_t aec_output_samples = 0;
|
|
|
|
|
+
|
|
|
esp_err_t esp_get_feed_data(
|
|
esp_err_t esp_get_feed_data(
|
|
|
bool is_get_raw_channel,
|
|
bool is_get_raw_channel,
|
|
|
int16_t *buffer,
|
|
int16_t *buffer,
|
|
@@ -78,6 +90,86 @@ esp_err_t sip_media_init(void);
|
|
|
static void rtp_tx_task(void *pvParameters);
|
|
static void rtp_tx_task(void *pvParameters);
|
|
|
static void rtp_rx_task(void *pvParameters);
|
|
static void rtp_rx_task(void *pvParameters);
|
|
|
|
|
|
|
|
|
|
+static void far_end_push(const int16_t *samples, size_t count)
|
|
|
|
|
+{
|
|
|
|
|
+ portENTER_CRITICAL(&far_end_mux);
|
|
|
|
|
+ for (size_t i = 0; i < count; ++i) {
|
|
|
|
|
+ size_t next = (far_end_write + 1) % FAR_END_FIFO_SAMPLES;
|
|
|
|
|
+ if (next == far_end_read) {
|
|
|
|
|
+ far_end_read = (far_end_read + 1) % FAR_END_FIFO_SAMPLES;
|
|
|
|
|
+ }
|
|
|
|
|
+ far_end_fifo[far_end_write] = samples[i];
|
|
|
|
|
+ far_end_write = next;
|
|
|
|
|
+ }
|
|
|
|
|
+ portEXIT_CRITICAL(&far_end_mux);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void far_end_pop(int16_t *samples, size_t count)
|
|
|
|
|
+{
|
|
|
|
|
+ portENTER_CRITICAL(&far_end_mux);
|
|
|
|
|
+ for (size_t i = 0; i < count; ++i) {
|
|
|
|
|
+ if (far_end_read == far_end_write) {
|
|
|
|
|
+ samples[i] = 0;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ samples[i] = far_end_fifo[far_end_read];
|
|
|
|
|
+ far_end_read = (far_end_read + 1) % FAR_END_FIFO_SAMPLES;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ portEXIT_CRITICAL(&far_end_mux);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static bool aec_process_capture(const int16_t *near_end,
|
|
|
|
|
+ const int16_t *far_end,
|
|
|
|
|
+ size_t sample_count)
|
|
|
|
|
+{
|
|
|
|
|
+ int frame_size = bsp_aec_get_frame_size();
|
|
|
|
|
+ if (frame_size <= 0 || frame_size > AEC_MAX_FRAME_SAMPLES) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (size_t i = 0; i < sample_count; ++i) {
|
|
|
|
|
+ if (aec_pending_samples == AEC_MAX_FRAME_SAMPLES) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ aec_mic_pending[aec_pending_samples] = near_end[i];
|
|
|
|
|
+ aec_ref_pending[aec_pending_samples] = far_end[i];
|
|
|
|
|
+ ++aec_pending_samples;
|
|
|
|
|
+
|
|
|
|
|
+ if (aec_pending_samples == (size_t)frame_size) {
|
|
|
|
|
+ int16_t processed[AEC_MAX_FRAME_SAMPLES];
|
|
|
|
|
+ if (bsp_aec_process_frame(aec_mic_pending,
|
|
|
|
|
+ aec_ref_pending,
|
|
|
|
|
+ processed) != ESP_OK) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* AEC runs at 16 kHz. The negotiated PCMU stream is 8 kHz,
|
|
|
|
|
+ * so retain every second cleaned sample for RTP encoding. */
|
|
|
|
|
+ for (int sample = 0; sample < frame_size; sample += 2) {
|
|
|
|
|
+ if (aec_output_samples < FAR_END_FIFO_SAMPLES) {
|
|
|
|
|
+ aec_output_fifo[aec_output_samples++] = processed[sample];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ aec_pending_samples = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static bool aec_output_pop(int16_t *samples, size_t count)
|
|
|
|
|
+{
|
|
|
|
|
+ if (aec_output_samples < count) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ memcpy(samples, aec_output_fifo, count * sizeof(int16_t));
|
|
|
|
|
+ memmove(aec_output_fifo,
|
|
|
|
|
+ aec_output_fifo + count,
|
|
|
|
|
+ (aec_output_samples - count) * sizeof(int16_t));
|
|
|
|
|
+ aec_output_samples -= count;
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/* ================= WIFI ================= */
|
|
/* ================= WIFI ================= */
|
|
|
|
|
|
|
|
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
|
|
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
|
|
@@ -306,16 +398,13 @@ static bool sip_extract_rtp_port(const char *msg, uint16_t *out_port)
|
|
|
|
|
|
|
|
static bool microphone_read(int16_t *samples, size_t count)
|
|
static bool microphone_read(int16_t *samples, size_t count)
|
|
|
{
|
|
{
|
|
|
- ESP_LOGI(TAG,
|
|
|
|
|
- "mic ptr=%p samples=%d bytes=%d",
|
|
|
|
|
- samples,
|
|
|
|
|
- count,
|
|
|
|
|
- count * sizeof(int16_t));
|
|
|
|
|
|
|
+ // ESP_LOGI(TAG,
|
|
|
|
|
+ // "mic ptr=%p samples=%d bytes=%d",
|
|
|
|
|
+ // samples,
|
|
|
|
|
+ // count,
|
|
|
|
|
+ // count * sizeof(int16_t));
|
|
|
|
|
|
|
|
- esp_err_t ret = esp_get_feed_data(
|
|
|
|
|
- false,
|
|
|
|
|
- (int16_t *)mic_buffer,
|
|
|
|
|
- sizeof(mic_buffer));
|
|
|
|
|
|
|
+ esp_err_t ret = esp_get_feed_data(false, samples, count);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -430,7 +519,6 @@ ESP_LOGI(TAG,
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
if(s_rtp_sock < 0)
|
|
if(s_rtp_sock < 0)
|
|
|
{
|
|
{
|
|
|
s_rtp_sock = socket(AF_INET,
|
|
s_rtp_sock = socket(AF_INET,
|
|
@@ -472,33 +560,26 @@ else
|
|
|
uint8_t payload[SAMPLES_PER_PACKET];
|
|
uint8_t payload[SAMPLES_PER_PACKET];
|
|
|
|
|
|
|
|
|
|
|
|
|
-// Read microphone data
|
|
|
|
|
-if(!microphone_read(
|
|
|
|
|
- (int16_t *)mic_buffer,
|
|
|
|
|
- sizeof(mic_buffer)))
|
|
|
|
|
|
|
+ // Read one 20 ms stereo capture block (320 mono samples at 16 kHz).
|
|
|
|
|
+ if (!microphone_read((int16_t *)mic_buffer, sizeof(mic_buffer)))
|
|
|
{
|
|
{
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
-int16_t *mic16 = (int16_t *)mic_buffer;
|
|
|
|
|
-/*
|
|
|
|
|
-ESP_LOGI("MIC",
|
|
|
|
|
-"pcm16=%d %d %d %d",
|
|
|
|
|
-mic16[0],
|
|
|
|
|
-mic16[1],
|
|
|
|
|
-mic16[2],
|
|
|
|
|
-mic16[3]);*/
|
|
|
|
|
-
|
|
|
|
|
-// Convert 32-bit audio to PCM16
|
|
|
|
|
-for(int i = 0; i < SAMPLES_PER_PACKET; i++)
|
|
|
|
|
-{
|
|
|
|
|
- // Take microphone channel
|
|
|
|
|
-int32_t s = mic_buffer[i * 2];
|
|
|
|
|
|
|
+ int16_t *mic16 = (int16_t *)mic_buffer;
|
|
|
|
|
+ int16_t near_end[MIC_FRAME_SAMPLES];
|
|
|
|
|
+ int16_t far_end[MIC_FRAME_SAMPLES];
|
|
|
|
|
+
|
|
|
|
|
+ for (int i = 0; i < MIC_FRAME_SAMPLES; ++i) {
|
|
|
|
|
+ int32_t left = mic16[i * 2];
|
|
|
|
|
+ int32_t right = mic16[i * 2 + 1];
|
|
|
|
|
+ near_end[i] = (int16_t)((left + right) / 2);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-// Trying these one at a time
|
|
|
|
|
-//mic_pcm16[i] = s >> 16;
|
|
|
|
|
- //mic_pcm16[i] = s >> 15;
|
|
|
|
|
- mic_pcm16[i] = s >> 14;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ far_end_pop(far_end, MIC_FRAME_SAMPLES);
|
|
|
|
|
+ if (!aec_process_capture(near_end, far_end, MIC_FRAME_SAMPLES) ||
|
|
|
|
|
+ !aec_output_pop(mic_pcm16, SAMPLES_PER_PACKET)) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
|
|
|
// Debug microphone level
|
|
// Debug microphone level
|
|
@@ -745,7 +826,28 @@ static void rtp_rx_task(void *pvParameters)
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-ESP_LOGI(TAG, "Received RTP packet (%d bytes)", n);
|
|
|
|
|
|
|
+if (s_rtp_peer_port != 0 &&
|
|
|
|
|
+ (src.sin_port != htons(s_rtp_peer_port) ||
|
|
|
|
|
+ src.sin_addr.s_addr != s_rtp_peer.sin_addr.s_addr))
|
|
|
|
|
+{
|
|
|
|
|
+ ESP_LOGW(TAG,
|
|
|
|
|
+ "Ignoring RTP from unexpected peer %s:%d",
|
|
|
|
|
+ inet_ntoa(src.sin_addr),
|
|
|
|
|
+ ntohs(src.sin_port));
|
|
|
|
|
+ continue;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* Ignore packets that are clearly looped back to the local device. */
|
|
|
|
|
+esp_netif_ip_info_t local_ip;
|
|
|
|
|
+esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
|
|
|
|
|
+esp_netif_get_ip_info(netif, &local_ip);
|
|
|
|
|
+if (src.sin_addr.s_addr == local_ip.ip.addr)
|
|
|
|
|
+{
|
|
|
|
|
+ ESP_LOGW(TAG, "Ignoring looped RTP packet from local IP");
|
|
|
|
|
+ continue;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ESP_LOGI(TAG, "Received RTP packet (%d bytes)", n);
|
|
|
|
|
|
|
|
if (n <= 12)
|
|
if (n <= 12)
|
|
|
{
|
|
{
|
|
@@ -753,23 +855,23 @@ if (n <= 12)
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-ESP_LOGI(TAG,
|
|
|
|
|
- "RTP Header: %02X %02X %02X %02X",
|
|
|
|
|
- rx_packet[0],
|
|
|
|
|
- rx_packet[1],
|
|
|
|
|
- rx_packet[2],
|
|
|
|
|
- rx_packet[3]);
|
|
|
|
|
-
|
|
|
|
|
- ESP_LOGI(TAG,
|
|
|
|
|
- "RTP Payload: %02X %02X %02X %02X %02X %02X %02X %02X",
|
|
|
|
|
- rx_packet[12],
|
|
|
|
|
- rx_packet[13],
|
|
|
|
|
- rx_packet[14],
|
|
|
|
|
- rx_packet[15],
|
|
|
|
|
- rx_packet[16],
|
|
|
|
|
- rx_packet[17],
|
|
|
|
|
- rx_packet[18],
|
|
|
|
|
- rx_packet[19]);
|
|
|
|
|
|
|
+// ESP_LOGI(TAG,
|
|
|
|
|
+// "RTP Header: %02X %02X %02X %02X",
|
|
|
|
|
+// rx_packet[0],
|
|
|
|
|
+// rx_packet[1],
|
|
|
|
|
+// rx_packet[2],
|
|
|
|
|
+// rx_packet[3]);
|
|
|
|
|
+
|
|
|
|
|
+// ESP_LOGI(TAG,
|
|
|
|
|
+// "RTP Payload: %02X %02X %02X %02X %02X %02X %02X %02X",
|
|
|
|
|
+// rx_packet[12],
|
|
|
|
|
+// rx_packet[13],
|
|
|
|
|
+// rx_packet[14],
|
|
|
|
|
+// rx_packet[15],
|
|
|
|
|
+// rx_packet[16],
|
|
|
|
|
+// rx_packet[17],
|
|
|
|
|
+// rx_packet[18],
|
|
|
|
|
+// rx_packet[19]);
|
|
|
|
|
|
|
|
|
|
|
|
|
int payload_size = n - 12;
|
|
int payload_size = n - 12;
|
|
@@ -781,6 +883,7 @@ if (payload_size > SAMPLES_PER_PACKET)
|
|
|
|
|
|
|
|
|
|
|
|
|
int16_t play_buf[640];
|
|
int16_t play_buf[640];
|
|
|
|
|
+int16_t far_end_ref[320];
|
|
|
|
|
|
|
|
for (int i = 0; i < payload_size; i++)
|
|
for (int i = 0; i < payload_size; i++)
|
|
|
{
|
|
{
|
|
@@ -801,20 +904,27 @@ for (int i = 0; i < payload_size; i++)
|
|
|
// interpolated sample
|
|
// interpolated sample
|
|
|
play_buf[4*i + 2] = s2; // Left
|
|
play_buf[4*i + 2] = s2; // Left
|
|
|
play_buf[4*i + 3] = s2; // Right
|
|
play_buf[4*i + 3] = s2; // Right
|
|
|
|
|
+
|
|
|
|
|
+ far_end_ref[2 * i] = s1;
|
|
|
|
|
+ far_end_ref[2 * i + 1] = s2;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // The reference must be the mono 16 kHz signal sent to the speaker,
|
|
|
|
|
+ // before it is duplicated into the codec's stereo output.
|
|
|
|
|
+ far_end_push(far_end_ref, payload_size * 2);
|
|
|
|
|
+
|
|
|
esp_err_t ret = esp_audio_play(
|
|
esp_err_t ret = esp_audio_play(
|
|
|
play_buf,
|
|
play_buf,
|
|
|
payload_size * 4 * sizeof(int16_t),
|
|
payload_size * 4 * sizeof(int16_t),
|
|
|
portMAX_DELAY);
|
|
portMAX_DELAY);
|
|
|
|
|
|
|
|
|
|
|
|
|
-ESP_LOGI(TAG,
|
|
|
|
|
- "esp_audio_play() = %s",
|
|
|
|
|
- esp_err_to_name(ret));
|
|
|
|
|
|
|
+// ESP_LOGI(TAG,
|
|
|
|
|
+// "esp_audio_play() = %s",
|
|
|
|
|
+// esp_err_to_name(ret));
|
|
|
|
|
|
|
|
- ESP_LOGI(TAG, "esp_audio_play() returned %s",
|
|
|
|
|
- esp_err_to_name(ret));
|
|
|
|
|
|
|
+// ESP_LOGI(TAG, "esp_audio_play() returned %s",
|
|
|
|
|
+// esp_err_to_name(ret));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ESP_LOGI(TAG, "RTP RX stopped");
|
|
ESP_LOGI(TAG, "RTP RX stopped");
|