Skip to content

Commit edc240a

Browse files
committed
Create a platform layer
Create platform implementations for linux and esp32s3. Get linux audio working using pulseaudio.
1 parent 95bece5 commit edc240a

File tree

10 files changed

+319
-155
lines changed

10 files changed

+319
-155
lines changed

src/CMakeLists.txt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
set(COMMON_SRC "webrtc.cpp" "main.cpp" "http.cpp")
1+
set(COMMON_SRC "webrtc.cpp" "main.cpp" "http.cpp" "media.cpp")
22

33
if(IDF_TARGET STREQUAL linux)
44
idf_component_register(
5-
SRCS ${COMMON_SRC}
5+
SRCS ${COMMON_SRC} "platform_linux.cpp"
66
REQUIRES peer esp-libopus esp_http_client)
7+
target_link_libraries(${COMPONENT_LIB} PRIVATE pulse pulse-simple)
8+
target_link_libraries(${COMPONENT_LIB} PRIVATE "-lbsd")
79
else()
810
idf_component_register(
9-
SRCS ${COMMON_SRC} "wifi.cpp" "media.cpp"
11+
SRCS ${COMMON_SRC} "platform_esp32s3.cpp" "wifi.cpp"
1012
REQUIRES driver esp_wifi nvs_flash peer esp_psram esp-libopus esp_http_client)
1113
endif()
1214

src/http.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <string.h>
44

55
#include "main.h"
6+
#include "platform.h"
67

