Skip to content

Commit 87738fb

Browse files
committed
Merge branch 'bugfix/fix_capture_audio_bypass_err' into 'main'
bugfix(esp_capture): Fix audio bypass fail and dynamic enable failed See merge request adf/multimedia/esp-gmf!138
2 parents f449d42 + fde6488 commit 87738fb

File tree

13 files changed

+404
-29
lines changed

13 files changed

+404
-29
lines changed

packages/esp_capture/CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
## v0.7.4
4+
5+
### Bug Fixes
6+
7+
- Fixed failed to start audio capture with PCM format
8+
- Fixed dynamically enable disable sink failed after started
9+
- Added get sink handle with same configuration after started
10+
- Fixed sync lost if dynamical enable and disable sink
11+
- Added test cases for audio bypass
12+
- Added test cases for dynamically enable and disable sink
13+
- Added multiple start and stop test cases
14+
315
## v0.7.3
416

517
### Bug Fixes

packages/esp_capture/idf_component.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: "0.7.3"
1+
version: "0.7.4"
22
description: Espressif Capture is a module for capture media stream from camera and microphone
33
url: https://github.com/espressif/esp-gmf/tree/main/packages/esp_capture
44
documentation: "https://github.com/espressif/esp-gmf/blob/main/packages/esp_capture/README.md"

packages/esp_capture/impl/capture_gmf_path/src/elements/gmf_audio_src.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ typedef struct {
2929
esp_gmf_audio_element_t parent;
3030
esp_gmf_port_handle_t in_port;
3131
esp_capture_sync_handle_t sync_handle;
32+
uint32_t base_pts;
3233
esp_capture_audio_src_if_t *audio_src_if;
3334
esp_gmf_info_sound_t aud_info;
3435
data_q_t *audio_src_q;
@@ -99,14 +100,22 @@ static void audio_src_thread(void *arg)
99100
}
100101
if (audio_src->frame_reached == false) {
101102
CAPTURE_PERF_MON(0, "Audio Src Frame Reached", {});
103+
// Get base pts
104+
if (audio_src->sync_handle) {
105+
uint32_t cur_pts = 0;
106+
esp_capture_sync_get_current(audio_src->sync_handle, &cur_pts);
107+
if (cur_pts > CAPTURE_SYNC_TOLERANCE) {
108+
audio_src->base_pts = cur_pts;
109+
}
110+
}
102111
audio_src->frame_reached = true;
103112
}
104113
esp_capture_stream_frame_t *frame = (esp_capture_stream_frame_t *)data;
105114
frame->stream_type = ESP_CAPTURE_STREAM_TYPE_AUDIO;
106115
frame->data = (data + sizeof(esp_capture_stream_frame_t));
107116
frame->size = audio_src->audio_frame_size;
108117
int ret = audio_src->audio_src_if->read_frame(audio_src->audio_src_if, frame);
109-
frame->pts = calc_audio_pts(audio_src, audio_src->audio_frames);
118+
frame->pts = calc_audio_pts(audio_src, audio_src->audio_frames) + audio_src->base_pts;
110119
if (ret != ESP_CAPTURE_ERR_OK) {
111120
data_q_send_buffer(audio_src->audio_src_q, 0);
112121
ESP_LOGE(TAG, "Failed to read audio frame ret %d", ret);
@@ -126,6 +135,7 @@ static void audio_src_thread(void *arg)
126135
data_q_send_buffer(audio_src->audio_src_q, frame_size);
127136
audio_src->audio_frames++;
128137
}
138+
audio_src->audio_frames = 0;
129139
// Wakeup reader if read from device failed
130140
if (err_exit) {
131141
data_q_wakeup(audio_src->audio_src_q);

packages/esp_capture/impl/capture_gmf_path/src/gmf_capture_audio_path.c

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,21 @@ static esp_capture_err_t get_audio_encoder(gmf_capture_path_mngr_t *mngr, uint8_
5454
return ESP_CAPTURE_ERR_NOT_FOUND;
5555
}
5656

57+
static esp_gmf_element_handle_t get_sink_tail_element(gmf_capture_path_mngr_t *mngr, audio_path_res_t *res)
58+
{
59+
uint8_t path_mask = (1 << res->base.path);
60+
for (int i = 0; i < mngr->pipeline_num; i++) {
61+
esp_capture_gmf_pipeline_t *pipeline = &mngr->pipeline[i];
62+
if ((pipeline->path_mask & path_mask) == 0) {
63+
continue;
64+
}
65+
if (capture_pipeline_is_sink(pipeline->pipeline)) {
66+
return ESP_GMF_PIPELINE_GET_LAST_ELEMENT(((esp_gmf_pipeline_handle_t)pipeline->pipeline));
67+
}
68+
}
69+
return NULL;
70+
}
71+
5772
static esp_capture_err_t set_audio_source_sync_handle(gmf_capture_path_mngr_t *mngr, esp_capture_sync_handle_t sync_handle)
5873
{
5974
for (int i = 0; i < mngr->pipeline_num; i++) {
@@ -99,10 +114,16 @@ static esp_gmf_err_io_t audio_sink_acquire(void *handle, esp_gmf_payload_t *load
99114
if (aud_frame == NULL) {
100115
return ESP_GMF_IO_FAIL;
101116
}
117+
102118
aud_frame->stream_type = ESP_CAPTURE_STREAM_TYPE_AUDIO;
103119
aud_frame->data = ((void *)aud_frame) + sizeof(esp_capture_stream_frame_t);
104-
load->buf = aud_frame->data;
105-
load->buf_length = wanted_size;
120+
if (load->buf) {
121+
// In bypass case copy data directly
122+
memcpy(aud_frame->data, load->buf, load->valid_size);
123+
} else {
124+
load->buf = aud_frame->data;
125+
load->buf_length = wanted_size;
126+
}
106127
return ESP_GMF_IO_OK;
107128
}
108129

@@ -124,6 +145,10 @@ static esp_gmf_err_io_t audio_sink_release(void *handle, esp_gmf_payload_t *load
124145
ESP_LOGI(TAG, "Drop for disable");
125146
data_q_send_buffer(q, 0);
126147
}
148+
if (load->buf == aud_frame->data) {
149+
// Clear buf when not bypass case
150+
load->buf = NULL;
151+
}
127152
}
128153
return ESP_GMF_IO_OK;
129154
}
@@ -144,7 +169,11 @@ static esp_capture_err_t audio_path_prepare(gmf_capture_path_res_t *mngr_res)
144169
if (res->audio_q == NULL) {
145170
return ESP_CAPTURE_ERR_NO_MEM;
146171
}
147-
esp_gmf_element_register_out_port(res->aenc_el, res->sink_port);
172+
if (res->aenc_el) {
173+
esp_gmf_element_register_out_port(res->aenc_el, res->sink_port);
174+
} else {
175+
esp_gmf_element_register_out_port(get_sink_tail_element(mngr_res->parent, res), res->sink_port);
176+
}
148177
}
149178
return ESP_CAPTURE_ERR_OK;
150179
}