78
#ifndef MIN
89
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
@@ -34,9 +35,7 @@ esp_err_t oai_http_event_handler(esp_http_client_event_t *evt) {
3435
ESP_LOGD(LOG_TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
3536
if (esp_http_client_is_chunked_response(evt->client)) {
3637
ESP_LOGE(LOG_TAG, "Chunked HTTP response not supported");
37-
#ifndef LINUX_BUILD
38-
esp_restart();
39-
#endif
38+
oai_platform_restart();
4039
}
4140

4241
if (output_len == 0 && evt->user_data) {
@@ -88,9 +87,7 @@ void oai_http_request(char *offer, char *answer) {
8887
esp_err_t err = esp_http_client_perform(client);
8988
if (err != ESP_OK || esp_http_client_get_status_code(client) != 201) {
9089
ESP_LOGE(LOG_TAG, "Error perform http request %s", esp_err_to_name(err));
91-
#ifndef LINUX_BUILD
92-
esp_restart();
93-
#endif
90+
oai_platform_restart();
9491
}
9592

9693
esp_http_client_cleanup(client);

src/main.cpp

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,19 @@
44
#include <esp_log.h>
55
#include <peer.h>
66

7-
#ifndef LINUX_BUILD
8-
#include "nvs_flash.h"
7+
#include "platform.h"
98

10-
extern "C" void app_main(void) {
11-
esp_err_t ret = nvs_flash_init();
12-
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
13-
ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
14-
ESP_ERROR_CHECK(nvs_flash_erase());
15-
ret = nvs_flash_init();
16-
}
17-
ESP_ERROR_CHECK(ret);
9+
#ifndef LINUX_BUILD
10+
#define MAIN extern "C" void app_main(void)
11+
#else
12+
#define MAIN int main(void)
13+
#endif
1814

15+
MAIN {
1916
ESP_ERROR_CHECK(esp_event_loop_create_default());
2017
peer_init();
21-
oai_init_audio_capture();
18+
oai_platform_init_audio_capture();
2219
oai_init_audio_decoder();
2320
oai_wifi();
2421
oai_webrtc();
2522
}
26-
#else
27-
int main(void) {
28-
ESP_ERROR_CHECK(esp_event_loop_create_default());
29-
peer_init();
30-
oai_webrtc();
31-
}
32-
#endif

src/main.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#ifndef _MAIN_H_
2+
#define _MAIN_H_
3+
14
#include <peer.h>
25

36
#define LOG_TAG "realtimeapi-sdk"
@@ -11,3 +14,5 @@ void oai_send_audio(PeerConnection *peer_connection);
1114
void oai_audio_decode(uint8_t *data, size_t size);
1215
void oai_webrtc();
1316
void oai_http_request(char *offer, char *answer);
17+
18+
#endif

src/media.cpp

Lines changed: 21 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,144 +1,68 @@
1-
#include <driver/i2s.h>
21
#include <opus.h>
2+
#include <stdio.h>
33

44
#include "main.h"
5+
#include "platform.h"
56

67
#define OPUS_OUT_BUFFER_SIZE 1276 // 1276 bytes is recommended by opus_encode
7-
#define SAMPLE_RATE 8000
8-
#define BUFFER_SAMPLES 320
9-
10-
#define MCLK_PIN 0
11-
#define DAC_BCLK_PIN 15
12-
#define DAC_LRCLK_PIN 16
13-
#define DAC_DATA_PIN 17
14-
#define ADC_BCLK_PIN 38
15-
#define ADC_LRCLK_PIN 39
16-
#define ADC_DATA_PIN 40
178

189
#define OPUS_ENCODER_BITRATE 30000
1910
#define OPUS_ENCODER_COMPLEXITY 0
2011

21-
void oai_init_audio_capture() {
22-
i2s_config_t i2s_config_out = {
23-
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
24-
.sample_rate = SAMPLE_RATE,
25-
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
26-
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
27-
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
28-
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
29-
.dma_buf_count = 8,
30-
.dma_buf_len = BUFFER_SAMPLES,
31-
.use_apll = 1,
32-
.tx_desc_auto_clear = true,
33-
};
34-
if (i2s_driver_install(I2S_NUM_0, &i2s_config_out, 0, NULL) != ESP_OK) {
35-
printf("Failed to configure I2S driver for audio output");
36-
return;
37-
}
38-
39-
i2s_pin_config_t pin_config_out = {
40-
.mck_io_num = MCLK_PIN,
41-
.bck_io_num = DAC_BCLK_PIN,
42-
.ws_io_num = DAC_LRCLK_PIN,
43-
.data_out_num = DAC_DATA_PIN,
44-
.data_in_num = I2S_PIN_NO_CHANGE,
45-
};
46-
if (i2s_set_pin(I2S_NUM_0, &pin_config_out) != ESP_OK) {
47-
printf("Failed to set I2S pins for audio output");
48-
return;
49-
}
50-
i2s_zero_dma_buffer(I2S_NUM_0);
12+
const auto kCaptureFrameSize = kCaptureSampleRate * 20 / 1000;
13+
const auto kPlaybackFrameSize = kPlaybackSampleRate * 20 / 1000;
5114

52-
i2s_config_t i2s_config_in = {
53-
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
54-
.sample_rate = SAMPLE_RATE,
55-
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
56-
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
57-
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
58-
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
59-
.dma_buf_count = 8,
60-
.dma_buf_len = BUFFER_SAMPLES,
61-
.use_apll = 1,
62-
};
63-
if (i2s_driver_install(I2S_NUM_1, &i2s_config_in, 0, NULL) != ESP_OK) {
64-
printf("Failed to configure I2S driver for audio input");
65-
return;
66-
}
67-
68-
i2s_pin_config_t pin_config_in = {
69-
.mck_io_num = MCLK_PIN,
70-
.bck_io_num = ADC_BCLK_PIN,
71-
.ws_io_num = ADC_LRCLK_PIN,
72-
.data_out_num = I2S_PIN_NO_CHANGE,
73-
.data_in_num = ADC_DATA_PIN,
74-
};
75-
if (i2s_set_pin(I2S_NUM_1, &pin_config_in) != ESP_OK) {
76-
printf("Failed to set I2S pins for audio input");
77-
return;
78-
}
79-
}
80-
81-
static opus_int16 *output_buffer = NULL;
82-
static size_t output_buffer_size = BUFFER_SAMPLES * sizeof(opus_int16);
8315
static OpusDecoder *opus_decoder = NULL;
16+
static OpusEncoder *opus_encoder = NULL;
17+
18+
static opus_int16 output_buffer[kPlaybackFrameSize * kPlaybackChannelCount];
19+
static opus_int16 input_buffer[kCaptureFrameSize * kCaptureChannelCount];
20+
static uint8_t encoder_output_buffer[OPUS_OUT_BUFFER_SIZE];
8421

8522
void oai_init_audio_decoder() {
8623
int decoder_error = 0;
87-
opus_decoder = opus_decoder_create(SAMPLE_RATE, 2, &decoder_error);
24+
opus_decoder = opus_decoder_create(kPlaybackSampleRate, kPlaybackChannelCount,
25+
&decoder_error);
8826
if (decoder_error != OPUS_OK) {
8927
printf("Failed to create OPUS decoder");
9028
return;
9129
}
92-
93-
output_buffer = (opus_int16 *)malloc(output_buffer_size);
9430
}
9531

9632
void oai_audio_decode(uint8_t *data, size_t size) {
97-
int decoded_size =
98-
opus_decode(opus_decoder, data, size, output_buffer, BUFFER_SAMPLES, 0);
33+
int decoded_size = opus_decode(opus_decoder, data, size, output_buffer,
34+
sizeof(output_buffer), 0);
9935

10036
if (decoded_size > 0) {
10137
size_t bytes_written = 0;
102-
i2s_write(I2S_NUM_0, output_buffer, output_buffer_size,
103-
&bytes_written, portMAX_DELAY);
38+
oai_platform_audio_write((char *)output_buffer, sizeof(output_buffer),
39+
&bytes_written);
10440
}
10541
}
10642

107-
static OpusEncoder *opus_encoder = NULL;
108-
static opus_int16 *encoder_input_buffer = NULL;
109-
static uint8_t *encoder_output_buffer = NULL;
110-
11143
void oai_init_audio_encoder() {
11244
int encoder_error;
113-
opus_encoder = opus_encoder_create(SAMPLE_RATE, 1, OPUS_APPLICATION_VOIP,
114-
&encoder_error);
45+
opus_encoder = opus_encoder_create(kCaptureSampleRate, kCaptureChannelCount,
46+
OPUS_APPLICATION_VOIP, &encoder_error);
11547
if (encoder_error != OPUS_OK) {
11648
printf("Failed to create OPUS encoder");
11749
return;
11850
}
11951

120-
if (opus_encoder_init(opus_encoder, SAMPLE_RATE, 1, OPUS_APPLICATION_VOIP) !=
121-
OPUS_OK) {
122-
printf("Failed to initialize OPUS encoder");
123-
return;
124-
}
125-
12652
opus_encoder_ctl(opus_encoder, OPUS_SET_BITRATE(OPUS_ENCODER_BITRATE));
12753
opus_encoder_ctl(opus_encoder, OPUS_SET_COMPLEXITY(OPUS_ENCODER_COMPLEXITY));
12854
opus_encoder_ctl(opus_encoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
129-
encoder_input_buffer = (opus_int16 *)malloc(BUFFER_SAMPLES);
130-
encoder_output_buffer = (uint8_t *)malloc(OPUS_OUT_BUFFER_SIZE);
13155
}
13256

13357
void oai_send_audio(PeerConnection *peer_connection) {
13458
size_t bytes_read = 0;
13559

136-
i2s_read(I2S_NUM_1, encoder_input_buffer, BUFFER_SAMPLES, &bytes_read,
137-
portMAX_DELAY);
60+
oai_platform_audio_read((char *)input_buffer, sizeof(input_buffer),
61+
&bytes_read);
13862

13963
auto encoded_size =
140-
opus_encode(opus_encoder, encoder_input_buffer, BUFFER_SAMPLES / 2,
141-
encoder_output_buffer, OPUS_OUT_BUFFER_SIZE);
64+
opus_encode(opus_encoder, input_buffer, kCaptureFrameSize,
65+
encoder_output_buffer, sizeof(encoder_output_buffer));
14266

14367
peer_connection_send_audio(peer_connection, encoder_output_buffer,
14468
encoded_size);

src/media.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#pragma once
2+
3+
#include "peer_connection.h"
4+
5+
void oai_send_audio(PeerConnection *peer_connection);

src/platform.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#pragma once
2+
3+
#include <stdlib.h>
4+
5+
#include "peer_connection.h"
6+
7+
inline constexpr int kCaptureSampleRate = 8000;
8+
inline constexpr int kCaptureChannelCount = 1;
9+
inline constexpr int kPlaybackSampleRate = 8000;
10+
inline constexpr int kPlaybackChannelCount = 2;
11+
12+
void oai_platform_init(void);
13+
void oai_platform_restart(void);
14+
void oai_platform_init_audio_capture(void);
15+
void oai_platform_audio_write(char *output_buffer, size_t output_buffer_size,
16+
size_t *bytes_written);
17+
void oai_platform_audio_read(char *input_buffer, size_t input_buffer_size,
18+
size_t *bytes_read);
19+
void oai_platform_send_audio_task(PeerConnection *peer_connection);

0 commit comments

Comments
 (0)