packages/esp_capture/impl/capture_gmf_path/src/gmf_capture_auto_audio_pipeline.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,15 @@ static esp_capture_err_t buildup_pipelines(audio_pipeline_t *audio_pipe)
321321
// TODO currently only support encoder
322322
proc_elements[proc_num++] = element_name;
323323
}
324+
if (proc_num == 0) {
325+
// Add a dummy element in case no element can not form pipeline
326+
const char *element_name = get_ops_element(audio_pipe, AUDIO_PATH_OPS_BIT_CVT);
327+
if (element_name == NULL) {
328+
ESP_LOGE(TAG, "Can not find element for bit convert");
329+
return ESP_CAPTURE_ERR_INTERNAL;
330+
}
331+
proc_elements[proc_num++] = element_name;
332+
}
324333
#if 0
325334
printf("Audio Pipeline %d: ", i);
326335
for (int j = 0; j < proc_num; j++) {

packages/esp_capture/impl/capture_gmf_path/src/gmf_capture_path_mngr.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,15 +160,27 @@ static esp_capture_err_t prepare_pipeline(gmf_capture_path_mngr_t *mngr, uint8_t
160160
gmf_capture_path_res_t *res = gmf_capture_path_mngr_get_path(mngr, path);
161161
uint8_t path_mask = (1 << path);
162162
if (res->negotiated == false) {
163+
bool for_all = true;
164+
for (int i = 0; i < mngr->path_num; i++) {
165+
gmf_capture_path_res_t *each = gmf_capture_path_mngr_get_path(mngr, i);
166+
if (each->negotiated) {
167+
for_all = false;
168+
break;
169+
}
170+
}
163171
if (mngr->pipeline_builder->negotiate) {
164172
int ret = ESP_CAPTURE_ERR_OK;
173+
uint8_t nego_mask = for_all ? ESP_CAPTURE_PIPELINE_NEGO_ALL_MASK : path_mask;
165174
CAPTURE_PERF_MON(path, (mngr->stream_type == ESP_CAPTURE_STREAM_TYPE_AUDIO) ? "Negotiate Audio Sink" : "Negotiate Video Sink", {
166-
ret = mngr->pipeline_builder->negotiate(mngr->pipeline_builder, path_mask);
175+
ret = mngr->pipeline_builder->negotiate(mngr->pipeline_builder, nego_mask);
167176
});
168177
if (ret != ESP_CAPTURE_ERR_OK) {
169178
ESP_LOGE(TAG, "Fail to negotiate audio pipeline");
170179
return ret;
171180
}
181+
if (res->configured) {
182+
res->negotiated = true;
183+
}
172184
}
173185
}
174186
for (int i = 0; i < mngr->pipeline_num; i++) {
@@ -298,6 +310,12 @@ static void stop_pipelines(gmf_capture_path_mngr_t *mngr, uint8_t path, gmf_capt
298310
CAPTURE_PERF_MON(res->path, (mngr->stream_type == ESP_CAPTURE_STREAM_TYPE_AUDIO) ? "Prepare Stop Audio Sink" : "Prepare Stop Video Sink", {
299311
stop_cb(res);
300312
});
313+
} else {
314+
// Src is stopped all related sink need re-negotiate
315+
for (int i = 0; i < mngr->path_num; i++) {
316+
gmf_capture_path_res_t *each = gmf_capture_path_mngr_get_idx(mngr, i);
317+
each->negotiated = false;
318+
}
301319
}
302320
ESP_LOGD(TAG, "Start to stop pipeline %d", sel_pipe);
303321
CAPTURE_PERF_MON(res->path, (mngr->stream_type == ESP_CAPTURE_STREAM_TYPE_AUDIO) ? "Stop Audio Pipeline" : "Stop Video Pipeline", {
@@ -353,6 +371,7 @@ static esp_capture_err_t stop_path(gmf_capture_path_mngr_t *mngr, uint8_t path,
353371
return ESP_CAPTURE_ERR_OK;
354372
}
355373
res->started = false;
374+
res->negotiated = false;
356375
stop_pipelines(mngr, path, stop_cb);
357376
release_pipelines(mngr, path, release_cb);
358377
ESP_LOGD(TAG, "Path %d stop finished\n", path);

packages/esp_capture/src/esp_capture.c

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,29 @@ static esp_capture_path_mngr_if_t *capture_get_mngr_by_stream_type(capture_t *ca
510510
return mngr;
511511
}
512512

513+
static bool capture_same_sink_cfg(esp_capture_sink_cfg_t *old, esp_capture_sink_cfg_t *sink_cfg)
514+
{
515+
if (old->audio_info.format_id != sink_cfg->audio_info.format_id ||
516+
old->video_info.format_id != sink_cfg->video_info.format_id) {
517+
return false;
518+
}
519+
if (old->audio_info.format_id) {
520+
if (old->audio_info.sample_rate != sink_cfg->audio_info.sample_rate ||
521+
old->audio_info.channel != sink_cfg->audio_info.channel ||
522+
old->audio_info.bits_per_sample != sink_cfg->audio_info.bits_per_sample) {
523+
return false;
524+
}
525+
}
526+
if (old->video_info.format_id) {
527+
if (old->video_info.width != sink_cfg->video_info.width ||
528+
old->video_info.height != sink_cfg->video_info.height ||
529+
old->video_info.fps != sink_cfg->video_info.fps) {
530+
return false;
531+
}
532+
}
533+
return true;
534+
}
535+
513536
esp_capture_err_t esp_capture_set_thread_scheduler(esp_capture_thread_scheduler_cb_t thread_scheduler)
514537
{
515538
capture_thread_set_scheduler(thread_scheduler);
@@ -736,15 +759,21 @@ esp_capture_err_t esp_capture_sink_setup(esp_capture_handle_t h, uint8_t type, e
736759
capture_mutex_lock(capture->api_lock, CAPTURE_MAX_LOCK_TIME);
737760
esp_capture_err_t ret = ESP_CAPTURE_ERR_OK;
738761
do {
762+
capture_path_t *cur = capture_get_path_by_index(capture, type);
739763
if (capture->started) {
764+
if (cur && capture_same_sink_cfg(&cur->sink_cfg, sink_info)) {
765+
// Allow get sink handle use same setup
766+
*path = (esp_capture_sink_handle_t)cur;
767+
ret = ESP_CAPTURE_ERR_OK;
768+
break;
769+
}
740770
ESP_LOGE(TAG, "Not support add path after started");
741771
CAPTURE_BREAK_SET_RETURN(ret, ESP_CAPTURE_ERR_INVALID_STATE);
742772
}
743773
if (capture->cfg.audio_path == NULL && capture->cfg.video_path == NULL) {
744774
ESP_LOGE(TAG, "Only support add sink for no path manager");
745775
CAPTURE_BREAK_SET_RETURN(ret, ESP_CAPTURE_ERR_NOT_SUPPORTED);
746776
}
747-
capture_path_t *cur = capture_get_path_by_index(capture, type);
748777
// Path already added
749778
if (cur) {
750779
if (cur->enable && capture->started) {
@@ -1104,7 +1133,6 @@ esp_capture_err_t esp_capture_sink_acquire_frame(esp_capture_sink_handle_t h, es
11041133
}
11051134
// TODO not add lock user need care the timing
11061135
if (path->enable == false) {
1107-
ESP_LOGE(TAG, "Capture path %d is not enabled", path->path_type);
11081136
return ESP_CAPTURE_ERR_INVALID_STATE;
11091137
}
11101138
int ret = ESP_CAPTURE_ERR_NOT_SUPPORTED;
@@ -1153,7 +1181,6 @@ esp_capture_err_t esp_capture_sink_release_frame(esp_capture_sink_handle_t h, es
11531181
}
11541182
// TODO not add lock user need care the timing
11551183
if (path->enable == false) {
1156-
ESP_LOGE(TAG, "Capture path %d is not enabled", path->path_type);
11571184
return ESP_CAPTURE_ERR_INVALID_STATE;
11581185
}
11591186
int ret = ESP_CAPTURE_ERR_OK;

packages/esp_capture/src/esp_capture_sync.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ esp_capture_err_t esp_capture_sync_on(esp_capture_sync_handle_t handle)
5252
}
5353
sync_t *sync = (sync_t *)handle;
5454
sync->started = true;
55+
sync->last_update_pts = 0;
5556
sync->last_update_time = CUR();
5657
return ESP_CAPTURE_ERR_OK;
5758
}

packages/esp_capture/test_apps/main/capture_builder.c

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -318,24 +318,13 @@ int build_advance_av_capture_sys(capture_sys_t *capture_sys)
318318
return 0;
319319
}
320320

321-
int read_all_frames(capture_sys_t *capture_sys, bool dual_sink, int timeout)
321+
void read_with_timeout(capture_sys_t *capture_sys, bool dual_sink, int timeout)
322322
{
323323
capture_run_result_t *res = &capture_sys->run_result;
324324
memset(res, 0, sizeof(capture_run_result_t));
325325
uint32_t start_time = esp_timer_get_time() / 1000;
326326
uint32_t cur_time = start_time;
327327
int sink_num = dual_sink ? 2 : 1;
328-
if (capture_sys->capture_sink[0]) {
329-
esp_capture_sink_enable(capture_sys->capture_sink[0], ESP_CAPTURE_RUN_MODE_ALWAYS);
330-
}
331-
if (dual_sink && capture_sys->capture_sink[1]) {
332-
esp_capture_sink_enable(capture_sys->capture_sink[1], ESP_CAPTURE_RUN_MODE_ALWAYS);
333-
}
334-
int ret = esp_capture_start(capture_sys->capture);
335-
if (ret != 0) {
336-
ESP_LOGE(TAG, "Fail to start capture");
337-
return -1;
338-
}
339328
while (cur_time < start_time + timeout) {
340329
// Following code acquire frame without wait for all supported sink
341330
for (int i = 0; i < sink_num; i++) {
@@ -345,7 +334,7 @@ int read_all_frames(capture_sys_t *capture_sys, bool dual_sink, int timeout)
345334
while (esp_capture_sink_acquire_frame(capture_sys->capture_sink[i], &frame, true) == ESP_CAPTURE_ERR_OK) {
346335
res->audio_frame_count[i]++;
347336
if (res->audio_frame_count[i] == 1) {
348-
ESP_LOGI(TAG, "[%d] First audio frame received", i);
337+
ESP_LOGI(TAG, "[%d] First audio frame received pts %d", i, (int)frame.pts);
349338
}
350339
res->audio_frame_size[i] += frame.size;
351340
res->audio_pts[i] = frame.pts;
@@ -355,7 +344,7 @@ int read_all_frames(capture_sys_t *capture_sys, bool dual_sink, int timeout)
355344
while (esp_capture_sink_acquire_frame(capture_sys->capture_sink[i], &frame, true) == ESP_CAPTURE_ERR_OK) {
356345
res->video_frame_count[i]++;
357346
if (res->video_frame_count[i] == 1) {
358-
ESP_LOGI(TAG, "[%d] First video frame received", i);
347+
ESP_LOGI(TAG, "[%d] First video frame received pts %d", i, (int)frame.pts);
359348
}
360349
res->video_frame_size[i] += frame.size;
361350
res->video_pts[i] = frame.pts;
@@ -365,7 +354,7 @@ int read_all_frames(capture_sys_t *capture_sys, bool dual_sink, int timeout)
365354
while (esp_capture_sink_acquire_frame(capture_sys->capture_sink[i], &frame, true) == ESP_CAPTURE_ERR_OK) {
366355
res->muxer_frame_count[i]++;
367356
if (res->muxer_frame_count[i] == 1) {
368-
ESP_LOGI(TAG, "[%d] First muxed frame received", i);
357+
ESP_LOGI(TAG, "[%d] First muxed frame received pts %d", i, (int)frame.pts);
369358
}
370359
res->muxer_frame_size[i] += frame.size;
371360
res->muxer_pts[i] = frame.pts;
@@ -375,23 +364,39 @@ int read_all_frames(capture_sys_t *capture_sys, bool dual_sink, int timeout)
375364
vTaskDelay(10 / portTICK_PERIOD_MS);
376365
cur_time = esp_timer_get_time() / 1000;
377366
}
378-
esp_capture_stop(capture_sys->capture);
379367

380368
// Show capture results
381369
for (int i = 0; i < sink_num; i++) {
382370
if (res->audio_frame_count[i]) {
383-
ESP_LOGI(TAG, "Audio Path %d frame_count:%d frame_size:%d pts:%d", i,
371+
ESP_LOGW(TAG, "Audio Path %d frame_count:%d frame_size:%d pts:%d", i,
384372
res->audio_frame_count[i], res->audio_frame_size[i], res->audio_pts[i]);
385373
}
386374
if (res->video_frame_count[i]) {
387-
ESP_LOGI(TAG, "Video Path %d frame_count:%d frame_size:%d pts:%d", i,
375+
ESP_LOGW(TAG, "Video Path %d frame_count:%d frame_size:%d pts:%d", i,
388376
res->video_frame_count[i], res->video_frame_size[i], res->video_pts[i]);
389377
}
390378
if (res->muxer_frame_count[i]) {
391-
ESP_LOGI(TAG, "Muxer Path %d frame_count:%d frame_size:%d pts:%d", i,
379+
ESP_LOGW(TAG, "Muxer Path %d frame_count:%d frame_size:%d pts:%d", i,
392380
res->muxer_frame_count[i], res->muxer_frame_size[i], res->muxer_pts[i]);
393381
}
394382
}
383+
}
384+
385+
int read_all_frames(capture_sys_t *capture_sys, bool dual_sink, int timeout)
386+
{
387+
if (capture_sys->capture_sink[0]) {
388+
esp_capture_sink_enable(capture_sys->capture_sink[0], ESP_CAPTURE_RUN_MODE_ALWAYS);
389+
}
390+
if (dual_sink && capture_sys->capture_sink[1]) {
391+
esp_capture_sink_enable(capture_sys->capture_sink[1], ESP_CAPTURE_RUN_MODE_ALWAYS);
392+
}
393+
int ret = esp_capture_start(capture_sys->capture);
394+
if (ret != 0) {
395+
ESP_LOGE(TAG, "Fail to start capture");
396+
return -1;
397+
}
398+
read_with_timeout(capture_sys, dual_sink, timeout);
399+
esp_capture_stop(capture_sys->capture);
395400
return 0;
396401
}
397402

packages/esp_capture/test_apps/main/capture_builder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ int build_advance_video_only_capture_sys(capture_sys_t *capture_sys);
5858

5959
int build_advance_av_capture_sys(capture_sys_t *capture_sys);
6060

61+
void read_with_timeout(capture_sys_t *capture_sys, bool dual_sink, int timeout);
62+
6163
int read_all_frames(capture_sys_t *capture_sys, bool dual_sink, int timeout);
6264

6365
void destroy_capture_sys(capture_sys_t *capture_sys);

0 commit comments

Comments
 (0)