diff --git a/fwk/api/ar_utils/linux/ar_msg.h b/fwk/api/ar_utils/linux/ar_msg.h index efc34e04..be4ae898 100644 --- a/fwk/api/ar_utils/linux/ar_msg.h +++ b/fwk/api/ar_utils/linux/ar_msg.h @@ -50,11 +50,11 @@ // Legacy debug priority messages -#define DBG_LOW_PRIO AR_HIGH_PRIO /**< Low priority debug message. */ -#define DBG_MED_PRIO AR_HIGH_PRIO /**< Medium priority debug message. */ +#define DBG_LOW_PRIO AR_LOW_PRIO /**< Low priority debug message. */ +#define DBG_MED_PRIO AR_MED_PRIO /**< Medium priority debug message. */ #define DBG_HIGH_PRIO AR_HIGH_PRIO /**< High priority debug message. */ #define DBG_ERROR_PRIO AR_ERROR_PRIO /**< Error priority debug message. */ -#define DBG_FATAL_PRIO AR_HIGH_PRIO /**< Fatal priority debug message. */ +#define DBG_FATAL_PRIO AR_FATAL_PRIO /**< Fatal priority debug message. */ #define MSG_LEGACY_ERROR DBG_ERROR_PRIO #define MSG_LEGACY_HIGH DBG_HIGH_PRIO #define MSG_LEGACY_MED DBG_MED_PRIO @@ -122,14 +122,26 @@ do { \ if (ar_log_debugmsg_enable) \ { \ - static const char *msg_tag = AR_MSG_TAG; \ - static const char filename[] = LOCAL_FILE_NAME; \ - static const uint32_t line_no = __LINE__; \ - ar_log( xx_ss_mask, msg_tag, filename, __FUNCTION__, line_no, xx_fmt, ##__VA_ARGS__); \ if (DBG_FATAL_PRIO == (xx_ss_mask)) \ { \ assert(0); \ } \ + else if (DBG_ERROR_PRIO == (xx_ss_mask)) \ + { \ + AR_LOG_ERR(AR_MSG_TAG, xx_fmt, ##__VA_ARGS__) \ + } \ + else if (DBG_HIGH_PRIO == (xx_ss_mask)) \ + { \ + AR_LOG_INFO(AR_MSG_TAG, xx_fmt, ##__VA_ARGS__) \ + } \ + else if (DBG_MED_PRIO == (xx_ss_mask)) \ + { \ + AR_LOG_DEBUG(AR_MSG_TAG, xx_fmt, ##__VA_ARGS__) \ + } \ + else if (DBG_LOW_PRIO == (xx_ss_mask)) \ + { \ + AR_LOG_VERBOSE(AR_MSG_TAG, xx_fmt, ##__VA_ARGS__) \ + } \ } \ } while(0) #endif //if defined (ARSPF_PLATFORM_LRH) diff --git a/fwk/platform/modules/generic/endpoint/alsa_device/build/Android.mk b/fwk/platform/modules/generic/endpoint/alsa_device/build/Android.mk index a8860100..4577b765 100644 --- a/fwk/platform/modules/generic/endpoint/alsa_device/build/Android.mk +++ b/fwk/platform/modules/generic/endpoint/alsa_device/build/Android.mk @@ -24,7 +24,7 @@ ALSA_DEVICE_CFLAGS_64 += -march=armv8-a+crypto ALSA_DEVICE_SHARED_LIBS := \ liblx-osal \ libar-gpr \ - libtinyalsa + liboss_tinyalsa ALSA_DEVICE_HEADER_LIBS := \ libspf_api \ diff --git a/fwk/platform/modules/generic/endpoint/alsa_device/capi/src/capi_alsa_device.c b/fwk/platform/modules/generic/endpoint/alsa_device/capi/src/capi_alsa_device.c index 9acf6379..00e56450 100644 --- a/fwk/platform/modules/generic/endpoint/alsa_device/capi/src/capi_alsa_device.c +++ b/fwk/platform/modules/generic/endpoint/alsa_device/capi/src/capi_alsa_device.c @@ -28,42 +28,67 @@ capi_err_t capi_alsa_device_process_source(capi_t *_pif, capi_stream_data_t *inp capi_err_t capi_alsa_device_process_sink(capi_t *_pif, capi_stream_data_t *input[], capi_stream_data_t *output[]); -/* Thread function that performs blocking reads into read_buffer and signals framework */ +/* Thread function that polls for hardware buffer availability and signals framework */ static void capi_alsa_device_dma_wait_thread(void *arg) { capi_alsa_device_t *me_ptr = (capi_alsa_device_t *)arg; AR_MSG(DBG_HIGH_PRIO, "CAPI_ALSA_DEVICE: DMA wait thread started for instance 0x%lx", me_ptr->iid); + bool_t needs_recovery = FALSE; + while (!me_ptr->exit_thread) { - /* - * TODO: Ideally this thread should use alsa_device_driver_wait() to only poll - * for hardware buffer availability and signal the framework, while the actual - * alsa_device_driver_read() is done in process_source. However, the - * alsa_device_driver_wait() based approach was found to be unreliable in - * practice. Until this is investigated and resolved, a blocking - * alsa_device_driver_read() is used here as a safe and functional workaround — - * it blocks until the data is available. - */ - ar_result_t result = alsa_device_driver_read(&me_ptr->alsa_device_driver, - me_ptr->read_buffer, - me_ptr->read_buffer_size); + /* Wait until process_sink/source completes before calling pcm_wait or + * pcm_prepare. Ensures no concurrent PCM operations on the same handle. */ + posal_nmutex_lock(me_ptr->data_ready_lock); + while (me_ptr->data_ready && !me_ptr->exit_thread) + { + posal_condvar_wait(me_ptr->process_done_cond, me_ptr->data_ready_lock); + } + posal_nmutex_unlock(me_ptr->data_ready_lock); + + if (me_ptr->exit_thread) break; + + /* Recover from XRUN here — after confirming process_source is not + * concurrently executing pcm_read on the same PCM handle. */ + if (needs_recovery) + { + needs_recovery = FALSE; + if (AR_EOK == alsa_device_driver_prepare(&me_ptr->alsa_device_driver)) + { + /* Source (capture): pcm_start required to restart DMA. + * Sink (playback): stream restarts automatically on next pcm_write. */ + if (ALSA_DEVICE_SOURCE == me_ptr->direction) + { + alsa_device_driver_start(&me_ptr->alsa_device_driver); + } + } + } + + ar_result_t result = alsa_device_driver_wait(&me_ptr->alsa_device_driver); if (result != AR_EOK) { - AR_MSG(DBG_ERROR_PRIO, "CAPI_ALSA_DEVICE: Read failed in DMA thread, result=%d", result); + if (!me_ptr->exit_thread) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_ALSA_DEVICE: pcm_wait failed in DMA thread, result=%d", result); + /* Set recovery flag for non-timeout errors (XRUN etc.). + * Timeout means no data yet — just retry pcm_wait. */ + if (AR_ETIMEOUT != result) + { + needs_recovery = TRUE; + } + } continue; } - AR_MSG(DBG_HIGH_PRIO, "CAPI_ALSA_DEVICE: DMA thread read %d bytes", me_ptr->read_buffer_size); - - /* Mark data as ready */ + /* Mark hardware data available and signal the framework */ + posal_nmutex_lock(me_ptr->data_ready_lock); me_ptr->data_ready = TRUE; + posal_nmutex_unlock(me_ptr->data_ready_lock); - /* Signal framework using STM signal */ if (me_ptr->signal_ptr && me_ptr->enable_stm) { - AR_MSG(DBG_HIGH_PRIO, "CAPI_ALSA_DEVICE: signaling the container"); posal_signal_send(me_ptr->signal_ptr); } } @@ -166,7 +191,20 @@ static capi_err_t capi_alsa_device_common_init(capi_t *_pif, capi_proplist_t *in return capi_result; } - return capi_result; + if (AR_EOK != posal_nmutex_create(&me_ptr->data_ready_lock, (POSAL_HEAP_ID)me_ptr->heap_mem.heap_id)) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_ALSA_DEVICE: Failed to create data_ready_lock"); + return CAPI_EFAILED; + } + + if (AR_EOK != posal_condvar_create(&me_ptr->process_done_cond, (POSAL_HEAP_ID)me_ptr->heap_mem.heap_id)) + { + posal_nmutex_destroy(&me_ptr->data_ready_lock); + AR_MSG(DBG_ERROR_PRIO, "CAPI_ALSA_DEVICE: Failed to create process_done_cond"); + return CAPI_EFAILED; + } + + return CAPI_EOK; } /*------------------------------------------------------------------------ @@ -336,7 +374,7 @@ static capi_err_t capi_alsa_device_process_set_properties(capi_alsa_device_t *me } case FWK_EXTN_PROPERTY_ID_STM_CTRL: { - if (payload_ptr->actual_data_len < sizeof(capi_prop_stm_ctrl_t)) + if (payload_ptr->actual_data_len < sizeof(capi_custom_property_t) + sizeof(capi_prop_stm_ctrl_t)) { AR_MSG(DBG_ERROR_PRIO, "Property id 0x%lx Bad param size %lu", @@ -350,9 +388,14 @@ static capi_err_t capi_alsa_device_process_set_properties(capi_alsa_device_t *me AR_MSG(DBG_HIGH_PRIO, "FWK_EXTN_PROPERTY_ID_STM_CTRL enable_stm %d", me_ptr->enable_stm); - if (ALSA_DEVICE_SOURCE == me_ptr->direction && - me_ptr->enable_stm && me_ptr->state != ALSA_DEVICE_INTERFACE_START) + if (me_ptr->enable_stm && me_ptr->state != ALSA_DEVICE_INTERFACE_START) { + if (!me_ptr->ep_mf_received) + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_ALSA_DEVICE: STM enable received before MF config, ignoring"); + break; + } capi_result = alsa_device_driver_open(&me_ptr->alsa_device_driver, me_ptr->direction); if (capi_result != AR_EOK) { @@ -360,28 +403,50 @@ static capi_err_t capi_alsa_device_process_set_properties(capi_alsa_device_t *me return CAPI_EFAILED; } + /* Sync int_samples_per_period with the actual period_size the ALSA driver + * negotiated — it may differ from the requested size due to HW constraints. */ + uint32_t actual_period_size = me_ptr->alsa_device_driver.config.period_size; + if (actual_period_size != me_ptr->int_samples_per_period) + { + AR_MSG(DBG_HIGH_PRIO, + "CAPI_ALSA_DEVICE: ALSA adjusted period_size: requested=%d actual=%d frames", + me_ptr->int_samples_per_period, actual_period_size); + me_ptr->int_samples_per_period = actual_period_size; + capi_result = capi_alsa_device_raise_thresh_delay_events(me_ptr); + if (CAPI_EOK != capi_result) + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_ALSA_DEVICE: Failed to raise threshold event after period_size adjustment"); + } + } + capi_result = alsa_device_driver_prepare(&me_ptr->alsa_device_driver); if (capi_result != AR_EOK) { AR_MSG(DBG_ERROR_PRIO, "CAPI_ALSA_DEVICE: alsa_device_driver_prepare failed with error code %d", capi_result); + alsa_device_driver_close(&me_ptr->alsa_device_driver); return CAPI_EFAILED; } - capi_result = alsa_device_driver_start(&me_ptr->alsa_device_driver); - if (capi_result != AR_EOK) + if (ALSA_DEVICE_SOURCE == me_ptr->direction) { - AR_MSG(DBG_ERROR_PRIO, - "CAPI_ALSA_DEVICE: alsa_device_driver_start failed with error code %d", - capi_result); - return CAPI_EFAILED; + capi_result = alsa_device_driver_start(&me_ptr->alsa_device_driver); + if (capi_result != AR_EOK) + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_ALSA_DEVICE: alsa_device_driver_start failed with error code %d", + capi_result); + alsa_device_driver_close(&me_ptr->alsa_device_driver); + return CAPI_EFAILED; + } } - if (NULL == me_ptr->read_buffer) + if (ALSA_DEVICE_SOURCE == me_ptr->direction && NULL == me_ptr->read_buffer) { struct pcm_config *config = &me_ptr->alsa_device_driver.config; - me_ptr->read_buffer_size = config->period_size * config->channels * (me_ptr->bit_width / 8); + me_ptr->read_buffer_size = config->period_size * config->channels * me_ptr->bytes_per_channel; me_ptr->read_buffer = (int8_t *)posal_memory_malloc( me_ptr->read_buffer_size, @@ -391,6 +456,7 @@ static capi_err_t capi_alsa_device_process_set_properties(capi_alsa_device_t *me { AR_MSG(DBG_ERROR_PRIO, "CAPI_ALSA_DEVICE: Failed to allocate read_buffer, size=%d", me_ptr->read_buffer_size); + alsa_device_driver_close(&me_ptr->alsa_device_driver); return CAPI_ENOMEMORY; } @@ -404,7 +470,7 @@ static capi_err_t capi_alsa_device_process_set_properties(capi_alsa_device_t *me ar_result_t thread_result = posal_thread_launch(&me_ptr->dma_wait_thread, "ALSA_DMA_WAIT", - ALSA_DEVICE_STACK_SIZE, + ALSA_DEVICE_DMA_THREAD_STACK_SIZE, 0, capi_alsa_device_dma_wait_thread, (void *)me_ptr, @@ -413,6 +479,13 @@ static capi_err_t capi_alsa_device_process_set_properties(capi_alsa_device_t *me if (AR_EOK != thread_result) { AR_MSG(DBG_ERROR_PRIO, "CAPI_ALSA_DEVICE: Failed to create DMA wait thread"); + if (me_ptr->read_buffer) + { + posal_memory_free(me_ptr->read_buffer); + me_ptr->read_buffer = NULL; + } + alsa_device_driver_stop(&me_ptr->alsa_device_driver); + alsa_device_driver_close(&me_ptr->alsa_device_driver); return CAPI_EFAILED; } @@ -480,15 +553,9 @@ static capi_err_t capi_alsa_device_process_get_properties(capi_alsa_device_t *me mod_prop.init_memory_req = sizeof(capi_alsa_device_t); mod_prop.stack_size = ALSA_DEVICE_STACK_SIZE; - if (ALSA_DEVICE_SOURCE == dir) - { - num_intf_extns = ALSA_DEVICE_NUM_FRAMEWORK_EXTENSIONS_SOURCE; - fwk_extn_ids[0] = FWK_EXTN_STM; - } - else - { - num_intf_extns = ALSA_DEVICE_NUM_FRAMEWORK_EXTENSIONS_SINK; - } + num_intf_extns = ALSA_DEVICE_NUM_FRAMEWORK_EXTENSIONS; + /* Both source and sink declare FWK_EXTN_STM for signal-triggered operation. */ + fwk_extn_ids[0] = FWK_EXTN_STM; mod_prop.num_fwk_extns = num_intf_extns; mod_prop.fwk_extn_ids_arr = fwk_extn_ids; @@ -547,7 +614,6 @@ static capi_err_t capi_alsa_device_process_get_properties(capi_alsa_device_t *me { AR_MSG(DBG_ERROR_PRIO, "CAPI_ALSA_DEVICE: Not valid media format size %d", payload_ptr->actual_data_len); return CAPI_ENEEDMORE; - break; } capi_media_fmt_v2_t *media_fmt_ptr = (capi_media_fmt_v2_t *)(payload_ptr->data_ptr); @@ -740,27 +806,46 @@ capi_err_t capi_alsa_device_end(capi_t *_pif) capi_alsa_device_t *me_ptr = (capi_alsa_device_t *)_pif; - if (me_ptr->is_thread_running) + if (me_ptr->state == ALSA_DEVICE_INTERFACE_START) { - me_ptr->exit_thread = TRUE; - } + if (me_ptr->is_thread_running) + { + me_ptr->exit_thread = TRUE; + } - ar_result = alsa_device_driver_stop(&me_ptr->alsa_device_driver); - if (ar_result != AR_EOK) - { - AR_MSG(DBG_ERROR_PRIO, - "CAPI_ALSA_DEVICE: alsa_device_driver_stop failed with error code %d", - ar_result); - capi_result = CAPI_EFAILED; - } + ar_result = alsa_device_driver_stop(&me_ptr->alsa_device_driver); + if (ar_result != AR_EOK) + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_ALSA_DEVICE: alsa_device_driver_stop failed with error code %d", + ar_result); + capi_result = CAPI_EFAILED; + } - ar_result = alsa_device_driver_close(&me_ptr->alsa_device_driver); - if (ar_result != AR_EOK) - { - AR_MSG(DBG_ERROR_PRIO, - "CAPI_ALSA_DEVICE: alsa_device_driver_close failed with error code %d", - ar_result); - capi_result = CAPI_EFAILED; + /* Unblock DMA thread if it is waiting on process_done_cond for process_sink/source. + * pcm_stop() handles the case where it is blocked inside pcm_wait(). */ + posal_nmutex_lock(me_ptr->data_ready_lock); + me_ptr->data_ready = FALSE; + posal_nmutex_unlock(me_ptr->data_ready_lock); + posal_condvar_signal(me_ptr->process_done_cond); + + /* Join the DMA thread now that both blocking paths are unblocked. */ + if (me_ptr->dma_wait_thread != NULL) + { + ar_result_t thread_result = AR_EOK; + posal_thread_join(me_ptr->dma_wait_thread, &thread_result); + me_ptr->dma_wait_thread = NULL; + AR_MSG(DBG_HIGH_PRIO, "CAPI_ALSA_DEVICE: DMA wait thread joined"); + } + + ar_result = alsa_device_driver_close(&me_ptr->alsa_device_driver); + if (ar_result != AR_EOK) + { + AR_MSG(DBG_ERROR_PRIO, + "CAPI_ALSA_DEVICE: alsa_device_driver_close failed with error code %d", + ar_result); + capi_result = CAPI_EFAILED; + } } if (me_ptr->read_buffer) @@ -771,6 +856,9 @@ capi_err_t capi_alsa_device_end(capi_t *_pif) AR_MSG(DBG_HIGH_PRIO, "CAPI_ALSA_DEVICE: read_buffer freed"); } + posal_condvar_destroy(&me_ptr->process_done_cond); + posal_nmutex_destroy(&me_ptr->data_ready_lock); + me_ptr->state = ALSA_DEVICE_INTERFACE_STOP; me_ptr->vtbl.vtbl_ptr = NULL; return capi_result; @@ -1099,7 +1187,7 @@ capi_err_t capi_alsa_device_process_sink(capi_t *_pif, capi_stream_data_t *input num_samples_per_intr = me_ptr->int_samples_per_period; num_channels = me_ptr->num_channels; bytes_per_channel = me_ptr->bytes_per_channel; - bytes_per_sample = me_ptr->bit_width / 8; + bytes_per_sample = me_ptr->bytes_per_channel; word_size = bytes_per_sample << 3; total_bytes = bytes_per_channel * num_samples_per_intr * num_channels; expected_ip_len_per_ch = bytes_per_channel * num_samples_per_intr; @@ -1114,30 +1202,18 @@ capi_err_t capi_alsa_device_process_sink(capi_t *_pif, capi_stream_data_t *input if (me_ptr->state != ALSA_DEVICE_INTERFACE_START) { - ar_result = alsa_device_driver_open(&me_ptr->alsa_device_driver, me_ptr->direction); - if (ar_result != AR_EOK) - { - AR_MSG(DBG_ERROR_PRIO, "alsa_device_driver_open failed with error code %d", ar_result); - return CAPI_EFAILED; - } - AR_MSG(DBG_HIGH_PRIO, - "CAPI_ALSA_DEVICE: alsa_device_driver_open success rc: %d", - ar_result); - - ar_result = alsa_device_driver_prepare(&me_ptr->alsa_device_driver); - if (ar_result != AR_EOK) - { - AR_MSG(DBG_ERROR_PRIO, - "CAPI_ALSA_DEVICE: alsa_device_driver_prepare failed with error code %d", - ar_result); - return CAPI_EFAILED; - } - AR_MSG(DBG_HIGH_PRIO, - "CAPI_ALSA_DEVICE: alsa_device_driver_prepare success rc: %d", - ar_result); + AR_MSG(DBG_ERROR_PRIO, "CAPI_ALSA_DEVICE: Sink not started"); + return CAPI_EFAILED; + } - me_ptr->state =ALSA_DEVICE_INTERFACE_START; + posal_nmutex_lock(me_ptr->data_ready_lock); + if (!me_ptr->data_ready) + { + posal_nmutex_unlock(me_ptr->data_ready_lock); + AR_MSG(DBG_LOW_PRIO, "CAPI_ALSA_DEVICE: Spurious trigger, no data ready"); + return CAPI_EOK; } + posal_nmutex_unlock(me_ptr->data_ready_lock); // Size checks is_input_available = capi_alsa_device_check_data_sufficiency(*input, @@ -1169,7 +1245,7 @@ capi_err_t capi_alsa_device_process_sink(capi_t *_pif, capi_stream_data_t *input { need_to_underrun = TRUE; is_input_available = FALSE; - AR_MSG_ISLAND(DBG_ERROR_PRIO, "CAPI: Failed to interleave data"); + AR_MSG(DBG_ERROR_PRIO, "CAPI: Failed to interleave data"); } } } @@ -1221,10 +1297,19 @@ capi_err_t capi_alsa_device_process_sink(capi_t *_pif, capi_stream_data_t *input if (ar_result != AR_EOK) { AR_MSG(DBG_ERROR_PRIO, "alsa_device_driver_write failed with error code %d", ar_result); + posal_nmutex_lock(me_ptr->data_ready_lock); + me_ptr->data_ready = FALSE; + posal_nmutex_unlock(me_ptr->data_ready_lock); + posal_condvar_signal(me_ptr->process_done_cond); return CAPI_EFAILED; } - AR_MSG_ISLAND(DBG_HIGH_PRIO, "CAPI: alsa_device_driver_write successful, total bytes copied: %d", total_bytes_copied); + posal_nmutex_lock(me_ptr->data_ready_lock); + me_ptr->data_ready = FALSE; + posal_nmutex_unlock(me_ptr->data_ready_lock); + posal_condvar_signal(me_ptr->process_done_cond); + + AR_MSG(DBG_LOW_PRIO, "CAPI: alsa_device_driver_write successful, total bytes copied: %d", total_bytes_copied); return capi_result; } @@ -1330,8 +1415,8 @@ bool_t capi_alsa_device_check_data_sufficiency(capi_stream_data_t *input, /*--------------------------------------------------------------------- Function name: capi_alsa_device_process_source - DESCRIPTION: Processes capture (source) - copies data from read_buffer - populated by DMA thread to output buffers + DESCRIPTION: Processes capture (source) - reads PCM data directly + into output buffers via pcm_read -----------------------------------------------------------------------*/ capi_err_t capi_alsa_device_process_source(capi_t *_pif, capi_stream_data_t *input[], capi_stream_data_t *output[]) { @@ -1355,54 +1440,77 @@ capi_err_t capi_alsa_device_process_source(capi_t *_pif, capi_stream_data_t *inp return CAPI_EBADPARAM; } + posal_nmutex_lock(me_ptr->data_ready_lock); + if (!me_ptr->data_ready) + { + posal_nmutex_unlock(me_ptr->data_ready_lock); + /* Spurious trigger: data_ready is FALSE, meaning the DMA thread has not yet + * returned from pcm_wait. It is therefore not blocked on process_done_cond, + * so no signal is needed here. */ + AR_MSG(DBG_LOW_PRIO, "CAPI_ALSA_DEVICE: Spurious trigger, no data ready"); + return CAPI_EOK; + } + /* data_ready is TRUE: DMA thread has completed pcm_wait and is now blocked on + * process_done_cond waiting for this function to complete pcm_read. The lock + * is released before pcm_read since the DMA thread cannot proceed until + * process_done_cond is signaled at the end of this function. */ + posal_nmutex_unlock(me_ptr->data_ready_lock); + num_channels = me_ptr->num_channels; - bytes_per_sample = me_ptr->bit_width / 8; + bytes_per_sample = me_ptr->bytes_per_channel; word_size = bytes_per_sample << 3; total_bytes = me_ptr->read_buffer_size; - if (!me_ptr->data_ready) + if (CAPI_DEINTERLEAVED_UNPACKED == me_ptr->gen_cntr_alsa_device_media_fmt.format.data_interleaving) { - // Data not ready - this is an underrun condition - AR_MSG(DBG_ERROR_PRIO, "CAPI_ALSA_DEVICE: Underrun - no data available in read_buffer"); + uint32_t bytes_per_ch = total_bytes / num_channels; - // Fill output with zeros - if (CAPI_DEINTERLEAVED_UNPACKED == me_ptr->gen_cntr_alsa_device_media_fmt.format.data_interleaving) + for (uint32_t ch = 0; ch < num_channels; ch++) { - uint32_t bytes_per_ch = total_bytes / num_channels; - for (uint32_t ch = 0; ch < num_channels; ch++) + if (output[port]->buf_ptr[ch].max_data_len < bytes_per_ch) { - memset(output[port]->buf_ptr[ch].data_ptr, 0, bytes_per_ch); - output[port]->buf_ptr[ch].actual_data_len = bytes_per_ch; + AR_MSG(DBG_ERROR_PRIO, + "CAPI_ALSA_DEVICE: Output buffer too small ch %d. Required: %d, Available: %d", + ch, bytes_per_ch, output[port]->buf_ptr[ch].max_data_len); + posal_nmutex_lock(me_ptr->data_ready_lock); + me_ptr->data_ready = FALSE; + posal_nmutex_unlock(me_ptr->data_ready_lock); + posal_condvar_signal(me_ptr->process_done_cond); + return CAPI_ENOMEMORY; } } - else // CAPI_INTERLEAVED + + ar_result_t result = alsa_device_driver_read(&me_ptr->alsa_device_driver, + me_ptr->read_buffer, + total_bytes); + if (result != AR_EOK) { - memset(output[port]->buf_ptr[0].data_ptr, 0, total_bytes); - output[port]->buf_ptr[0].actual_data_len = total_bytes; + AR_MSG(DBG_ERROR_PRIO, "CAPI_ALSA_DEVICE: pcm_read failed in process_source, result=%d", result); + posal_nmutex_lock(me_ptr->data_ready_lock); + me_ptr->data_ready = FALSE; + posal_nmutex_unlock(me_ptr->data_ready_lock); + posal_condvar_signal(me_ptr->process_done_cond); + return CAPI_EFAILED; } - return CAPI_EOK; - } - // Data is ready - copy from read_buffer - if (CAPI_DEINTERLEAVED_UNPACKED == me_ptr->gen_cntr_alsa_device_media_fmt.format.data_interleaving) - { capi_buf_t intlv_buf; intlv_buf.data_ptr = me_ptr->read_buffer; intlv_buf.actual_data_len = total_bytes; intlv_buf.max_data_len = me_ptr->read_buffer_size; - // Deinterleave to output buffers if (AR_EOK != spf_intlv_to_deintlv(&intlv_buf, output[port]->buf_ptr, num_channels, word_size)) { AR_MSG(DBG_ERROR_PRIO, "CAPI_ALSA_DEVICE: Failed to deinterleave data"); + posal_nmutex_lock(me_ptr->data_ready_lock); + me_ptr->data_ready = FALSE; + posal_nmutex_unlock(me_ptr->data_ready_lock); + posal_condvar_signal(me_ptr->process_done_cond); return CAPI_EFAILED; } - // Update actual data length for each channel - uint32_t bytes_per_ch = total_bytes / num_channels; for (uint32_t ch = 0; ch < num_channels; ch++) { output[port]->buf_ptr[ch].actual_data_len = bytes_per_ch; @@ -1410,26 +1518,41 @@ capi_err_t capi_alsa_device_process_source(capi_t *_pif, capi_stream_data_t *inp } else // CAPI_INTERLEAVED { - // For interleaved output, copy directly to first buffer if (output[port]->buf_ptr[0].max_data_len < total_bytes) { AR_MSG(DBG_ERROR_PRIO, "CAPI_ALSA_DEVICE: Output buffer too small. Required: %d, Available: %d", total_bytes, output[port]->buf_ptr[0].max_data_len); + posal_nmutex_lock(me_ptr->data_ready_lock); + me_ptr->data_ready = FALSE; + posal_nmutex_unlock(me_ptr->data_ready_lock); + posal_condvar_signal(me_ptr->process_done_cond); return CAPI_ENOMEMORY; } - memscpy(output[port]->buf_ptr[0].data_ptr, - output[port]->buf_ptr[0].max_data_len, - me_ptr->read_buffer, - total_bytes); + ar_result_t result = alsa_device_driver_read(&me_ptr->alsa_device_driver, + output[port]->buf_ptr[0].data_ptr, + total_bytes); + if (result != AR_EOK) + { + AR_MSG(DBG_ERROR_PRIO, "CAPI_ALSA_DEVICE: pcm_read failed in process_source, result=%d", result); + posal_nmutex_lock(me_ptr->data_ready_lock); + me_ptr->data_ready = FALSE; + posal_nmutex_unlock(me_ptr->data_ready_lock); + posal_condvar_signal(me_ptr->process_done_cond); + return CAPI_EFAILED; + } + output[port]->buf_ptr[0].actual_data_len = total_bytes; } + posal_nmutex_lock(me_ptr->data_ready_lock); me_ptr->data_ready = FALSE; + posal_nmutex_unlock(me_ptr->data_ready_lock); + posal_condvar_signal(me_ptr->process_done_cond); - AR_MSG_ISLAND(DBG_HIGH_PRIO, "CAPI_ALSA_DEVICE: Process source successful, bytes: %d", total_bytes); + AR_MSG(DBG_LOW_PRIO, "CAPI_ALSA_DEVICE: Process source successful, bytes: %d", total_bytes); return capi_result; } @@ -1596,10 +1719,12 @@ ar_result_t capi_alsa_device_set_hw_ep_mf_cfg(param_id_hw_ep_mf_t *alsa_device_c if (DATA_FORMAT_COMPR_OVER_PCM_PACKETIZED == me_ptr->data_format) { me_ptr->gen_cntr_alsa_device_media_fmt.header.format_header.data_format = CAPI_COMPR_OVER_PCM_PACKETIZED; + me_ptr->gen_cntr_alsa_device_media_fmt.format.data_interleaving = CAPI_INTERLEAVED; } else { me_ptr->gen_cntr_alsa_device_media_fmt.header.format_header.data_format = CAPI_FIXED_POINT; + me_ptr->gen_cntr_alsa_device_media_fmt.format.data_interleaving = CAPI_DEINTERLEAVED_UNPACKED; } AR_MSG(DBG_HIGH_PRIO, "ALSA Device: Initialized data_format for SOURCE direction: %d", @@ -1626,6 +1751,15 @@ ar_result_t capi_alsa_device_set_hw_ep_mf_cfg(param_id_hw_ep_mf_t *alsa_device_c me_ptr->int_samples_per_period = me_ptr->sample_rate / NUM_MS_PER_SEC; } alsa_device_driver_set_cfg(&me_ptr->alsa_device_driver, alsa_device_cfg_ptr); + + /* If frame size arrived before MF, period_size was computed with rate=0. + * Recompute now that config->rate is valid. */ + if (me_ptr->frame_size_cfg_received) + { + param_id_frame_size_factor_t frame_size_cfg = { .frame_size_factor = me_ptr->frame_size_ms }; + alsa_device_driver_set_frame_size_cfg(&frame_size_cfg, &me_ptr->alsa_device_driver); + } + // Set flag to true me_ptr->ep_mf_received = TRUE; diff --git a/fwk/platform/modules/generic/endpoint/alsa_device/capi/src/capi_alsa_device_i.h b/fwk/platform/modules/generic/endpoint/alsa_device/capi/src/capi_alsa_device_i.h index c102caef..2c8af2e2 100644 --- a/fwk/platform/modules/generic/endpoint/alsa_device/capi/src/capi_alsa_device_i.h +++ b/fwk/platform/modules/generic/endpoint/alsa_device/capi/src/capi_alsa_device_i.h @@ -16,6 +16,8 @@ #include "alsa_device_api.h" #include "capi_cmn.h" #include "alsa_device_driver.h" +#include "posal_nmutex.h" +#include "posal_condvar.h" /*===================================================================== Macros @@ -28,10 +30,10 @@ #define min(A,B) ((A) < (B) ? (A) : (B)) #endif - /* Number of CAPI Framework extension needed -Note: this module is not defined as Signal Triggered Module */ -#define ALSA_DEVICE_NUM_FRAMEWORK_EXTENSIONS_SOURCE 1 -#define ALSA_DEVICE_NUM_FRAMEWORK_EXTENSIONS_SINK 0 + /* Number of CAPI Framework extensions needed — both source and sink declare FWK_EXTN_STM */ +#define ALSA_DEVICE_NUM_FRAMEWORK_EXTENSIONS 1 + +#define ALSA_DEVICE_DMA_THREAD_STACK_SIZE 8192 /* Number of milliseconds in a second*/ #define NUM_MS_PER_SEC 1000 @@ -105,15 +107,19 @@ typedef struct capi_alsa_device void * signal_ptr; // Signal ptr for STM uint32_t enable_stm; - /* Thread management for source direction */ + /* Thread management for DMA wait thread (used by both source and sink) */ posal_thread_t dma_wait_thread; // Thread handle for DMA waiting bool_t is_thread_running; // Thread running state bool_t exit_thread; // Thread exit flag - /* Buffer to store the data read form ALSA driver in wait thread */ - int8_t *read_buffer; // Buffer to hold one period of captured data + /* Intermediate buffer for deinterleaved capture path (interleaved staging) */ + int8_t *read_buffer; // Intermediate buffer for deinterleaved conversion uint32_t read_buffer_size; // Size of read buffer in bytes - bool_t data_ready; // Flag: data available in read buffer + bool_t data_ready; // Flag: pcm_wait has returned, period is available + + /* Synchronization between DMA thread and process_sink/source */ + posal_nmutex_t data_ready_lock; // Protects data_ready + posal_condvar_t process_done_cond; // Signaled by process_sink/source after pcm_write/read completes } capi_alsa_device_t; /*------------------------------------------------------------------------ diff --git a/fwk/platform/modules/generic/endpoint/alsa_device/lib/src/tinyalsa/alsa_device_driver.c b/fwk/platform/modules/generic/endpoint/alsa_device/lib/src/tinyalsa/alsa_device_driver.c index e27e266d..340f8559 100644 --- a/fwk/platform/modules/generic/endpoint/alsa_device/lib/src/tinyalsa/alsa_device_driver.c +++ b/fwk/platform/modules/generic/endpoint/alsa_device/lib/src/tinyalsa/alsa_device_driver.c @@ -28,7 +28,7 @@ ar_result_t alsa_device_driver_set_cfg(alsa_device_driver_t *alsa_device_driver_ if (alsa_device_cfg_ptr->bit_width == 32) config->format = PCM_FORMAT_S32_LE; else if (alsa_device_cfg_ptr->bit_width == 24) - config->format = PCM_FORMAT_S24_3LE; + config->format = PCM_FORMAT_S24_LE; else if (alsa_device_cfg_ptr->bit_width == 16) config->format = PCM_FORMAT_S16_LE; @@ -85,6 +85,11 @@ ar_result_t alsa_device_driver_open(alsa_device_driver_t *alsa_device_driver_ptr AR_MSG(DBG_ERROR_PRIO, "ALSA_DEVICE_DRIVER: Unable to open PCM device %u (%s)\n", alsa_device_driver_ptr->device_id, pcm_get_error(alsa_device_driver_ptr->pcm)); + if (alsa_device_driver_ptr->pcm) + { + pcm_close(alsa_device_driver_ptr->pcm); + alsa_device_driver_ptr->pcm = NULL; + } return AR_EFAILED; } @@ -146,7 +151,7 @@ ar_result_t alsa_device_driver_read(alsa_device_driver_t *alsa_device_driver_ptr return AR_EFAILED; } - AR_MSG(DBG_HIGH_PRIO, "ALSA_DEVICE_DRIVER: pcm_read success, bytes: %d", num_bytes); + AR_MSG(DBG_LOW_PRIO, "ALSA_DEVICE_DRIVER: pcm_read success, bytes: %d", num_bytes); return AR_EOK; } @@ -159,7 +164,7 @@ ar_result_t alsa_device_driver_write(alsa_device_driver_t *alsa_device_driver_pt return AR_EFAILED; } - //AR_MSG(DBG_HIGH_PRIO, "ALSA_DEVICE_DRIVER: pcm write success \n"); + AR_MSG(DBG_LOW_PRIO, "ALSA_DEVICE_DRIVER: pcm write success \n"); return AR_EOK; } @@ -184,9 +189,11 @@ ar_result_t alsa_device_driver_close(alsa_device_driver_t *alsa_device_driver_pt { AR_MSG(DBG_ERROR_PRIO, "ALSA_DEVICE_DRIVER: pcm close failed with error: %s\n", pcm_get_error(alsa_device_driver_ptr->pcm)); + alsa_device_driver_ptr->pcm = NULL; return AR_EFAILED; } + alsa_device_driver_ptr->pcm = NULL; AR_MSG(DBG_HIGH_PRIO, "ALSA_DEVICE_DRIVER: pcm close success.\n"); return AR_EOK; diff --git a/fwk/spf/apm/ext/multi_client/src/apm_multi_client.c b/fwk/spf/apm/ext/multi_client/src/apm_multi_client.c index d79b963f..df205b03 100644 --- a/fwk/spf/apm/ext/multi_client/src/apm_multi_client.c +++ b/fwk/spf/apm/ext/multi_client/src/apm_multi_client.c @@ -1103,14 +1103,16 @@ ar_result_t apm_multi_client_update_sg_calibration_state(apm_t *apm_info_ptr) { ar_result_t result = AR_EOK; apm_sub_graph_t *sub_graph_node_ptr = NULL; - spf_list_node_t *temp_cached_ptr; + spf_list_node_t *curr_ptr = apm_info_ptr->curr_cmd_ctrl_ptr->db_default_set_cfg_cmd_ctrl.parsed_sg_list_ptr; gpr_packet_t *packet_curr_client = (gpr_packet_t *)apm_info_ptr->curr_cmd_ctrl_ptr->cmd_msg.payload_ptr; while (NULL != curr_ptr) { - uint32_t sub_graph_id = *((uint32_t *)(curr_ptr->obj_ptr)); + spf_list_node_t *next_curr_ptr = curr_ptr->next_ptr; + + uint32_t sub_graph_id = *((uint32_t *)(curr_ptr->obj_ptr)); result = apm_db_get_sub_graph_node(&apm_info_ptr->graph_info, sub_graph_id, &sub_graph_node_ptr, APM_DB_OBJ_QUERY); @@ -1135,14 +1137,16 @@ ar_result_t apm_multi_client_update_sg_calibration_state(apm_t *apm_info_ptr) packet_curr_client->src_port, sub_graph_id); - temp_cached_ptr = curr_ptr; + uint32_t * temp_cached_obj_ptr = (uint32_t *)(curr_ptr->obj_ptr); apm_db_remove_node_from_list(&apm_info_ptr->curr_cmd_ctrl_ptr->db_default_set_cfg_cmd_ctrl.parsed_sg_list_ptr, (void *)(curr_ptr->obj_ptr), &apm_info_ptr->curr_cmd_ctrl_ptr->db_default_set_cfg_cmd_ctrl.num_subgraph_node); - posal_memory_free(temp_cached_ptr->obj_ptr); - curr_ptr = curr_ptr->next_ptr; + posal_memory_free((void*)temp_cached_obj_ptr); + temp_cached_obj_ptr = NULL; + + curr_ptr = next_curr_ptr; } return result; diff --git a/fwk/spf/apm/ext/multi_client/src/apm_multi_client_utils.c b/fwk/spf/apm/ext/multi_client/src/apm_multi_client_utils.c index f4a88376..a812e6ca 100644 --- a/fwk/spf/apm/ext/multi_client/src/apm_multi_client_utils.c +++ b/fwk/spf/apm/ext/multi_client/src/apm_multi_client_utils.c @@ -289,6 +289,8 @@ ar_result_t apm_multi_client_free_conn(apm_t *apm_info_ptr, apm_sub_graph_t *sub while (conn_cfg_list_ptr) { + spf_list_node_t *next_conn_cfg_list_ptr = conn_cfg_list_ptr->next_ptr; + apm_module_data_port_conn_t *conn_cfg_ptr = (apm_module_data_port_conn_t *)conn_cfg_list_ptr->obj_ptr; // All the connection from this SG should be removed either originating or ending @@ -322,7 +324,7 @@ ar_result_t apm_multi_client_free_conn(apm_t *apm_info_ptr, apm_sub_graph_t *sub conn_cfg_ptr = NULL; } - LIST_ADVANCE(conn_cfg_list_ptr); + conn_cfg_list_ptr = next_conn_cfg_list_ptr; } return result; @@ -340,6 +342,8 @@ ar_result_t apm_multi_client_free_ctrl_link(apm_t *apm_info_ptr, apm_sub_graph_t while (ctrl_link_cfg_list_ptr) { + spf_list_node_t *next_ctrl_link_cfg_list_ptr = ctrl_link_cfg_list_ptr->next_ptr; + apm_module_ctrl_port_conn_t *ctrl_link_cfg_ptr = (apm_module_ctrl_port_conn_t *)ctrl_link_cfg_list_ptr->obj_ptr; // All the connection from this SG should be removed either originating or ending @@ -373,7 +377,7 @@ ar_result_t apm_multi_client_free_ctrl_link(apm_t *apm_info_ptr, apm_sub_graph_t ctrl_link_cfg_ptr = NULL; } - LIST_ADVANCE(ctrl_link_cfg_list_ptr); + ctrl_link_cfg_list_ptr = next_ctrl_link_cfg_list_ptr; } return result; diff --git a/fwk/spf/containers/cmn/container_utils/core/inc/container_utils.h b/fwk/spf/containers/cmn/container_utils/core/inc/container_utils.h index 6070d639..ac2e9590 100644 --- a/fwk/spf/containers/cmn/container_utils/core/inc/container_utils.h +++ b/fwk/spf/containers/cmn/container_utils/core/inc/container_utils.h @@ -726,6 +726,7 @@ ar_result_t cu_register_module_events(cu_base_t *me_ptr, gpr_packet_t *packet_pt ar_result_t cu_register_module_events_v2(cu_base_t *me_ptr, gpr_packet_t *packet_ptr); ar_result_t cu_handle_cntr_events_reg_dereg(cu_base_t *me_ptr, topo_reg_event_t *reg_event_payload_ptr, bool_t is_register); ar_result_t cu_raise_container_events_to_clients(cu_base_t *me_ptr, uint32_t event_id, int8_t *payload_ptr, uint32_t payload_size); +ar_result_t cu_handle_md_tracking_internal_event(cu_base_t * me_ptr, gpr_packet_t *packet_ptr, spf_cfg_data_type_t cfg_type); ar_result_t cu_graph_connect(cu_base_t *me_ptr); ar_result_t cu_graph_control_connect(cu_base_t *me_ptr); diff --git a/fwk/spf/containers/cmn/container_utils/core/src/cu_cmd_handler.c b/fwk/spf/containers/cmn/container_utils/core/src/cu_cmd_handler.c index 99b149be..9cd40197 100644 --- a/fwk/spf/containers/cmn/container_utils/core/src/cu_cmd_handler.c +++ b/fwk/spf/containers/cmn/container_utils/core/src/cu_cmd_handler.c @@ -1779,3 +1779,51 @@ ar_result_t cu_process_cmd_queue(cu_base_t *me_ptr) me_ptr->flags.apm_cmd_context = FALSE; return result; } +ar_result_t cu_handle_md_tracking_internal_event(cu_base_t *me_ptr, gpr_packet_t *packet_ptr, spf_cfg_data_type_t cfg_type) +{ + ar_result_t result = AR_EOK; + + // Validate packet pointer + if (NULL == packet_ptr) + { + CU_MSG(me_ptr->gu_ptr->log_id, DBG_ERROR_PRIO, "invalid packet_ptr received."); + return AR_EBADPARAM; + } + + module_cmn_md_tracking_md_event_rsp_handle_t *tracking_event_ptr = GPR_PKT_GET_PAYLOAD(module_cmn_md_tracking_md_event_rsp_handle_t, packet_ptr); + + switch (tracking_event_ptr->tracking_rsp_cfg) + { + case TRACKING_MD_EVENT_RSP_SET_CFG: + { + + uint8_t *param_data_ptr = (uint8_t *)(tracking_event_ptr + 1); + + result = cu_set_get_cfgs_packed_loop(me_ptr, + param_data_ptr, + packet_ptr->dst_port, + tracking_event_ptr->tracking_event_payload_size, + TRUE, /* is_set_cfg */ + FALSE, /*is_out_of_band*/ + FALSE, /*is_deregister*/ + cfg_type); + + CU_MSG(me_ptr->gu_ptr->log_id, DBG_HIGH_PRIO, "done tracking MD event with result %lu", result); + + __gpr_cmd_free(packet_ptr); + break; + + } + default: + { + result = CAPI_EBADPARAM; + CU_MSG(me_ptr->gu_ptr->log_id, DBG_ERROR_PRIO, "Unsupported Tracking event RSP CFG: %lu", tracking_event_ptr->tracking_rsp_cfg); + + __gpr_cmd_free(packet_ptr); + break; + } + } + + + return result; +} diff --git a/fwk/spf/containers/cmn/container_utils/core/src/cu_gpr_if.c b/fwk/spf/containers/cmn/container_utils/core/src/cu_gpr_if.c index 7d7b021e..1ed940d8 100644 --- a/fwk/spf/containers/cmn/container_utils/core/src/cu_gpr_if.c +++ b/fwk/spf/containers/cmn/container_utils/core/src/cu_gpr_if.c @@ -72,6 +72,7 @@ uint32_t cu_gpr_callback(gpr_packet_t *packet, void *callback_data) case IMCL_INTER_PROC_TRIGGER_MSG_GPR: case IMCL_INTER_PROC_POLLING_MSG_GPR: case IMCL_INTER_PROC_PEER_STATE_UPDATE: + case EVENT_ID_MODULE_CMN_METADATA_CUSTOM_TRACKING_EVENT: // for polling message, first push to cmd Q. from there, we'll open the message and push to the ctrl port // Q // which will be polled at process boundary diff --git a/fwk/spf/containers/cmn/topologies/gen_topo/core/src/gen_topo_data_process_island.c b/fwk/spf/containers/cmn/topologies/gen_topo/core/src/gen_topo_data_process_island.c index a4915b38..190face2 100644 --- a/fwk/spf/containers/cmn/topologies/gen_topo/core/src/gen_topo_data_process_island.c +++ b/fwk/spf/containers/cmn/topologies/gen_topo/core/src/gen_topo_data_process_island.c @@ -694,7 +694,8 @@ GEN_TOPO_STATIC ar_result_t gen_topo_check_copy_between_modules(gen_topo_t * // Only try to propogate media fomrat if the next port state is started because MF will only be propogated if the // port state is started this will avoid infinite loop in GC. // Ref Test Case: dtmf_gen_cfg_cmd_seq_1 , dtmf_gen_cfg_cmd_seq_2 & dtmf_gen_cfg_cmd_seq_3 - if ((0 == next_bufs_ptr[0].actual_data_len) && (TOPO_PORT_STATE_STARTED == next_in_port_ptr->common.state)) + if ((0 == next_bufs_ptr[0].actual_data_len) && (TOPO_PORT_STATE_STARTED == next_in_port_ptr->common.state) + && (0 == next_module_ptr->pending_zeros_at_eos)) { gen_topo_propagate_media_fmt_from_module(topo_ptr, TRUE /* is_data_path*/, module_list_ptr); diff --git a/fwk/spf/containers/cmn/topologies/gen_topo/core/src/gen_topo_trigger_policy_island.c b/fwk/spf/containers/cmn/topologies/gen_topo/core/src/gen_topo_trigger_policy_island.c index 96c17542..6224c57a 100644 --- a/fwk/spf/containers/cmn/topologies/gen_topo/core/src/gen_topo_trigger_policy_island.c +++ b/fwk/spf/containers/cmn/topologies/gen_topo/core/src/gen_topo_trigger_policy_island.c @@ -1437,13 +1437,17 @@ gen_topo_data_need_t gen_topo_in_port_needs_data(gen_topo_t *topo_ptr, gen_topo_ else #endif { - // if there's a flushing EOS stuck, input is optional - if (in_port_ptr->common.sdata.flags.marker_eos) + // if there's a flushing EOS or DFG stuck, input is optional + /* Fix for DFG: + Ideally checking just for end_of_frame should be sufficient for DFG. + Since end_of_frame has wider scope threfore to limit the fix, DFG MD is looked up.*/ + if (in_port_ptr->common.sdata.flags.marker_eos || + (in_port_ptr->common.sdata.flags.end_of_frame && gen_topo_md_list_has_dfg(in_port_ptr->common.sdata.metadata_list_ptr))) { #ifdef TRIGGER_DEBUG_DEEP TOPO_MSG(topo_ptr->gu.log_id, DBG_LOW_PRIO, - " Module 0x%lX: Input port id:0x%lx, port has EOS. need data optionally", + " Module 0x%lX: Input port id:0x%lx, port has EOS or DFG. need data optionally", in_port_ptr->gu.cmn.module_ptr->module_instance_id, in_port_ptr->gu.cmn.id); #endif diff --git a/fwk/spf/containers/cmn/topologies/gen_topo/ext/metadata/inc/gen_topo_metadata.h b/fwk/spf/containers/cmn/topologies/gen_topo/ext/metadata/inc/gen_topo_metadata.h index fd3d5ff2..3cae0ed5 100644 --- a/fwk/spf/containers/cmn/topologies/gen_topo/ext/metadata/inc/gen_topo_metadata.h +++ b/fwk/spf/containers/cmn/topologies/gen_topo/ext/metadata/inc/gen_topo_metadata.h @@ -224,8 +224,8 @@ ar_result_t gen_topo_validate_metadata_eof(gen_topo_module_t *module_ptr); void gen_topo_populate_metadata_for_peer_cntr(gen_topo_t * gen_topo_ptr, gu_ext_out_port_t * ext_out_port_ptr, module_cmn_md_list_t **md_list_pptr, - module_cmn_md_list_t **out_md_list_pptr, - bool_t * out_buf_has_flushing_eos_ptr); + module_cmn_md_list_t **out_md_list_pptr, + bool_t * out_buf_has_flushing_eos_dfg_ptr); ar_result_t gen_topo_check_realloc_md_list_in_peer_heap_id(uint32_t log_id, gu_ext_out_port_t * ext_out_port_ptr, diff --git a/fwk/spf/containers/cmn/topologies/gen_topo/ext/metadata/src/gen_topo_metadata.c b/fwk/spf/containers/cmn/topologies/gen_topo/ext/metadata/src/gen_topo_metadata.c index 8b69e1fd..aa8ce8bc 100644 --- a/fwk/spf/containers/cmn/topologies/gen_topo/ext/metadata/src/gen_topo_metadata.c +++ b/fwk/spf/containers/cmn/topologies/gen_topo/ext/metadata/src/gen_topo_metadata.c @@ -15,6 +15,7 @@ #include "gen_topo_capi.h" #include "spf_ref_counter.h" #include "thin_topo_inline.h" +#include "dam_batch_metadata_api.h" static ar_result_t gen_topo_metadata_create_with_tracking(gen_topo_t * topo_ptr, module_cmn_md_list_t ** md_list_pptr, @@ -524,6 +525,124 @@ static ar_result_t gen_topo_raise_md_tracking_event(gen_topo_tracking_md_context return result; } +static ar_result_t gen_topo_raise_custom_md_tracking_event(gen_topo_tracking_md_context_t *cb_context_ptr, uint32_t ref_count) +{ + + //define outgoing payload struct + struct module_tracking_event_payload_t + { + module_cmn_md_tracking_md_event_rsp_handle_t tracking_header; + + struct tracking_data_t + { + apm_module_param_data_t header; + dam_batch_end_md_gen_t data; + }tracking_data; + }; + + ar_result_t result = AR_EOK; + if (NULL == cb_context_ptr->tracking_payload_ptr) + { + TOPO_MSG(cb_context_ptr->log_id, + DBG_HIGH_PRIO, + "MD_DBG: NULL md_tracking_ptr = 0x%X in callback", + cb_context_ptr->tracking_payload_ptr); + return result; + } + + if ((MODULE_CMN_MD_TRACKING_EVENT_POLICY_EACH == cb_context_ptr->flags.tracking_policy) || + ((MODULE_CMN_MD_TRACKING_EVENT_POLICY_LAST == cb_context_ptr->flags.tracking_policy) && (0 == ref_count))) + { + + uint32_t opcode = EVENT_ID_MODULE_CMN_METADATA_CUSTOM_TRACKING_EVENT; + + struct module_tracking_event_payload_t md_payload_send; + memset(&md_payload_send, 0, sizeof(md_payload_send)); + + module_cmn_md_tracking_payload_t *md_tracking_ptr = + (module_cmn_md_tracking_payload_t *)cb_context_ptr->tracking_payload_ptr; + + md_payload_send.tracking_header.tracking_payload.metadata_id = cb_context_ptr->metadata_id; + md_payload_send.tracking_header.tracking_payload.source_module_instance = md_tracking_ptr->src_port; + md_payload_send.tracking_header.tracking_payload.module_instance_id = cb_context_ptr->module_instance_id; + md_payload_send.tracking_header.tracking_payload.token_lsw = md_tracking_ptr->token_lsw; + md_payload_send.tracking_header.tracking_payload.token_msw = md_tracking_ptr->token_msw; + md_payload_send.tracking_header.tracking_payload.flags = (0 == ref_count) ? TRUE : FALSE; + md_payload_send.tracking_header.tracking_payload.status = cb_context_ptr->render_status; + + md_payload_send.tracking_header.tracking_rsp_cfg = TRACKING_MD_EVENT_RSP_SET_CFG; + md_payload_send.tracking_header.tracking_event_payload_size = sizeof(struct tracking_data_t); + + /* populate the payload header */ + dam_batch_end_md_gen_t *md_payload_ptr = (dam_batch_end_md_gen_t *)cb_context_ptr->md_payload_ptr; + + if (NULL == md_payload_ptr) + { + TOPO_MSG(cb_context_ptr->log_id, + DBG_ERROR_PRIO, + "MD_DBG: Null metadata payload pointer for DAM_BATCH_DONE_MD_ID_MARKER"); + return AR_EBADPARAM; + } + + apm_module_param_data_t *payload_header_ptr = &md_payload_send.tracking_data.header; + dam_batch_end_md_gen_t *payload_data_ptr = &md_payload_send.tracking_data.data; + + payload_header_ptr->module_instance_id = md_tracking_ptr->dest_port; + payload_header_ptr->param_id = md_payload_ptr->param_id; + payload_header_ptr->param_size = sizeof(dam_batch_end_md_gen_t); + + memscpy(payload_data_ptr, payload_header_ptr->param_size, md_payload_ptr, payload_header_ptr->param_size); + + TOPO_MSG(cb_context_ptr->log_id, + DBG_HIGH_PRIO, + "MD_DBG: md_event_param_id = %lu, md_param out_ch_idx = %lu", + payload_header_ptr->param_id, payload_data_ptr->output_port_idx); + + bool_t is_registered = FALSE; + (void)__gpr_cmd_is_registered(md_tracking_ptr->src_port, &is_registered); + // if stream close is done prior to render EOS, then client must not receive render EOS + if (is_registered) + { + gpr_cmd_alloc_send_t args; + args.src_domain_id = md_tracking_ptr->src_domain_id; + args.dst_domain_id = md_tracking_ptr->dst_domain_id; + args.src_port = md_tracking_ptr->src_port; + args.dst_port = md_tracking_ptr->dest_port; + args.token = md_tracking_ptr->token_msw; + args.opcode = opcode; + args.payload = &md_payload_send; + args.payload_size = sizeof(struct module_tracking_event_payload_t); + args.client_data = 0; + __gpr_cmd_alloc_send(&args); + + TOPO_MSG(cb_context_ptr->log_id, + DBG_HIGH_PRIO, + "MD_DBG: Raising tracking event for MD_ID (0x%lx) (src port 0x%lX), render status = %lu, " + "policy 0x%x ref_count = %lu cmd_opcode 0x%lX", + cb_context_ptr->metadata_id, + md_tracking_ptr->src_port, + cb_context_ptr->render_status, + cb_context_ptr->flags.tracking_policy, + ref_count, + opcode); + } + else + { + TOPO_MSG(cb_context_ptr->log_id, + DBG_HIGH_PRIO, + "MD_DBG: Not Raising tracking event for MD_ID (0x%lx) as client has closed the source module. " + "(src port 0x%lX), render status = %lu, policy 0x%x ref_count = %lu cmd_opcode 0x%lX", + cb_context_ptr->metadata_id, + md_tracking_ptr->src_port, + cb_context_ptr->render_status, + cb_context_ptr->flags.tracking_policy, + ref_count, + opcode); + } + } + return result; +} + void gen_topo_send_md_render_status(void *context_ptr, uint32_t ref_count) { gen_topo_tracking_md_context_t *cb_context_ptr = (gen_topo_tracking_md_context_t *)context_ptr; @@ -537,6 +656,11 @@ void gen_topo_send_md_render_status(void *context_ptr, uint32_t ref_count) { gen_topo_raise_eos_tracking_event(cb_context_ptr, ref_count); } + else if((DAM_BATCH_END_MD_ID_MARKER == cb_context_ptr->metadata_id) && + (MODULE_CMN_MD_TRACKING_USE_CUSTOM_EVENT == cb_context_ptr->tracking_payload_ptr->flags.requires_custom_event)) + { + gen_topo_raise_custom_md_tracking_event(cb_context_ptr, ref_count); + } else { gen_topo_raise_md_tracking_event(cb_context_ptr, ref_count); @@ -737,6 +861,22 @@ static ar_result_t gen_topo_metadata_create_with_tracking(gen_topo_t TOPO_MSG(log_id, DBG_ERROR_PRIO, "MD_DBG: Failed to create a metadata tracking pointer"); THROW(ar_result, result); } + + module_cmn_md_tracking_payload_t *md_tracking_payload_ptr = &tracking_info_ptr->tracking_payload; + + if( 0 == md_tracking_payload_ptr->src_domain_id && MODULE_CMN_MD_IS_INTERNAL_CLIENT_MD == flags.is_client_metadata) + { + uint32_t host_domain; + __gpr_cmd_get_host_domain_id(&host_domain); + + md_tracking_payload_ptr->src_domain_id = host_domain; + } + + if(0 == md_tracking_payload_ptr->dst_domain_id) + { + md_tracking_payload_ptr->dst_domain_id = md_tracking_payload_ptr->src_domain_id; + } + md_ptr->tracking_ptr = md_tracking_ref_ptr; memscpy(md_ptr->tracking_ptr, sizeof(module_cmn_md_tracking_payload_t), diff --git a/fwk/spf/containers/cmn/topologies/gen_topo/ext/metadata/src/gen_topo_metadata_island.c b/fwk/spf/containers/cmn/topologies/gen_topo/ext/metadata/src/gen_topo_metadata_island.c index b70b1ca1..ba1969b6 100644 --- a/fwk/spf/containers/cmn/topologies/gen_topo/ext/metadata/src/gen_topo_metadata_island.c +++ b/fwk/spf/containers/cmn/topologies/gen_topo/ext/metadata/src/gen_topo_metadata_island.c @@ -15,6 +15,7 @@ #include "gen_topo_capi.h" #include "spf_ref_counter.h" #include "thin_topo_inline.h" +#include "dam_batch_metadata_api.h" #define PRINT_MD_PROP_DBG_ISLAND(str1, str2, len_per_ch, str3, ...) \ TOPO_MSG_ISLAND(topo_ptr->gu.log_id, \ @@ -1158,9 +1159,9 @@ void gen_topo_populate_metadata_for_peer_cntr(gen_topo_t * gen_topo_pt gu_ext_out_port_t * ext_out_port_ptr, module_cmn_md_list_t **md_list_pptr, module_cmn_md_list_t **out_md_list_pptr, - bool_t * out_buf_has_flushing_eos_ptr) + bool_t * out_buf_has_flushing_eos_dfg_ptr) { - *out_buf_has_flushing_eos_ptr = FALSE; + *out_buf_has_flushing_eos_dfg_ptr = FALSE; if ((!md_list_pptr) || (!(*md_list_pptr))) { @@ -1203,7 +1204,7 @@ void gen_topo_populate_metadata_for_peer_cntr(gen_topo_t * gen_topo_pt } if (eos_metadata_ptr->flags.is_flushing_eos) { - *out_buf_has_flushing_eos_ptr = TRUE; + *out_buf_has_flushing_eos_dfg_ptr = TRUE; // Check if container voting changes need to be deferred for this Flushing EOS. gen_topo_check_eos_md_update_defer_voting_flag(&ext_out_port_ptr->int_out_port_ptr->cmn, md_ptr); @@ -1212,7 +1213,10 @@ void gen_topo_populate_metadata_for_peer_cntr(gen_topo_t * gen_topo_pt // should free only contr ref ptr. others should stay for next containers use gen_topo_free_eos_cargo(gen_topo_ptr, md_ptr, eos_metadata_ptr); } - + else if(MODULE_CMN_MD_ID_DFG == md_ptr->metadata_id) + { + *out_buf_has_flushing_eos_dfg_ptr = TRUE; + } #if defined(METADATA_DEBUGGING) TOPO_MSG_ISLAND(gen_topo_ptr->gu.log_id, DBG_HIGH_PRIO, @@ -1654,6 +1658,26 @@ capi_err_t gen_topo_capi_metadata_destroy(void * context_ptr, override_ctrl_to_disable_tracking_event); break; } + case DAM_BATCH_END_MD_ID_MARKER: + { + if (NULL != md_ptr->tracking_ptr) + { + // Exit island here since we need to do a mem free operation which is in nlpi + gen_topo_exit_island_temporarily(topo_ptr); + gen_topo_raise_tracking_event(topo_ptr, + md_sink_miid, + md_list_ptr, + !is_dropped, + (void *)&md_ptr->metadata_buf, //since metadata have payload + override_ctrl_to_disable_tracking_event); + } + + //Dont need to exit island here since gen_topo_free_md can return nodes in island as well + //if md node belongs to lpi pool + ar_result = gen_topo_free_md(topo_ptr, md_list_ptr, md_ptr, head_pptr); + + break; + } default: // For MODULE_CMN_MD_ID_DFG, this is sufficient { #ifdef METADATA_DEBUGGING diff --git a/fwk/spf/containers/gen_cntr/core/src/gen_cntr_cmd_handler.c b/fwk/spf/containers/gen_cntr/core/src/gen_cntr_cmd_handler.c index c0c65ca6..7b3f6db4 100644 --- a/fwk/spf/containers/gen_cntr/core/src/gen_cntr_cmd_handler.c +++ b/fwk/spf/containers/gen_cntr/core/src/gen_cntr_cmd_handler.c @@ -354,6 +354,10 @@ static ar_result_t gen_cntr_handle_rest_of_graph_open(cu_base_t *base_ptr, void // note: since newly opened modules/ports are not going to change the order of started_sorted_module_list therefore // not updating it + if (check_if_pass_thru_container(me_ptr)) + { + TRY(result, pt_cntr_init_data_ports_post_async_create_finish(&me_ptr->topo)); + } TRY(result, gen_cntr_allocate_wait_mask_arr(me_ptr)); @@ -591,6 +595,11 @@ ar_result_t gen_cntr_gpr_cmd(cu_base_t *base_ptr) cu_set_get_cfgs_packed(base_ptr, packet_ptr, SPF_CFG_DATA_SHARED_PERSISTENT); break; } + case EVENT_ID_MODULE_CMN_METADATA_CUSTOM_TRACKING_EVENT: + { + cu_handle_md_tracking_internal_event(base_ptr, packet_ptr, SPF_CFG_DATA_TYPE_DEFAULT); + break; + } default: { TRY(result, cu_gpr_cmd(base_ptr)); @@ -2371,7 +2380,10 @@ ar_result_t gen_cntr_initiate_duty_cycle_island_entry(cu_base_t *base_ptr) if (!me_ptr->cu.pm_info.flags.module_disallows_duty_cycling) { - gen_cntr_listen_to_controls(me_ptr); + /* Listen only to the control commands and not Data triggers + wakeups. This step should not be skipped for IoT application. + TODO: Generalize this implementation*/ + //gen_cntr_listen_to_controls(me_ptr); gen_cntr_handle_events_after_cmds(me_ptr, FALSE, result); cu_send_island_entry_ack_to_dcm(&me_ptr->cu); } diff --git a/fwk/spf/containers/gen_cntr/core/src/gen_cntr_data_handler_island.c b/fwk/spf/containers/gen_cntr/core/src/gen_cntr_data_handler_island.c index dcaa4729..584d1435 100644 --- a/fwk/spf/containers/gen_cntr/core/src/gen_cntr_data_handler_island.c +++ b/fwk/spf/containers/gen_cntr/core/src/gen_cntr_data_handler_island.c @@ -332,7 +332,7 @@ static ar_result_t gen_cntr_check_output_space_availability(gen_cntr_t * GEN_CNTR_MSG_ISLAND(me_ptr->topo.gu.log_id, DBG_ERROR_PRIO, - "Output buffer is too small (%lu - %lu) < (%lu) ", + "Output buffer is too small (%u - %u) < (%u) ", max_data_len, actual_data_len, actual_len); @@ -387,7 +387,7 @@ static ar_result_t gen_cntr_check_output_space_availability(gen_cntr_t * { GEN_CNTR_MSG_ISLAND(me_ptr->topo.gu.log_id, DBG_ERROR_PRIO, - "Output buffer is too small (%lu - %lu) < (%lu) ", + "Output buffer is too small (%u - %u) < (%u) ", ext_out_port_ptr->buf.max_data_len, ext_out_port_ptr->buf.actual_data_len, *total_len_ptr); diff --git a/fwk/spf/containers/gen_cntr/ext/err_check/src/gen_cntr_err_handler.c b/fwk/spf/containers/gen_cntr/ext/err_check/src/gen_cntr_err_handler.c index b4419171..ee907d56 100644 --- a/fwk/spf/containers/gen_cntr/ext/err_check/src/gen_cntr_err_handler.c +++ b/fwk/spf/containers/gen_cntr/ext/err_check/src/gen_cntr_err_handler.c @@ -98,7 +98,9 @@ ar_result_t gen_cntr_check_handle_signal_miss(gen_cntr_t *me_ptr, bool_t is_afte { GEN_CNTR_MSG(me_ptr->topo.gu.log_id, DBG_ERROR_PRIO, "Error in handling signal miss before process"); } - + // reset the counters to make sure false interrupts during the error handling is ignored + me_ptr->st_module.processed_interrupt_counter = 0; + me_ptr->st_module.raised_interrupt_counter = 0; *continue_processing = FALSE; } diff --git a/fwk/spf/containers/gen_cntr/ext/pass_thru_cntr/inc/pt_cntr.h b/fwk/spf/containers/gen_cntr/ext/pass_thru_cntr/inc/pt_cntr.h index b7260fc1..78628dc0 100644 --- a/fwk/spf/containers/gen_cntr/ext/pass_thru_cntr/inc/pt_cntr.h +++ b/fwk/spf/containers/gen_cntr/ext/pass_thru_cntr/inc/pt_cntr.h @@ -194,6 +194,7 @@ ar_result_t pt_cntr_create_module(gen_topo_t *topo_ptr, gen_topo_graph_init_t *graph_init_data_ptr); ar_result_t pt_cntr_init_ext_in_port(void *base_ptr, gu_ext_in_port_t *gu_ext_port_ptr); ar_result_t pt_cntr_init_ext_out_port(void *base_ptr, gu_ext_out_port_t *gu_ext_port_ptr); +ar_result_t pt_cntr_init_data_ports_post_async_create_finish(gen_topo_t *topo_ptr); ar_result_t pt_cntr_deinit_ext_in_port(void *base_ptr, gu_ext_in_port_t *gu_ext_port_ptr); diff --git a/fwk/spf/containers/gen_cntr/ext/pass_thru_cntr/src/pt_cmd_handler.c b/fwk/spf/containers/gen_cntr/ext/pass_thru_cntr/src/pt_cmd_handler.c index 395d62a9..66f3c127 100644 --- a/fwk/spf/containers/gen_cntr/ext/pass_thru_cntr/src/pt_cmd_handler.c +++ b/fwk/spf/containers/gen_cntr/ext/pass_thru_cntr/src/pt_cmd_handler.c @@ -113,9 +113,10 @@ ar_result_t pt_cntr_post_operate_on_ext_in_port(void *base_ gu_ext_in_port_t **ext_in_port_pptr, spf_cntr_sub_graph_list_t *spf_sg_list_ptr) { - ar_result_t result = AR_EOK; - gen_cntr_ext_in_port_t *ext_in_port_ptr = (gen_cntr_ext_in_port_t *)*ext_in_port_pptr; - gen_topo_input_port_t *in_port_ptr = (gen_topo_input_port_t *)ext_in_port_ptr->gu.int_in_port_ptr; + ar_result_t result = AR_EOK; + pt_cntr_t *me_ptr = (pt_cntr_t *)base_ptr; + pt_cntr_ext_in_port_t *ext_in_port_ptr = (pt_cntr_ext_in_port_t *)*ext_in_port_pptr; + gen_topo_input_port_t *in_port_ptr = (gen_topo_input_port_t *)ext_in_port_ptr->gc.gu.int_in_port_ptr; if (TOPO_SG_OP_STOP & sg_ops) { @@ -125,6 +126,26 @@ ar_result_t pt_cntr_post_operate_on_ext_in_port(void *base_ { // todo: check if the module's first input is getting started, then stop pushing zeros from the next module's // input + + // if only the external input is just opened for the first time, its possible that the buffer was never assigned + // to this port check if the port has valid MF and doesnt have the buffer, then we should trigger the buffer + // assignment and proc list update logic + // + // Note: if the port was stopped and getting started, then buffer may have been already assigned and going from + // stop to start will not trigger proc list update or buffer size change because the ext input rely on the self SG + // state which might have been started and buffer is already assigned on the first port start. + if (TOPO_PORT_STATE_STARTED == in_port_ptr->common.state && (TRUE == in_port_ptr->common.flags.is_mf_valid) && + (NULL == ext_in_port_ptr->topo_in_buf_ptr)) + { + CU_MSG(me_ptr->gc.cu.gu_ptr->log_id, + DBG_LOW_PRIO, + "cu_handle_sg_mgmt_cmd. sg_op %lu handling post operate on external input id 0x%lx", + sg_ops, + ext_in_port_ptr->gc.gu.int_in_port_ptr->cmn.id); + + result |= pt_cntr_update_module_process_list(me_ptr); + result |= pt_cntr_assign_port_buffers(me_ptr); + } } /* If ext input port receives both a self and peer stop/flush from upstream (any order) @@ -341,20 +362,17 @@ static ar_result_t pt_cntr_check_n_validate_module_static_properties(pt_cntr_t * ar_result_t pt_cntr_init_ext_in_port(void *base_ptr, gu_ext_in_port_t *gu_ext_port_ptr) { ar_result_t result = AR_EOK; - pt_cntr_ext_in_port_t *ext_in_port_ptr = (pt_cntr_ext_in_port_t *)gu_ext_port_ptr; - pt_cntr_input_port_t *in_port_ptr = (pt_cntr_input_port_t *)ext_in_port_ptr->gc.gu.int_in_port_ptr; - pt_cntr_module_t *module_ptr = (pt_cntr_module_t *)in_port_ptr->gc.gu.cmn.module_ptr; result = gen_cntr_init_ext_in_port(base_ptr, gu_ext_port_ptr); - in_port_ptr->sdata_ptr = &in_port_ptr->gc.common.sdata; - module_ptr->in_port_sdata_pptr[in_port_ptr->gc.gu.cmn.index] = &in_port_ptr->gc.common.sdata; - #ifdef VERBOSE_DEBUGGING pt_cntr_t *me_ptr = (pt_cntr_t *)base_ptr; + pt_cntr_ext_in_port_t *ext_in_port_ptr = (pt_cntr_ext_in_port_t *)gu_ext_port_ptr; + pt_cntr_input_port_t *in_port_ptr = (pt_cntr_input_port_t *)ext_in_port_ptr->gc.gu.int_in_port_ptr; + pt_cntr_module_t *module_ptr = (pt_cntr_module_t *)in_port_ptr->gc.gu.cmn.module_ptr; GEN_CNTR_MSG(me_ptr->gc.topo.gu.log_id, DBG_LOW_PRIO, - "Assigned self sdata ptr 0x%lx to module 0x%lx in_port_id 0x%x", + "Assigned sdata ptr 0x%lx to module 0x%lx in_port_id 0x%x", in_port_ptr->sdata_ptr, module_ptr->gc.topo.gu.module_instance_id, in_port_ptr->gc.gu.cmn.id); @@ -365,20 +383,17 @@ ar_result_t pt_cntr_init_ext_in_port(void *base_ptr, gu_ext_in_port_t *gu_ext_po ar_result_t pt_cntr_init_ext_out_port(void *base_ptr, gu_ext_out_port_t *gu_ext_port_ptr) { ar_result_t result = AR_EOK; - pt_cntr_ext_out_port_t *ext_out_port_ptr = (pt_cntr_ext_out_port_t *)gu_ext_port_ptr; - pt_cntr_output_port_t *out_port_ptr = (pt_cntr_output_port_t *)ext_out_port_ptr->gc.gu.int_out_port_ptr; - pt_cntr_module_t *module_ptr = (pt_cntr_module_t *)out_port_ptr->gc.gu.cmn.module_ptr; result = gen_cntr_init_ext_out_port(base_ptr, gu_ext_port_ptr); - out_port_ptr->sdata_ptr = &out_port_ptr->gc.common.sdata; - module_ptr->out_port_sdata_pptr[out_port_ptr->gc.gu.cmn.index] = &out_port_ptr->gc.common.sdata; - #ifdef VERBOSE_DEBUGGING pt_cntr_t *me_ptr = (pt_cntr_t *)base_ptr; + pt_cntr_ext_out_port_t *ext_out_port_ptr = (pt_cntr_ext_out_port_t *)gu_ext_port_ptr; + pt_cntr_output_port_t *out_port_ptr = (pt_cntr_output_port_t *)ext_out_port_ptr->gc.gu.int_out_port_ptr; + pt_cntr_module_t *module_ptr = (pt_cntr_module_t *)out_port_ptr->gc.gu.cmn.module_ptr; GEN_CNTR_MSG(me_ptr->gc.topo.gu.log_id, DBG_LOW_PRIO, - "Assigned self sdata ptr 0x%lx to module 0x%lx out_port_id 0x%x", + "Assigned sdata ptr 0x%lx to module 0x%lx out_port_id 0x%x", out_port_ptr->sdata_ptr, module_ptr->gc.topo.gu.module_instance_id, out_port_ptr->gc.gu.cmn.id); @@ -541,3 +556,68 @@ ar_result_t pt_cntr_create_module(gen_topo_t *topo_ptr, return result; } + +// some data ports could be added through async gu, and those ports would get a valid port index only after calling +// gu_async_create_finish(), PTC has dependency on the port indices hence newly opened ports should be handled +// under critical section through this function. +ar_result_t pt_cntr_init_data_ports_post_async_create_finish(gen_topo_t *topo_ptr) +{ + ar_result_t result = AR_EOK; + + gu_t *gu_ptr = get_gu_ptr_for_current_command_context(&topo_ptr->gu); + + // Consider only updated modules, for new or default status modules data port scratch will assigned during + // prepare. for updated modules scratch info needs to be updated here itself since the module may be part of + // the proc list and there is a chance that module process can be called before prepare is received. + + // New ports may be added. need to set it to module. + for (gu_ext_in_port_list_t *ext_in_port_list_ptr = gu_ptr->ext_in_port_list_ptr; (NULL != ext_in_port_list_ptr); + LIST_ADVANCE(ext_in_port_list_ptr)) + { + pt_cntr_input_port_t *in_port_ptr = + (pt_cntr_input_port_t *)ext_in_port_list_ptr->ext_in_port_ptr->int_in_port_ptr; + + pt_cntr_module_t *module_ptr = + (pt_cntr_module_t *)ext_in_port_list_ptr->ext_in_port_ptr->int_in_port_ptr->cmn.module_ptr; + + if (NULL == in_port_ptr->sdata_ptr) + { + in_port_ptr->sdata_ptr = &in_port_ptr->gc.common.sdata; + module_ptr->in_port_sdata_pptr[in_port_ptr->gc.gu.cmn.index] = &in_port_ptr->gc.common.sdata; + + GEN_CNTR_MSG(topo_ptr->gu.log_id, + DBG_LOW_PRIO, + "Assigning self sdata ptr 0x%lx to module 0x%lx external in_port_id 0x%x", + in_port_ptr->sdata_ptr, + module_ptr->gc.topo.gu.module_instance_id, + in_port_ptr->gc.gu.cmn.id); + } + } + + // New ports may be added. need to intialize sdata ptr for the ext port + for (gu_ext_out_port_list_t *ext_out_port_list_ptr = gu_ptr->ext_out_port_list_ptr; + (NULL != ext_out_port_list_ptr); + LIST_ADVANCE(ext_out_port_list_ptr)) + { + pt_cntr_output_port_t *out_port_ptr = + (pt_cntr_output_port_t *)ext_out_port_list_ptr->ext_out_port_ptr->int_out_port_ptr; + + pt_cntr_module_t *module_ptr = + (pt_cntr_module_t *)ext_out_port_list_ptr->ext_out_port_ptr->int_out_port_ptr->cmn.module_ptr; + + if (NULL == out_port_ptr->sdata_ptr) + { + out_port_ptr->sdata_ptr = &out_port_ptr->gc.common.sdata; + module_ptr->out_port_sdata_pptr[out_port_ptr->gc.gu.cmn.index] = &out_port_ptr->gc.common.sdata; + + GEN_CNTR_MSG(topo_ptr->gu.log_id, + DBG_LOW_PRIO, + "Assigning self sdata ptr 0x%lx to module 0x%lx out_port_id 0x%x", + out_port_ptr->sdata_ptr, + module_ptr->gc.topo.gu.module_instance_id, + out_port_ptr->gc.gu.cmn.id); + } + } + + return result; +} \ No newline at end of file diff --git a/fwk/spf/containers/gen_cntr/ext/pass_thru_cntr/src/pt_cntr_process.c b/fwk/spf/containers/gen_cntr/ext/pass_thru_cntr/src/pt_cntr_process.c index 0014430d..3236fd90 100644 --- a/fwk/spf/containers/gen_cntr/ext/pass_thru_cntr/src/pt_cntr_process.c +++ b/fwk/spf/containers/gen_cntr/ext/pass_thru_cntr/src/pt_cntr_process.c @@ -776,12 +776,12 @@ PT_CNTR_STATIC ar_result_t pt_cntr_post_process_peer_ext_output(pt_cntr_t &(ext_out_port_ptr->gc.gu), &(sdata_ptr->metadata_list_ptr)); - bool_t out_buf_has_flushing_eos = FALSE; + bool_t out_buf_has_flushing_eos_dfg = FALSE; gen_topo_populate_metadata_for_peer_cntr(&(me_ptr->gc.topo), &(ext_out_port_ptr->gc.gu), &(sdata_ptr->metadata_list_ptr), &out_buf_ptr->metadata_list_ptr, - &out_buf_has_flushing_eos); + &out_buf_has_flushing_eos_dfg); } #ifdef PT_CNTR_TIME_PROP_ENABLE @@ -2270,6 +2270,12 @@ ar_result_t pt_cntr_signal_trigger(cu_base_t *cu_ptr, uint32_t channel_bit_index // } } + if (me_ptr->gc.cu.cmd_msg.payload_ptr) + { + // if async command processing is going on then check for any pending event handling + gen_cntr_handle_fwk_events_in_data_path(&me_ptr->gc); + } + /*clear the trigger signal */ posal_signal_clear_inline(me_ptr->gc.st_module.trigger_signal_ptr); diff --git a/fwk/spf/containers/gen_cntr/ext/pass_thru_cntr/stub_src/pt_cntr.c b/fwk/spf/containers/gen_cntr/ext/pass_thru_cntr/stub_src/pt_cntr.c index e870507e..91dde1f2 100644 --- a/fwk/spf/containers/gen_cntr/ext/pass_thru_cntr/stub_src/pt_cntr.c +++ b/fwk/spf/containers/gen_cntr/ext/pass_thru_cntr/stub_src/pt_cntr.c @@ -70,6 +70,11 @@ ar_result_t pt_cntr_validate_media_fmt_thresh(pt_cntr_t *me_ptr) } ar_result_t pt_cntr_validate_topo_at_open(pt_cntr_t *me_ptr) +{ + return AR_EUNSUPPORTED; +} + +ar_result_t pt_cntr_init_data_ports_post_async_create_finish(gen_topo_t *topo_ptr) { return AR_EUNSUPPORTED; } \ No newline at end of file diff --git a/fwk/spf/containers/gen_cntr/ext/peer_cntr/src/gen_cntr_peer_cntr_output_island.c b/fwk/spf/containers/gen_cntr/ext/peer_cntr/src/gen_cntr_peer_cntr_output_island.c index e32faa3b..155c4c06 100644 --- a/fwk/spf/containers/gen_cntr/ext/peer_cntr/src/gen_cntr_peer_cntr_output_island.c +++ b/fwk/spf/containers/gen_cntr/ext/peer_cntr/src/gen_cntr_peer_cntr_output_island.c @@ -256,7 +256,7 @@ static ar_result_t gen_cntr_output_buf_set_up_peer_cntr(gen_cntr_t *me_ptr, gen_ static ar_result_t gen_cntr_populate_peer_cntr_out_buf(gen_cntr_t * me_ptr, gen_cntr_ext_out_port_t *ext_out_port_ptr, - bool_t * out_buf_has_flushing_eos_ptr) + bool_t * out_buf_has_flushing_eos_dfg_ptr) { ar_result_t result = AR_EOK; @@ -345,7 +345,7 @@ static ar_result_t gen_cntr_populate_peer_cntr_out_buf(gen_cntr_t * &(ext_out_port_ptr->gu), &(ext_out_port_ptr->md_list_ptr), outbuf_md_list_pptr, - out_buf_has_flushing_eos_ptr); + out_buf_has_flushing_eos_dfg_ptr); } #ifdef VERBOSE_DEBUGGING @@ -515,7 +515,7 @@ static ar_result_t gen_cntr_send_peer_cntr_out_buffers(gen_cntr_t * spf_msg_t * media_fmt_msg_ptr) { ar_result_t result = AR_EOK; - bool_t out_buf_has_flushing_eos = FALSE; + bool_t out_buf_has_flushing_eos_dfg = FALSE; if (media_fmt_msg_ptr && media_fmt_msg_ptr->payload_ptr) { @@ -583,7 +583,7 @@ static ar_result_t gen_cntr_send_peer_cntr_out_buffers(gen_cntr_t * return result; } - gen_cntr_populate_peer_cntr_out_buf(me_ptr, ext_out_port_ptr, &out_buf_has_flushing_eos); + gen_cntr_populate_peer_cntr_out_buf(me_ptr, ext_out_port_ptr, &out_buf_has_flushing_eos_dfg); // if module output unpacked, container needs to convert to packed. // note that internal output port may have new media format that hasn't been propagated to ext @@ -646,7 +646,7 @@ static ar_result_t gen_cntr_send_peer_cntr_out_buffers(gen_cntr_t * gen_cntr_clear_ext_out_bufs(ext_out_port_ptr, TRUE /*clear_max*/); // if flushing EOS was sent out, reset the ext out port - if (out_buf_has_flushing_eos) + if (out_buf_has_flushing_eos_dfg) { gen_cntr_ext_out_port_basic_reset(me_ptr, ext_out_port_ptr); if (FALSE == me_ptr->topo.flags.defer_voting_on_dfs_change) diff --git a/fwk/spf/containers/olc/core/src/olc_data_handler.c b/fwk/spf/containers/olc/core/src/olc_data_handler.c index 28f5d910..be6eeda7 100644 --- a/fwk/spf/containers/olc/core/src/olc_data_handler.c +++ b/fwk/spf/containers/olc/core/src/olc_data_handler.c @@ -981,12 +981,12 @@ ar_result_t olc_populate_peer_cntr_out_buf(olc_t *me_ptr, olc_ext_out_port_t *ex DATA_BUFFER_FLAG_TIMESTAMP_VALID_SHIFT); out_buf_ptr->timestamp = ts.value; - bool_t out_buf_has_flushing_eos; + bool_t out_buf_has_flushing_eos_dfg = FALSE; gen_topo_populate_metadata_for_peer_cntr(&(me_ptr->topo), &(ext_out_port_ptr->gu), &(ext_out_port_ptr->md_list_ptr), &(out_buf_ptr->metadata_list_ptr), - &out_buf_has_flushing_eos); + &out_buf_has_flushing_eos_dfg); #ifdef VERBOSE_DEBUGGING OLC_MSG(me_ptr->topo.gu.log_id, diff --git a/fwk/spf/containers/spl_cntr/core/src/spl_cntr_buf_util.c b/fwk/spf/containers/spl_cntr/core/src/spl_cntr_buf_util.c index b1df8988..27089566 100644 --- a/fwk/spf/containers/spl_cntr/core/src/spl_cntr_buf_util.c +++ b/fwk/spf/containers/spl_cntr/core/src/spl_cntr_buf_util.c @@ -1685,12 +1685,12 @@ ar_result_t spl_cntr_deliver_output_buffer(spl_cntr_t *me_ptr, spl_cntr_ext_out_ // Move md from ext out port to data msg. We always deliver the entire buffer, so we can also deliver // all metadata. - bool_t OUT_BUF_HAS_FLUSHING_EOS_UNUSED = FALSE; + bool_t OUT_BUF_HAS_FLUSHING_EOS_DFG_UNUSED = FALSE; gen_topo_populate_metadata_for_peer_cntr(&(me_ptr->topo.t_base), &(ext_out_port_ptr->gu), &(int_out_port_ptr->md_list_ptr), &(out_buf_msg_ptr->metadata_list_ptr), - &OUT_BUF_HAS_FLUSHING_EOS_UNUSED); + &OUT_BUF_HAS_FLUSHING_EOS_DFG_UNUSED); // At this point, md_list is NULL so it cannot contain any flushing eos. Set marker to FALSE. int_out_port_ptr->t_base.common.sdata.flags.marker_eos = FALSE; diff --git a/fwk/spf/interfaces/module/imcl/api/imcl_bt_sideband_encoder_feedback_api.h b/fwk/spf/interfaces/module/imcl/api/imcl_bt_sideband_encoder_feedback_api.h index 14ca9ebc..e6d18b04 100644 --- a/fwk/spf/interfaces/module/imcl/api/imcl_bt_sideband_encoder_feedback_api.h +++ b/fwk/spf/interfaces/module/imcl/api/imcl_bt_sideband_encoder_feedback_api.h @@ -55,7 +55,7 @@ typedef struct imcl_param_id_bt_sideband_encoder_feedback_t /* Payload of IMCL_PARAM_ID_BT_SIDEBAND_ENCODER_FEEDBACK_V2*/ typedef struct imcl_param_id_bt_sideband_encoder_feedback_v2_t { - uint8_t num_sidebands; + uint32_t num_sidebands; /** number of sideband payloads */ #ifdef __H2XML__ imcl_param_id_bt_sideband_encoder_feedback_v2_payload_t payload[0]; diff --git a/fwk/spf/interfaces/module/imcl/api/imcl_dam_detection_api.h b/fwk/spf/interfaces/module/imcl/api/imcl_dam_detection_api.h index c7186a5d..1228aea0 100644 --- a/fwk/spf/interfaces/module/imcl/api/imcl_dam_detection_api.h +++ b/fwk/spf/interfaces/module/imcl/api/imcl_dam_detection_api.h @@ -314,6 +314,16 @@ typedef enum * will exit island when the buffer is full, enter when the DAM is buffering * and Downstream module is done processing, wait for PARAM_ID_AUDIO_DAM_ALLOW_DCM_ISLAND_ENTRY */ + AUDIO_DAM_BATCH_STREAM_WITH_ISLAND_DUTY_CYCLING_MD_TRACKING_EVENT = 5, + /* Open gate for corresponding gate and send out data in batches along with + * the metadata i.e. only after batch amount of data is accumulated in the + * dam buffer, DAM sends the batch data and metadata repeatedly till gate + * close is requested. The metadata is inserted at the end of the batch. + * This metadata is consumed by the downstream and a GPR event is raised + * to DAM indicating that the batch is consumed. DAM will exit island when + * the buffer is full, enters back when the DAM is buffering and the metadata + * is consumed, wait for PARAM_ID_AUDIO_DAM_HANDLE_BATCH_TRACKING_EVENT */ + AUDIO_DAM_BATCH_INVALID = 0xFFFFFFFF /* Invalid option for gate_open */ } audio_dam_gate_ctrl_op_t; diff --git a/fwk/spf/interfaces/module/metadata/api/dam_batch_metadata_api.h b/fwk/spf/interfaces/module/metadata/api/dam_batch_metadata_api.h new file mode 100644 index 00000000..61886a3d --- /dev/null +++ b/fwk/spf/interfaces/module/metadata/api/dam_batch_metadata_api.h @@ -0,0 +1,52 @@ +#ifndef DAM_BATCH_METADATA_API_H +#define DAM_BATCH_METADATA_API_H +/** + * \file dam_batch_metadata_api.h + * \brief + * This file contains metadata IDs used by DAM to send batch tracking + * information downstream. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause-Clear + */ + +#include "ar_defs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /*__cplusplus*/ + +/** + Metadata ID for indicating the end of DAM Batch. + + module_cmn_md_t structure has to set the metadata_id field to this id + when the metadata is DAM_BATCH_END_MD_ID_MARKER. + + DAM_BATCH_END_MD_ID_MARKER payload for internal propagation within SPF is defined by dam_batch_end_md_gen_t +*/ +#define DAM_BATCH_END_MD_ID_MARKER 0x0A00106A + + +typedef struct dam_batch_end_md_gen_t dam_batch_end_md_gen_t; + +/** Payload sent along with DAM_BATCH_END_MD_ID_MARKER metadata +*/ +struct dam_batch_end_md_gen_t +{ + uint32_t param_id; + /*Parameter ID need to be handled on recieving tracking event*/ + + uint32_t output_port_idx; + /*DAM output port index where Duty Cycling is enabled*/ +}; + + +#ifdef __cplusplus +} +#endif /*__cplusplus */ + +// clang-format on + +#endif /* #ifndef DAM_BATCH_METADATA_API_H */ diff --git a/fwk/spf/interfaces/module/metadata/api/module_cmn_metadata.h b/fwk/spf/interfaces/module/metadata/api/module_cmn_metadata.h index ee1e8afd..29b7d42e 100644 --- a/fwk/spf/interfaces/module/metadata/api/module_cmn_metadata.h +++ b/fwk/spf/interfaces/module/metadata/api/module_cmn_metadata.h @@ -380,6 +380,46 @@ struct module_cmn_md_eos_t /**************************************** DFG - End *************************************/ +/* + * The custom event is raised if the SPF internal metadata is set as custom tracking metadata. + * The event will be sent to the GPR client from SPF in the following scenarios. + * + * Metadata is dropped in the SPF. + * Metadata is consumed by the the module and not propagated further. + * All sink modules including the hardware end-points would consume the metadata. +*/ +#define EVENT_ID_MODULE_CMN_METADATA_CUSTOM_TRACKING_EVENT 0x0300100F + +typedef struct module_cmn_md_tracking_md_event_rsp_handle_t module_cmn_md_tracking_md_event_rsp_handle_t; + +/*============================================================================== + Type Definitions +==============================================================================*/ +typedef enum +{ + TRACKING_MD_EVENT_RSP_INVALID = 0, + /* Invalid option for the tracking cmd */ + + TRACKING_MD_EVENT_RSP_SET_CFG = 1, + /* Handle the tracking event as SET config after reciving it at the CU layer. */ + +} module_cmn_tracking_event_rsp_cfg_t; + +/** Custom tracking event payload for metadata +*/ +struct module_cmn_md_tracking_md_event_rsp_handle_t +{ + metadata_tracking_event_t tracking_payload; + /* Tracking payload for the metadata used for generic events*/ + + module_cmn_tracking_event_rsp_cfg_t tracking_rsp_cfg; + /* GPR Tracking event command configuration */ + + uint32_t tracking_event_payload_size; + /* Size of the tracking metadata event payload */ + +}; + /** @} */ /* end_addtogroup capi_if_ext_metadata */ #ifdef __cplusplus diff --git a/fwk/spf/modules/audio_dam_buffer/api/audio_dam_buffer_api.h b/fwk/spf/modules/audio_dam_buffer/api/audio_dam_buffer_api.h index d2d407e8..f8be99c1 100644 --- a/fwk/spf/modules/audio_dam_buffer/api/audio_dam_buffer_api.h +++ b/fwk/spf/modules/audio_dam_buffer/api/audio_dam_buffer_api.h @@ -360,6 +360,20 @@ struct param_id_audio_ctrl_to_data_port_map_t #include "spf_end_pack.h" ; +/*============================================================================== + Constants +==============================================================================*/ + + /** + * PARAM_ID_AUDIO_DAM_HANDLE_BATCH_END_TRACKING_EVENT + * + * DAM sends this parameter to downstream as part of the tracking metadata payload. + * After consuming the batch, downstream raise a GPR tracking event back to inform + * about batch consumption through this parameter. + * + */ +#define PARAM_ID_AUDIO_DAM_HANDLE_BATCH_END_TRACKING_EVENT 0x08001BD3 + /** @} <-- End of the module -- > */ diff --git a/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer.c b/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer.c index 04a0ec58..71527fd6 100644 --- a/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer.c +++ b/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer.c @@ -1456,6 +1456,62 @@ capi_err_t capi_audio_dam_buffer_set_param_non_island(capi_t *ca break; } + case PARAM_ID_AUDIO_DAM_HANDLE_BATCH_END_TRACKING_EVENT: + { + + if (params_ptr->actual_data_len < sizeof(dam_batch_end_md_gen_t)) + { + DAM_MSG(me_ptr->miid, + DBG_ERROR_PRIO, + "capi_audio_dam: Param id 0x%lx Bad param size %lu", + (uint32_t)param_id, + params_ptr->actual_data_len); + return CAPI_ENEEDMORE; + } + + dam_batch_end_md_gen_t *md_event_ptr = (dam_batch_end_md_gen_t *)params_ptr->data_ptr; + + uint32_t op_port_index = md_event_ptr->output_port_idx; + + uint32_t op_arr_index = get_arr_index_from_port_index(me_ptr, op_port_index, FALSE); + + if(UMAX_32 == op_arr_index) + { + DAM_MSG(me_ptr->miid, + DBG_ERROR_PRIO, + "capi_audio_dam: Param id 0x%lx, recieved invalid port index %lu", + (uint32_t)param_id, + params_ptr->actual_data_len); + return CAPI_EBADPARAM; + } + + // Store the flag + me_ptr->out_port_info_arr[op_arr_index].ready_for_island_entry = TRUE; + + /* Decrease the count and check in island entry condition if this count is zero. */ + if(0 < me_ptr->out_port_info_arr[op_arr_index].ref_count_batch_end_md) + { + --me_ptr->out_port_info_arr[op_arr_index].ref_count_batch_end_md; + } + else + { + DAM_MSG(me_ptr->miid, DBG_MED_PRIO, "Invalid Ref count of batch end md"); + } + + bool_t can_enter_island = capi_audio_dam_check_island_entry_cond(me_ptr); + + // island entry conditions, pending_bytes -> 0, DCM mode enabled and port is intialized + if (can_enter_island) + { + result |= capi_dam_duty_cycling_buf_send_message_to_dcm(me_ptr, (uint32_t)SPF_MSG_CMD_DCM_REQ_FOR_UNBLOCK_ISLAND_ENTRY); + } + else + { + DAM_MSG(me_ptr->miid, DBG_MED_PRIO, "Island entry conditions not met.. Buffering data"); + } + + break; + } default: { DAM_MSG(me_ptr->miid, DBG_ERROR_PRIO, "capi_audio_dam: Unsupported Param id ::0x%x \n", param_id); @@ -2391,6 +2447,9 @@ static capi_err_t capi_audio_dam_data_port_op_handler(capi_audio_dam_t *me_ptr, me_ptr->out_port_info_arr[arr_index].is_open = FALSE; me_ptr->out_port_info_arr[arr_index].gate_ctrl_op = AUDIO_DAM_BATCH_INVALID; me_ptr->out_port_info_arr[arr_index].is_dcm_duty_cycling_enabled = FALSE; + me_ptr->out_port_info_arr[arr_index].handle_md_batch_tracking = FALSE; + me_ptr->out_port_info_arr[arr_index].is_partial_batch_drain_enabled = FALSE; + me_ptr->out_port_info_arr[arr_index].is_handle_partial_drain = FALSE; } break; @@ -2417,6 +2476,14 @@ static capi_err_t capi_audio_dam_data_port_op_handler(capi_audio_dam_t *me_ptr, me_ptr->out_port_info_arr[arr_index].is_dcm_duty_cycling_enabled = TRUE; } + else if(AUDIO_DAM_BATCH_STREAM_WITH_ISLAND_DUTY_CYCLING_MD_TRACKING_EVENT == me_ptr->out_port_info_arr[arr_index].gate_ctrl_op) + { + me_ptr->out_port_info_arr[arr_index].handle_md_batch_tracking = TRUE; + me_ptr->out_port_info_arr[arr_index].is_partial_batch_drain_enabled = TRUE; + me_ptr->out_port_info_arr[arr_index].is_dcm_duty_cycling_enabled = TRUE; + me_ptr->out_port_info_arr[arr_index].is_handle_partial_drain = FALSE; + } + /** for outputs trigger policy is optional present if gate is opened, other wise it is non-trigger * blocked*/ if (me_ptr->out_port_info_arr[arr_index].is_gate_opened) @@ -2470,28 +2537,53 @@ static capi_err_t capi_audio_dam_data_port_op_handler(capi_audio_dam_t *me_ptr, */ for (uint32_t arr_idx = 0; arr_idx < me_ptr->max_output_ports; arr_idx++) { - if ((!me_ptr->out_port_info_arr[arr_idx].is_gate_opened) || - (!is_dam_output_port_initialized(me_ptr, arr_idx)) || - (!me_ptr->out_port_info_arr[arr_idx].is_started) || - (!me_ptr->out_port_info_arr[arr_idx].strm_reader_ptr->is_batch_streaming)) + /** reset the circ buffer if gate is closed */ + if ((!me_ptr->out_port_info_arr[arr_idx].is_gate_opened) && + (is_dam_output_port_initialized(me_ptr, arr_idx))) + { + + // adjust rd ptr inorder to drop all the data + uint32_t read_offset_in_us = 0; + audio_dam_stream_read_adjust(me_ptr->out_port_info_arr[arr_idx].strm_reader_ptr, + read_offset_in_us, + NULL, + FALSE); + + continue; + } + else if ((!me_ptr->out_port_info_arr[arr_idx].is_gate_opened) || + (!is_dam_output_port_initialized(me_ptr, arr_idx)) || + (!me_ptr->out_port_info_arr[arr_idx].is_started) || + (!me_ptr->out_port_info_arr[arr_idx].strm_reader_ptr->is_batch_streaming)) { continue; } - audio_dam_force_set_pending_bytes(me_ptr->out_port_info_arr[arr_idx].strm_reader_ptr); + uint32_t pending_bytes = 0; + audio_dam_get_stream_reader_pending_bytes(me_ptr->out_port_info_arr[arr_idx].strm_reader_ptr, &pending_bytes); - // check if the DCM is eneabled and pending bytes is non-zero (capture transition from 0 -> non-zero number) - if (FALSE == me_ptr->out_port_info_arr[arr_idx].is_dcm_duty_cycling_enabled) + /* complete the current batch first then create next batch with remaining bytes*/ + if ((0 < pending_bytes) && me_ptr->out_port_info_arr[arr_idx].is_partial_batch_drain_enabled) { - posal_island_trigger_island_exit(); - capi_dam_duty_cycling_buf_send_message_to_dcm(me_ptr, (uint32_t)SPF_MSG_CMD_DCM_REQ_FOR_ISLAND_EXIT); + /* treat graph close as eos and drain partial data as seperate batch*/ + me_ptr->out_port_info_arr[arr_idx].is_handle_partial_drain = TRUE; } + else + { + audio_dam_force_set_pending_bytes(me_ptr->out_port_info_arr[arr_idx].strm_reader_ptr); - uint32_t pending_bytes = 0; - audio_dam_get_stream_reader_pending_bytes(me_ptr->out_port_info_arr[arr_idx].strm_reader_ptr, - &pending_bytes); + // check if the DCM is eneabled and pending bytes is non-zero (capture transition from 0 -> non-zero number) + if (FALSE == me_ptr->out_port_info_arr[arr_idx].is_dcm_duty_cycling_enabled) + { + posal_island_trigger_island_exit(); + capi_dam_duty_cycling_buf_send_message_to_dcm(me_ptr, (uint32_t)SPF_MSG_CMD_DCM_REQ_FOR_ISLAND_EXIT); + } + } - me_ptr->out_port_info_arr[arr_idx].bytes_before_eos = pending_bytes; + uint32_t unread_bytes = 0; + audio_dam_get_stream_reader_unread_bytes(me_ptr->out_port_info_arr[arr_idx].strm_reader_ptr, &unread_bytes); + + me_ptr->out_port_info_arr[arr_idx].bytes_before_eos = unread_bytes; if (me_ptr->out_port_info_arr[arr_idx].bytes_before_eos) { me_ptr->out_port_info_arr[arr_idx].pending_eos = TRUE; @@ -2508,6 +2600,21 @@ static capi_err_t capi_audio_dam_data_port_op_handler(capi_audio_dam_t *me_ptr, me_ptr->out_port_info_arr[arr_index].is_started = FALSE; me_ptr->out_port_info_arr[arr_index].gate_ctrl_op = AUDIO_DAM_BATCH_INVALID; me_ptr->out_port_info_arr[arr_index].is_dcm_duty_cycling_enabled = FALSE; + me_ptr->out_port_info_arr[arr_index].handle_md_batch_tracking = FALSE; + me_ptr->out_port_info_arr[arr_index].is_partial_batch_drain_enabled = FALSE; + me_ptr->out_port_info_arr[arr_index].is_handle_partial_drain = FALSE; + me_ptr->out_port_info_arr[arr_index].pending_eos = FALSE; + me_ptr->out_port_info_arr[arr_index].bytes_before_eos = 0; + + if (is_dam_output_port_initialized(me_ptr, arr_index)) + { + // Reset read offset to zero to drop all stale data + uint32_t read_offset_in_us = 0; + audio_dam_stream_read_adjust(me_ptr->out_port_info_arr[arr_index].strm_reader_ptr, + read_offset_in_us, + NULL, + FALSE); + } } break; diff --git a/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer_i.h b/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer_i.h index e5b538c0..8eaab5ab 100644 --- a/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer_i.h +++ b/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer_i.h @@ -25,6 +25,7 @@ #include "capi_intf_extn_data_port_operation.h" #include "capi_intf_extn_metadata.h" #include "other_metadata.h" +#include "dam_batch_metadata_api.h" #include "platform_internal_dcm_if.h" #ifdef __cplusplus @@ -179,6 +180,19 @@ typedef struct /* indicate if the EOS is yet to sent */ bool_t is_dcm_duty_cycling_enabled; bool_t ready_for_island_entry; + + /*Indicate if metadata needs to be sent after every batch in batching mode*/ + bool_t handle_md_batch_tracking; + /* ref count of end metadata sent for island entry condition*/ + uint32_t ref_count_batch_end_md; + + /* Indicate if partial data needs to be drained if eos is received*/ + bool_t is_partial_batch_drain_enabled; + bool_t is_handle_partial_drain; + + /*Handle frame size mismatch*/ + bool_t send_dfg_md; + } _aud_dam_output_port_info; typedef struct @@ -359,6 +373,8 @@ capi_err_t capi_audio_dam_imcl_trigger_island_entry(capi_audio_dam_t *me_ptr, uint32_t op_arr_index, vw_imcl_header_t *header_ptr); +bool_t capi_audio_dam_check_island_entry_cond(capi_audio_dam_t* me_ptr); + ///////////////////////////////////// GENERIC UTILS /////////////////////////////////////// capi_err_t capi_check_and_close_the_gate(capi_audio_dam_t *me_ptr, uint32_t op_arr_index, bool_t is_destroy); @@ -420,6 +436,12 @@ capi_err_t capi_dam_insert_flushing_eos_at_out_port(capi_audio_dam_t *me_ptr, bool_t skip_voting_on_eos, eos_type_t eos_type); +capi_err_t capi_dam_insert_tracking_md_at_out_port(capi_audio_dam_t *me_ptr, + capi_stream_data_t *output, + uint32_t output_port_index, + bool_t send_dfg_md, + bool_t is_eos_case); + capi_vtbl_t *capi_audio_dam_buffer_get_vtable(); static inline POSAL_HEAP_ID capi_audio_dam_get_peer_heap_id(capi_audio_dam_t *me_ptr, uint32_t op_arr_idx) diff --git a/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer_imc_utils.c b/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer_imc_utils.c index d4cf322d..9cb1dba6 100644 --- a/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer_imc_utils.c +++ b/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer_imc_utils.c @@ -21,7 +21,6 @@ static capi_err_t capi_audio_dam_imcl_set_hdlr_drain_history_data(capi_audio_dam uint32_t op_arr_index, param_id_audio_dam_data_flow_ctrl_t *cfg_ptr); -static bool_t capi_audio_dam_check_island_entry_cond(capi_audio_dam_t* me_ptr); static capi_err_t capi_audio_dam_raise_allow_duty_cycling(capi_audio_dam_t *me_ptr, bool_t allow_duty_cycling) { capi_err_t result = CAPI_EOK; @@ -164,6 +163,7 @@ capi_err_t capi_audio_dam_imcl_set_hdlr_flow_ctrl_v2(capi_audio_dam_t *me_ptr, } case AUDIO_DAM_BATCH_STREAM: case AUDIO_DAM_BATCH_STREAM_WITH_ISLAND_DUTY_CYCLING: + case AUDIO_DAM_BATCH_STREAM_WITH_ISLAND_DUTY_CYCLING_MD_TRACKING_EVENT: { DAM_MSG(me_ptr->miid, DBG_HIGH_PRIO, @@ -177,12 +177,19 @@ capi_err_t capi_audio_dam_imcl_set_hdlr_flow_ctrl_v2(capi_audio_dam_t *me_ptr, result = capi_audio_dam_imcl_handle_gate_open(me_ptr, op_arr_index, (param_id_audio_dam_data_flow_ctrl_t *)cfg_ptr); - if (AUDIO_DAM_BATCH_STREAM_WITH_ISLAND_DUTY_CYCLING == cfg_ptr->gate_ctrl) + if (AUDIO_DAM_BATCH_STREAM_WITH_ISLAND_DUTY_CYCLING == cfg_ptr->gate_ctrl || AUDIO_DAM_BATCH_STREAM_WITH_ISLAND_DUTY_CYCLING_MD_TRACKING_EVENT == cfg_ptr->gate_ctrl) { me_ptr->out_port_info_arr[op_arr_index].is_dcm_duty_cycling_enabled = TRUE; me_ptr->out_port_info_arr[op_arr_index].ready_for_island_entry = TRUE; - me_ptr->out_port_info_arr[op_arr_index].gate_ctrl_op = AUDIO_DAM_BATCH_STREAM_WITH_ISLAND_DUTY_CYCLING; + + if(AUDIO_DAM_BATCH_STREAM_WITH_ISLAND_DUTY_CYCLING_MD_TRACKING_EVENT == cfg_ptr->gate_ctrl) + { + me_ptr->out_port_info_arr[op_arr_index].handle_md_batch_tracking = TRUE; + me_ptr->out_port_info_arr[op_arr_index].is_partial_batch_drain_enabled = TRUE; + } + + me_ptr->out_port_info_arr[op_arr_index].gate_ctrl_op = cfg_ptr->gate_ctrl; capi_audio_dam_raise_allow_duty_cycling(me_ptr, TRUE); } break; @@ -239,7 +246,7 @@ static capi_err_t capi_audio_dam_imcl_set_hdlr_drain_history_data(capi_audio_dam return result; } -static bool_t capi_audio_dam_check_island_entry_cond(capi_audio_dam_t* me_ptr) +bool_t capi_audio_dam_check_island_entry_cond(capi_audio_dam_t* me_ptr) { uint32_t pending_bytes_to_read = 0; bool_t trigger_dcm_island_entry = TRUE; @@ -260,12 +267,22 @@ static bool_t capi_audio_dam_check_island_entry_cond(capi_audio_dam_t* me_ptr) DAM_MSG(me_ptr->miid, DBG_MED_PRIO, "Processing on port_index:%d still going on", i); trigger_dcm_island_entry = FALSE; } + if(me_ptr->out_port_info_arr[i].is_handle_partial_drain) + { + DAM_MSG(me_ptr->miid, DBG_MED_PRIO, "EOS patial batch needs to be handled on port_index: %d", i); + return FALSE; + } audio_dam_get_stream_reader_pending_bytes(me_ptr->out_port_info_arr[i].strm_reader_ptr, &pending_bytes_to_read); if (pending_bytes_to_read) { DAM_MSG(me_ptr->miid, DBG_MED_PRIO, "Batching stream data buffering started on port_index: %d, pending_bytes:%lu", i, pending_bytes_to_read); return FALSE; } + if(0 != me_ptr->out_port_info_arr[i].ref_count_batch_end_md && me_ptr->out_port_info_arr[i].handle_md_batch_tracking) + { + DAM_MSG(me_ptr->miid, DBG_MED_PRIO, "Ref batch end md count is: %lu", me_ptr->out_port_info_arr[i].ref_count_batch_end_md); + return FALSE; + } } return trigger_dcm_island_entry; } diff --git a/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer_island.c b/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer_island.c index bc73efe0..2231cd07 100644 --- a/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer_island.c +++ b/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer_island.c @@ -54,7 +54,8 @@ uint32_t capi_dam_get_ctrl_port_arr_idx_from_ctrl_port_id(capi_audio_dam_t *me_p static capi_err_t capi_audio_dam_handle_and_drop_metadata(capi_audio_dam_t *me_ptr, capi_stream_data_t *input, - uint32_t ip_port_index) + uint32_t ip_port_index, + bool_t *is_eos_recieved) { capi_err_t capi_result = CAPI_EOK; capi_stream_data_v2_t *in_stream_ptr = (capi_stream_data_v2_t *)input; @@ -76,21 +77,8 @@ static capi_err_t capi_audio_dam_handle_and_drop_metadata(capi_audio_dam_t *me else if (MODULE_CMN_MD_ID_EOS == node_ptr->obj_ptr->metadata_id) { DAM_MSG_ISLAND(me_ptr->miid, DBG_HIGH_PRIO, "EOS rcvd"); - - for (uint32_t op_arr_index = 0; op_arr_index < me_ptr->max_output_ports; op_arr_index++) - { - /** do not reset the circ buffer if gate is open*/ - if (!me_ptr->out_port_info_arr[op_arr_index].is_gate_opened) - { - - // adjust rd ptr inorder to drop all the data - uint32_t read_offset_in_us = 0; - audio_dam_stream_read_adjust(me_ptr->out_port_info_arr[op_arr_index].strm_reader_ptr, - read_offset_in_us, - NULL, - FALSE); - } - } + // handle the eos after stream write + *is_eos_recieved = TRUE; } if (me_ptr->metadata_handler.metadata_destroy) @@ -114,6 +102,44 @@ static capi_err_t capi_audio_dam_handle_and_drop_metadata(capi_audio_dam_t *me return capi_result; } +static capi_err_t capi_audio_dam_handle_eos_and_partial_batch(capi_audio_dam_t *me_ptr, bool_t new_data_arrived, bool_t is_eos_recieved) +{ + capi_err_t capi_result = CAPI_EOK; + + for (uint32_t op_arr_index = 0; op_arr_index < me_ptr->max_output_ports; op_arr_index++) + { + + if(new_data_arrived && me_ptr->out_port_info_arr[op_arr_index].is_handle_partial_drain) + { + DAM_MSG_ISLAND(me_ptr->miid, DBG_ERROR_PRIO, " Previous EOS event is not handled yet, Merging new data in the partial batch."); + me_ptr->out_port_info_arr[op_arr_index].is_handle_partial_drain = FALSE; + } + + if(is_eos_recieved) + { + /** do not reset the circ buffer if gate is open*/ + if (!me_ptr->out_port_info_arr[op_arr_index].is_gate_opened) + { + // adjust rd ptr inorder to drop all the data + uint32_t read_offset_in_us = 0; + audio_dam_stream_read_adjust(me_ptr->out_port_info_arr[op_arr_index].strm_reader_ptr, + read_offset_in_us, + NULL, + FALSE); + } + + /** Handle partial batch */ + if(me_ptr->out_port_info_arr[op_arr_index].is_partial_batch_drain_enabled) + { + me_ptr->out_port_info_arr[op_arr_index].is_handle_partial_drain = TRUE; + } + + } + } + + return capi_result; +} + /*------------------------------------------------------------------------ Function name: capi_audio_dam_buffer_process Processes an input buffer and generates an output buffer. @@ -137,6 +163,8 @@ capi_err_t capi_audio_dam_buffer_process(capi_t *capi_ptr, capi_stream_data_t *i if (input) { + bool_t is_eos_recieved = FALSE; + for (uint32_t arr_idx = 0; arr_idx < me_ptr->max_input_ports; arr_idx++) { // Check the port index from arr index @@ -149,7 +177,7 @@ capi_err_t capi_audio_dam_buffer_process(capi_t *capi_ptr, capi_stream_data_t *i continue; } - result |= capi_audio_dam_handle_and_drop_metadata(me_ptr, input[port_index], port_index); + result |= capi_audio_dam_handle_and_drop_metadata(me_ptr, input[port_index], port_index, &is_eos_recieved); // input port buffers sanity check if ((NULL == me_ptr->in_port_info_arr[arr_idx].strm_writer_ptr) || @@ -179,6 +207,11 @@ capi_err_t capi_audio_dam_buffer_process(capi_t *capi_ptr, capi_stream_data_t *i input[port_index]->flags.is_timestamp_valid, input[port_index]->buf_ptr[0].actual_data_len); #endif + + + bool_t new_data_arrived = input[port_index]->buf_ptr[0].actual_data_len > 0? TRUE : FALSE; + capi_audio_dam_handle_eos_and_partial_batch(me_ptr, new_data_arrived, is_eos_recieved); + } } @@ -240,9 +273,37 @@ capi_err_t capi_audio_dam_buffer_process(capi_t *capi_ptr, capi_stream_data_t *i uint32_t output_frame_len_us = 0; bool_t is_timestamp_valid = FALSE; + // Handle partial drain: Wait for pending bytes to become zero, then force drain + bool_t is_batching_req_met = FALSE; + if(TRUE == me_ptr->out_port_info_arr[arr_idx].is_handle_partial_drain) + { + uint32_t pending_batch_bytes = 0; + audio_dam_get_stream_reader_pending_bytes(me_ptr->out_port_info_arr[arr_idx].strm_reader_ptr, &pending_batch_bytes); + + // Only drain when pending bytes become zero (current batch completes) + if(0 == pending_batch_bytes) + { + //force set the unread bytes in DAM buffer to pending bytes + audio_dam_force_set_pending_bytes(me_ptr->out_port_info_arr[arr_idx].strm_reader_ptr); + + audio_dam_get_stream_reader_pending_bytes(me_ptr->out_port_info_arr[arr_idx].strm_reader_ptr, &pending_batch_bytes); + DAM_MSG_ISLAND(me_ptr->miid, DBG_HIGH_PRIO, " Partial batch created with total_data_bytes: %lu.", pending_batch_bytes); + + //pending bytes must be non-zero for island exit + if(0 < pending_batch_bytes) + { + is_batching_req_met = TRUE; + me_ptr->out_port_info_arr[arr_idx].send_dfg_md = TRUE; + } + + me_ptr->out_port_info_arr[arr_idx].is_handle_partial_drain = FALSE; + } + } + if (me_ptr->out_port_info_arr[arr_idx].is_dcm_duty_cycling_enabled) { - bool_t is_batching_req_met = audio_dam_if_batching_req_met(me_ptr->out_port_info_arr[arr_idx].strm_reader_ptr); + is_batching_req_met |= audio_dam_if_batching_req_met(me_ptr->out_port_info_arr[arr_idx].strm_reader_ptr); + if (is_batching_req_met) { DAM_MSG_ISLAND(me_ptr->miid, DBG_MED_PRIO, "voting for island exit"); @@ -253,12 +314,15 @@ capi_err_t capi_audio_dam_buffer_process(capi_t *capi_ptr, capi_stream_data_t *i } } + + bool_t is_batch_sent = false; result = audio_dam_stream_read(me_ptr->out_port_info_arr[arr_idx].strm_reader_ptr, num_output_chs, output[port_index]->buf_ptr, &is_timestamp_valid, &output[port_index]->timestamp, - &output_frame_len_us); + &output_frame_len_us, + &is_batch_sent); if (AR_ENEEDMORE == result) { @@ -267,12 +331,33 @@ capi_err_t capi_audio_dam_buffer_process(capi_t *capi_ptr, capi_stream_data_t *i } else if (AR_EOK == result) // If read was successful update the current timestamp. { - if (me_ptr->out_port_info_arr[arr_idx].pending_eos) + /* Snapshot pending_eos before handle_pending_eos can clear it, so we can detect + whether EOS was actually inserted in this process call. */ + bool_t was_eos_pending = me_ptr->out_port_info_arr[arr_idx].pending_eos; + if (was_eos_pending) { posal_island_trigger_island_exit(); capi_audio_dam_handle_pending_eos(me_ptr, output, arr_idx, port_index); } + if(me_ptr->out_port_info_arr[arr_idx].handle_md_batch_tracking && (is_batch_sent)) //send the marker metadata as batch is sent + { + bool_t is_eos_case = was_eos_pending && !me_ptr->out_port_info_arr[arr_idx].pending_eos; + if (is_eos_case) + { + me_ptr->out_port_info_arr[arr_idx].send_dfg_md = FALSE; // enforce EOS wins over DFG if pending EOS is there. + } + + if (CAPI_EOK == (result = capi_dam_insert_tracking_md_at_out_port(me_ptr, output[port_index], port_index, me_ptr->out_port_info_arr[arr_idx].send_dfg_md, is_eos_case))) + { + DAM_MSG_ISLAND(me_ptr->miid, + DBG_HIGH_PRIO, + "DAM: Inserted tracking MD after Batch"); + ++me_ptr->out_port_info_arr[arr_idx].ref_count_batch_end_md; + } + me_ptr->out_port_info_arr[arr_idx].send_dfg_md = FALSE; + } + output[port_index]->flags.is_timestamp_valid = is_timestamp_valid; if (me_ptr->out_port_info_arr[arr_idx].ftrt_unread_data_len_in_us) diff --git a/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer_output_ctrl_island.c b/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer_output_ctrl_island.c index c185af09..9c56955d 100644 --- a/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer_output_ctrl_island.c +++ b/fwk/spf/modules/audio_dam_buffer/capi/src/capi_audio_dam_buffer_output_ctrl_island.c @@ -139,7 +139,7 @@ capi_err_t capi_check_and_close_the_gate(capi_audio_dam_t *me_ptr, uint32_t op_a // For Acoustic Activity Detection usecase, we do not support best channel feature, so we dont have to revert the channel order. if (FALSE == me_ptr->out_port_info_arr[op_arr_index].is_peer_aad) { - posal_island_trigger_island_exit(); + posal_island_trigger_island_exit(); capi_audio_dam_reorder_chs_at_gate_close(me_ptr, op_arr_index, is_destroy); // In AAD usecase, do not update KPPS in process context. @@ -289,3 +289,101 @@ capi_err_t capi_dam_insert_flushing_eos_at_out_port(capi_audio_dam_t *me_ptr, return capi_result; } + +capi_err_t capi_dam_insert_tracking_md_at_out_port(capi_audio_dam_t *me_ptr, + capi_stream_data_t *output, + uint32_t output_port_index, + bool_t send_dfg_md, + bool_t is_eos_case) +{ + capi_err_t capi_result = CAPI_EOK; + capi_stream_data_v2_t *out_stream_ptr = (capi_stream_data_v2_t *)output; + module_cmn_md_tracking_t batch_tracking_md_info; + memset(&batch_tracking_md_info, 0, sizeof(batch_tracking_md_info)); + + if (CAPI_STREAM_V2 != out_stream_ptr->flags.stream_data_version) + { + DAM_MSG_ISLAND(me_ptr->miid, DBG_ERROR_PRIO, "capi_audio_dam: stream version must be 1"); + return CAPI_EFAILED; + } + module_cmn_md_list_t **md_list_pptr = &out_stream_ptr->metadata_list_ptr; + module_cmn_md_t *new_md_ptr = NULL; + dam_batch_end_md_gen_t *md_payload_ptr = NULL; + capi_heap_id_t heap; + heap.heap_id = (uint32_t)me_ptr->heap_id; + module_cmn_md_flags_t flags; + + batch_tracking_md_info.heap_info.heap_id = heap.heap_id; + batch_tracking_md_info.tracking_payload.flags.requires_custom_event = MODULE_CMN_MD_TRACKING_USE_CUSTOM_EVENT; + batch_tracking_md_info.tracking_payload.dest_port = me_ptr->miid; + batch_tracking_md_info.tracking_payload.src_port = me_ptr->miid; + + flags.word = 0; + flags.version = MODULE_CMN_MD_VERSION; + flags.tracking_mode = MODULE_CMN_MD_TRACKING_CONFIG_ENABLE_FOR_DROP_OR_CONSUME; + flags.tracking_policy = MODULE_CMN_MD_TRACKING_EVENT_POLICY_LAST; + /*if metadata splits into multiple path, DAM should be informed only when last event done*/ + + capi_result = me_ptr->metadata_handler.metadata_create_with_tracking(me_ptr->metadata_handler.context_ptr, + md_list_pptr, + sizeof(dam_batch_end_md_gen_t), + heap, + DAM_BATCH_END_MD_ID_MARKER, + flags, + &batch_tracking_md_info, + &new_md_ptr); + + if (capi_result) + { + DAM_MSG_ISLAND(me_ptr->miid, DBG_ERROR_PRIO, "Failed to create metadata entry END md with error 0x%x", capi_result); + return CAPI_EFAILED; + } + + new_md_ptr->metadata_id = DAM_BATCH_END_MD_ID_MARKER; + new_md_ptr->offset = output->buf_ptr[0].actual_data_len/me_ptr->operating_mf.bytes_per_sample; + md_payload_ptr = (dam_batch_end_md_gen_t *)&new_md_ptr->metadata_buf; + md_payload_ptr->output_port_idx = output_port_index; //output port index to handle Duty cycling + md_payload_ptr->param_id = PARAM_ID_AUDIO_DAM_HANDLE_BATCH_END_TRACKING_EVENT; //Param ID to set after tracking event + + /* END md is sample-associated only for EOS; buffer-associated for all other batch completions. */ + new_md_ptr->metadata_flag.buf_sample_association = is_eos_case ? MODULE_CMN_MD_SAMPLE_ASSOCIATED : MODULE_CMN_MD_BUFFER_ASSOCIATED; + + + DAM_MSG_ISLAND(me_ptr->miid, DBG_HIGH_PRIO, "DAM: Created and inserted tracking MD at output port index:%lu with offset: %lu", + output_port_index, new_md_ptr->offset); + + if(send_dfg_md) + { + //Inset DFG metadata to handle the framesize mismatch only for partial batches + + uint32_t dfg_payload_size = 0; // No metadata specific payload for dfg as of now + bool_t IN_BAND_PAYLOAD = FALSE; + module_cmn_md_t *md_ptr_dfg = NULL; + + capi_result = me_ptr->metadata_handler.metadata_create(me_ptr->metadata_handler.context_ptr, + md_list_pptr, + dfg_payload_size, + heap, + IN_BAND_PAYLOAD, + &md_ptr_dfg); + + if (capi_result) + { + DAM_MSG_ISLAND(me_ptr->miid, DBG_ERROR_PRIO, "Failed to create metadata entry for DFG with error 0x%x", capi_result); + return CAPI_EFAILED; + } + + md_ptr_dfg->metadata_flag.buf_sample_association = MODULE_CMN_MD_BUFFER_ASSOCIATED; + + // Update the metadata parameters + md_ptr_dfg->metadata_id = MODULE_CMN_MD_ID_DFG; + DAM_MSG_ISLAND(me_ptr->miid, DBG_HIGH_PRIO, "Generated DFG MD offset %d", new_md_ptr->offset ); + md_ptr_dfg->offset = new_md_ptr->offset; + + // Update flags to denote data flow state + out_stream_ptr->flags.end_of_frame = 1; + + } + + return capi_result; +} \ No newline at end of file diff --git a/fwk/spf/modules/audio_dam_buffer/lib/inc/audio_dam_driver.h b/fwk/spf/modules/audio_dam_buffer/lib/inc/audio_dam_driver.h index 73e6b759..5526fc49 100644 --- a/fwk/spf/modules/audio_dam_buffer/lib/inc/audio_dam_driver.h +++ b/fwk/spf/modules/audio_dam_buffer/lib/inc/audio_dam_driver.h @@ -324,7 +324,8 @@ ar_result_t audio_dam_stream_read(audio_dam_stream_reader_t *reader_handle, capi_buf_t * output_buf_arr, bool_t * output_buf_ts_is_valid, int64_t * output_buf_ts, - uint32_t * output_buf_len_in_us); + uint32_t * output_buf_len_in_us, + bool_t * is_batch_sent); /* * Adjusts the read pointer diff --git a/fwk/spf/modules/audio_dam_buffer/lib/src/audio_dam_driver_read_island.c b/fwk/spf/modules/audio_dam_buffer/lib/src/audio_dam_driver_read_island.c index 1f37f51e..5dbf36c5 100644 --- a/fwk/spf/modules/audio_dam_buffer/lib/src/audio_dam_driver_read_island.c +++ b/fwk/spf/modules/audio_dam_buffer/lib/src/audio_dam_driver_read_island.c @@ -186,7 +186,8 @@ static ar_result_t audio_dam_stream_batch_read(audio_dam_stream_reader_t *reader capi_buf_t * output_buf_arr, // in/out bool_t * output_buf_ts_is_valid, // out int64_t * output_buf_ts, // out - uint32_t * output_buf_len_in_us) // out + uint32_t * output_buf_len_in_us, // out + bool_t * is_batch_sent) { ar_result_t result = AR_EOK; uint32_t requested_batch_us = reader_handle->data_batching_us; @@ -235,6 +236,10 @@ static ar_result_t audio_dam_stream_batch_read(audio_dam_stream_reader_t *reader if (AR_EOK == result) { reader_handle->pending_batch_bytes -= output_buf_arr[0].actual_data_len; + if(reader_handle->pending_batch_bytes == 0) + { + *is_batch_sent = true; + } } return result; @@ -245,7 +250,8 @@ ar_result_t audio_dam_stream_read(audio_dam_stream_reader_t *reader_handle, capi_buf_t *output_buf_arr, // in/out bool_t *output_buf_ts_is_valid, // out int64_t *output_buf_ts, // out - uint32_t *output_buf_len_in_us) // out + uint32_t *output_buf_len_in_us, // out + bool_t *is_batch_sent) { ar_result_t result = AR_EOK; @@ -270,7 +276,8 @@ ar_result_t audio_dam_stream_read(audio_dam_stream_reader_t *reader_handle, output_buf_arr, output_buf_ts_is_valid, output_buf_ts, - output_buf_len_in_us); + output_buf_len_in_us, + is_batch_sent); } else { diff --git a/fwk/spf/modules/history_buffer/capi/src/capi_history_buffer.c b/fwk/spf/modules/history_buffer/capi/src/capi_history_buffer.c index 660875c9..db55d95d 100644 --- a/fwk/spf/modules/history_buffer/capi/src/capi_history_buffer.c +++ b/fwk/spf/modules/history_buffer/capi/src/capi_history_buffer.c @@ -343,25 +343,22 @@ static capi_err_t capi_history_buffer_process(capi_t *_pif, capi_stream_data_t * if (TRUE == me_ptr->is_trigger_detected) { /* Populate flow control param payload. */ - param_id_audio_dam_data_flow_ctrl_t flow_ctrl_cfg; - flow_ctrl_cfg.is_gate_open = TRUE; - flow_ctrl_cfg.read_offset_in_us = keyword_length_in_us; + param_id_audio_dam_data_flow_ctrl_v2_t flow_ctrl_cfg; + memset(&flow_ctrl_cfg, 0, sizeof(param_id_audio_dam_data_flow_ctrl_v2_t)); - flow_ctrl_cfg.num_best_channels = 0; // TODO: update best channels info if needed. This is optional. + flow_ctrl_cfg.gate_ctrl = AUDIO_DAM_GATE_OPEN; + flow_ctrl_cfg.read_offset_in_us = keyword_length_in_us; /* Send flow control param to DAM module through control port.*/ if (CAPI_EOK != - capi_history_buffer_send_flow_ctrl_msg_to_dam(me_ptr, &flow_ctrl_cfg)) + capi_history_buffer_send_flow_ctrl_v2_msg_to_dam(me_ptr, &flow_ctrl_cfg)) { AR_MSG(DBG_ERROR_PRIO, "CAPI History Buffer: Sending GATE OPEN to DAM Failed."); me_ptr->is_trigger_detected = FALSE; return CAPI_EFAILED; } - else - { - AR_MSG(DBG_MED_PRIO, "CAPI History Buffer: Sent gate open to audio DAM module"); - } + AR_MSG(DBG_MED_PRIO, "0x%lx: CAPI History Buffer: Sent Gate open with flow 0x%lx and batch_size 0x%lx to Cntrl Port", me_ptr->miid, flow_ctrl_cfg.gate_ctrl, keyword_length_in_us); /* If keyword is detected, module needs to send the detection event to the DSP clients. Detection module populates the current detection info into the event payload and raises the detection event. @@ -672,13 +669,13 @@ static capi_err_t capi_history_buffer_set_param(capi_t *_pif, "Received history buffer reset, sending gate close to DAM"); /* Populate dam gate control IMC param payload. */ - param_id_audio_dam_data_flow_ctrl_t ctrl_cfg; - memset(&ctrl_cfg, 0, sizeof(param_id_audio_dam_data_flow_ctrl_t)); + param_id_audio_dam_data_flow_ctrl_v2_t ctrl_cfg; + memset(&ctrl_cfg, 0, sizeof(param_id_audio_dam_data_flow_ctrl_v2_t)); // populate payload for gate close - ctrl_cfg.is_gate_open = FALSE; + ctrl_cfg.gate_ctrl = AUDIO_DAM_GATE_CLOSE; - result = capi_history_buffer_send_flow_ctrl_msg_to_dam(me_ptr, &ctrl_cfg); + result = capi_history_buffer_send_flow_ctrl_v2_msg_to_dam(me_ptr, &ctrl_cfg); // update flag to show, detection event is finished. me_ptr->is_event_inprogess = FALSE; @@ -743,18 +740,42 @@ static capi_err_t capi_history_buffer_set_param(capi_t *_pif, param_id_history_buffer_mode_t *cfg_ptr = (param_id_history_buffer_mode_t *)params_ptr->data_ptr; - me_ptr->mode.data_flow_mode = cfg_ptr->data_flow_mode; - - if (me_ptr->mode.data_flow_mode != HISTORY_BUFFER_ON_DEMAND) + switch(cfg_ptr->data_flow_mode) { - me_ptr->mode.data_flow_mode = HISTORY_BUFFER_ON_DEMAND; - me_ptr->mode.batch_size_ms = 0; - - DE_DBG(me_ptr->miid, DBG_HIGH_PRIO, "Unsupported mode %u, switched to ON_DEMAND", me_ptr->mode.data_flow_mode); + case HISTORY_BUFFER_BATCHING: + { + me_ptr->data_flow_mode = HISTORY_BUFFER_BATCHING; + + if(cfg_ptr->batch_size_ms) + { + me_ptr->hist_buffer_duration_msec = cfg_ptr->batch_size_ms; + me_ptr->max_dam_buffer_size_us = (me_ptr->hist_buffer_duration_msec * 1000); + } + + me_ptr->is_event_inprogess = TRUE; + + if (CAPI_FAILED(capi_history_buffer_resize_and_batch_gate_open_to_dam(me_ptr))) + { + AR_MSG(DBG_HIGH_PRIO, "Unable to send buffer resize and gate open to DAM"); + } + + break; + } + case HISTORY_BUFFER_ON_DEMAND: + { + me_ptr->data_flow_mode = HISTORY_BUFFER_ON_DEMAND; + break; + } + default: + { + me_ptr->data_flow_mode = HISTORY_BUFFER_ON_DEMAND; + DE_DBG(me_ptr->miid, DBG_HIGH_PRIO, "Unsupported mode %u, switched to ON_DEMAND", me_ptr->data_flow_mode); + break; + } } DE_DBG(me_ptr->miid, DBG_HIGH_PRIO, "Configured data flow mode is: %u and batch size in msec: %u", - me_ptr->mode.data_flow_mode, me_ptr->mode.batch_size_ms); + me_ptr->data_flow_mode, me_ptr->hist_buffer_duration_msec); break; } diff --git a/fwk/spf/modules/history_buffer/capi/src/capi_history_buffer_i.h b/fwk/spf/modules/history_buffer/capi/src/capi_history_buffer_i.h index dee0eb8c..15bcadbb 100644 --- a/fwk/spf/modules/history_buffer/capi/src/capi_history_buffer_i.h +++ b/fwk/spf/modules/history_buffer/capi/src/capi_history_buffer_i.h @@ -132,7 +132,7 @@ typedef struct capi_history_buffer_t history_buffer_ctrl_port_info_t ctrl_port_info[HISTORY_BUFFER_MAX_CONTROL_PORTS]; /* Control port info structure, currently applicable to one input port. */ - param_id_history_buffer_mode_t mode; + uint32_t data_flow_mode; } capi_history_buffer_t; diff --git a/fwk/spf/modules/history_buffer/capi/src/capi_history_buffer_imcl_utils.c b/fwk/spf/modules/history_buffer/capi/src/capi_history_buffer_imcl_utils.c index 360980f2..3113a137 100644 --- a/fwk/spf/modules/history_buffer/capi/src/capi_history_buffer_imcl_utils.c +++ b/fwk/spf/modules/history_buffer/capi/src/capi_history_buffer_imcl_utils.c @@ -283,9 +283,9 @@ capi_err_t capi_history_buffer_handle_intf_extn_ctrl_port_operation(capi_history Module can use capi_history_buffer_imcl_send_to_peer() if it needs to send any intents. */ /* Send history buffer resize command to the DAM Module, to adjust the size of circular buffer */ - if (CAPI_FAILED(capi_history_buffer_imcl_send_resize_to_dam(me_ptr))) + if (CAPI_FAILED(capi_history_buffer_resize_and_batch_gate_open_to_dam(me_ptr))) { - AR_MSG(DBG_HIGH_PRIO, "Unable to send history buffer resize to DAM"); + AR_MSG(DBG_HIGH_PRIO, "Unable to send buffer resize and gate open to DAM"); } } } @@ -821,76 +821,132 @@ capi_err_t capi_history_buffer_imcl_send_to_peer(capi_event_callback_info_t *eve } /* ========================================================================= - * FUNCTION : capi_history_buffer_send_flow_ctrl_msg_to_dam + * FUNCTION : capi_history_buffer_send_flow_ctrl_v2_msg_to_dam * * Refer capi_history_buffer_imcl_utils.h for function usage. * ========================================================================= */ -capi_err_t capi_history_buffer_send_flow_ctrl_msg_to_dam(capi_history_buffer_t * me_ptr, - param_id_audio_dam_data_flow_ctrl_t *param_ptr) +capi_err_t capi_history_buffer_send_flow_ctrl_v2_msg_to_dam(capi_history_buffer_t *me_ptr, param_id_audio_dam_data_flow_ctrl_v2_t *param_ptr) { capi_err_t result = CAPI_EOK; - /* Check the control ports that are connected and check supported Intent IDs. - Need to check if each control port supports the intent ID INTENT_ID_AUDIO_DAM_DETECTION_ENGINE_CTRL - indicating its a control port to DAM */ - for (uint32_t ctrl_port_idx = 0; ctrl_port_idx < HISTORY_BUFFER_MAX_CONTROL_PORTS; ctrl_port_idx++) + // define outgoing payload structure. + struct dam_flow_ctrl_v2_payload_t { - /* Send intents to only connected port and if control port supports intent id detection ctrl */ - if ((me_ptr->ctrl_port_info[ctrl_port_idx].state != CTRL_PORT_PEER_CONNECTED) && - capi_history_buffer_check_intent_id_support(me_ptr, ctrl_port_idx, INTENT_ID_AUDIO_DAM_DETECTION_ENGINE_CTRL)) - { - continue; - } + vw_imcl_header_t header; + param_id_audio_dam_data_flow_ctrl_v2_t cfg; + }; - AR_MSG(DBG_HIGH_PRIO, - "Sending IMC message through control port id 0x%lx", - me_ptr->ctrl_port_info[ctrl_port_idx].port_id); + // get the port index, can use for loop if more than one. + uint32_t ctrl_port_idx = 0; - // get control port id for the port index. - uint32_t control_port_id = me_ptr->ctrl_port_info[ctrl_port_idx].port_id; + /* Step A - Get buffers*/ + // Request buffers for this particular control port id. + capi_buf_t buffer; - /* Step A - Get recurring buffers*/ - // Request recurring buffers for this particular control port id. - capi_buf_t buffer; - capi_history_buffer_imcl_get_recurring_buf(&me_ptr->cb_info, control_port_id, &buffer); - if (NULL == buffer.data_ptr || buffer.max_data_len < sizeof(vw_imcl_header_t)) - { - DE_DBG(me_ptr->miid, DBG_ERROR_PRIO, "Received NULL intent buffer or invalid size %lu", buffer.max_data_len); - result = CAPI_EFAILED; - } - else /* Step B- Populate and send the buffer */ - { - // create the payload with outgoing param ids. - struct dam_flow_ctrl_payload_t - { - vw_imcl_header_t header; - param_id_audio_dam_data_flow_ctrl_t cfg; - }; + result = capi_history_buffer_imcl_get_one_time_buf( &me_ptr->cb_info, + me_ptr->ctrl_port_info[ctrl_port_idx].port_id, + sizeof(struct dam_flow_ctrl_v2_payload_t), + &buffer); + + if (CAPI_EOK != result) + { + AR_MSG(DBG_ERROR_PRIO, + "0x%lx: CAPI_HISTORY_BUFFER_IMCL: capi_cmn_imcl_get_one_time_buf() failed with result : %lu", + me_ptr->miid, + result); + return CAPI_EFAILED; + } - struct dam_flow_ctrl_payload_t *temp = (struct dam_flow_ctrl_payload_t *)buffer.data_ptr; + /* Step B- Populate and send the buffer */ + struct dam_flow_ctrl_v2_payload_t *temp = (struct dam_flow_ctrl_v2_payload_t *)buffer.data_ptr; - // populate param payload - uint32_t param_len = - sizeof(param_id_audio_dam_data_flow_ctrl_t) + (param_ptr->num_best_channels * sizeof(uint32_t)); + buffer.actual_data_len = sizeof(struct dam_flow_ctrl_v2_payload_t); - temp->header.opcode = PARAM_ID_AUDIO_DAM_DATA_FLOW_CTRL; - temp->header.actual_data_len = param_len; + temp->header.opcode = PARAM_ID_AUDIO_DAM_DATA_FLOW_CTRL_V2; + temp->header.actual_data_len = sizeof(param_id_audio_dam_data_flow_ctrl_v2_t); - // copy param struct param_id_audio_dam_data_flow_ctrl_t payload to intent buffer - memscpy(&temp->cfg, buffer.max_data_len - sizeof(vw_imcl_header_t), param_ptr, param_len); + memset(&temp->cfg, 0, sizeof(param_id_audio_dam_data_flow_ctrl_v2_t)); - buffer.actual_data_len = param_len + sizeof(vw_imcl_header_t); + temp->cfg.gate_ctrl = (audio_dam_gate_ctrl_op_t) param_ptr->gate_ctrl; + temp->cfg.read_offset_in_us = param_ptr->read_offset_in_us; - /*To send data over to the IMCL peer*/ - imcl_outgoing_data_flag_t flags; - flags.should_send = TRUE; // FALSE == buffer is returned to fwk and not sent to peer module. - flags.is_trigger = TRUE; // FALSE == polling, refer intf extension for more details - result = capi_history_buffer_imcl_send_to_peer(&me_ptr->cb_info, &buffer, control_port_id, flags); - } + AR_MSG(DBG_LOW_PRIO, "0x%lx: CAPI_HISTORY_BUFFER: Sending data flow msg v2 %lu to DAM", me_ptr->miid, temp->cfg.gate_ctrl); + + /*To send data over to the IMCL peer*/ + imcl_outgoing_data_flag_t flags; + flags.should_send = TRUE; // FALSE == buffer is returned to fwk and not sent to peer module. + flags.is_trigger = TRUE; // FALSE == polling, refer intf extension for more details + + return capi_history_buffer_imcl_send_to_peer(&me_ptr->cb_info, &buffer, me_ptr->ctrl_port_info[ctrl_port_idx].port_id, flags); +} + +/* ========================================================================= + * FUNCTION : capi_history_buffer_send_allow_dcm_island_entry_to_dam + * + * Refer capi_history_buffer_imcl_utils.h for function usage. + * ========================================================================= */ +capi_err_t capi_history_buffer_send_allow_dcm_island_entry_to_dam(capi_history_buffer_t *me_ptr) +{ + /* Only one control port supported (HISTORY_BUFFER_MAX_CONTROL_PORTS = 1) */ + uint32_t ctrl_port_idx = 0; + + // Safety check: ensure ctrl port is connected before sending. + if (CTRL_PORT_PEER_CONNECTED != me_ptr->ctrl_port_info[ctrl_port_idx].state) + { + AR_MSG(DBG_HIGH_PRIO, + "0x%lx: CAPI_HISTORY_BUFFER: ctrl port not connected, skipping allow_dcm_island_entry", + me_ptr->miid); + return CAPI_EOK; } - return result; + + // Populate the payload + param_id_audio_dam_allow_dcm_island_entry_t dam_process_done; + dam_process_done.process_done = TRUE; + + // Populate the IMCL header. + vw_imcl_header_t header; + header.opcode = PARAM_ID_AUDIO_DAM_ALLOW_DCM_ISLAND_ENTRY; + header.actual_data_len = sizeof(param_id_audio_dam_allow_dcm_island_entry_t); + + // Get a one-time buffer from the framework + capi_buf_t buffer; + capi_err_t result = capi_history_buffer_imcl_get_one_time_buf(&me_ptr->cb_info, + me_ptr->ctrl_port_info[ctrl_port_idx].port_id, + sizeof(header) + header.actual_data_len, + &buffer); + if (CAPI_EOK != result || NULL == buffer.data_ptr) + { + AR_MSG(DBG_ERROR_PRIO, + "0x%lx: CAPI_HISTORY_BUFFER: received NULL payload ptr while sending allow_dcm_island_entry to DAM", + me_ptr->miid); + return CAPI_EFAILED; + } + + // Copy the vw_imcl_header + uint32_t bytes_copied = memscpy(buffer.data_ptr, buffer.max_data_len, &header, sizeof(header)); + bytes_copied += memscpy(buffer.data_ptr + bytes_copied, + buffer.max_data_len - bytes_copied, + &dam_process_done, + header.actual_data_len); + + buffer.actual_data_len = bytes_copied; + + AR_MSG(DBG_HIGH_PRIO, + "0x%lx: CAPI_HISTORY_BUFFER: Sending ALLOW_DCM_ISLAND_ENTRY to DAM for first batch island entry", + me_ptr->miid); + + // To send data over to the IMCL peer + imcl_outgoing_data_flag_t flags; + flags.should_send = TRUE; + flags.is_trigger = TRUE; + + return capi_history_buffer_imcl_send_to_peer(&me_ptr->cb_info, + &buffer, + me_ptr->ctrl_port_info[ctrl_port_idx].port_id, + flags); } + capi_err_t capi_history_buffer_imcl_send_resize_to_dam(capi_history_buffer_t *me_ptr) { capi_err_t result = CAPI_EOK; @@ -959,4 +1015,50 @@ capi_err_t capi_history_buffer_imcl_send_resize_to_dam(capi_history_buffer_t *me } } return result; -} \ No newline at end of file +} + +capi_err_t capi_history_buffer_resize_and_batch_gate_open_to_dam(capi_history_buffer_t *me_ptr) +{ + capi_err_t result = CAPI_EOK; + /*Send the RESIZE to the DAM Module*/ + result = capi_history_buffer_imcl_send_resize_to_dam(me_ptr); + + if (CAPI_EOK != result) + { + AR_MSG(DBG_MED_PRIO, "CAPI History Buffer: Couldn't send resize to DAM "); + return result; + } + + if(HISTORY_BUFFER_BATCHING == me_ptr->data_flow_mode) + { + + /* Populate dam gate control IMC param payload. */ + param_id_audio_dam_data_flow_ctrl_v2_t flow_ctrl_cfg; + memset(&flow_ctrl_cfg, 0, sizeof(param_id_audio_dam_data_flow_ctrl_v2_t)); + + flow_ctrl_cfg.gate_ctrl = AUDIO_DAM_BATCH_STREAM_WITH_ISLAND_DUTY_CYCLING_MD_TRACKING_EVENT; + flow_ctrl_cfg.read_offset_in_us = me_ptr->max_dam_buffer_size_us; + + result = capi_history_buffer_send_flow_ctrl_v2_msg_to_dam(me_ptr, &flow_ctrl_cfg); + + if (CAPI_EOK != result) + { + AR_MSG(DBG_MED_PRIO, "0x%lx: CAPI History Buffer: Couldn't send Gate open with flow 0x%lx and batch_size 0x%lx to Cntrl Port", + me_ptr->miid, flow_ctrl_cfg.gate_ctrl, me_ptr->max_dam_buffer_size_us); + return result; + } + + result = capi_history_buffer_send_allow_dcm_island_entry_to_dam(me_ptr); + if (CAPI_EOK != result) + { + AR_MSG(DBG_MED_PRIO, + "0x%lx: CAPI History Buffer: Couldn't send allow_dcm_island_entry to DAM for first batch", + me_ptr->miid); + result = CAPI_EOK; /* Non-fatal: tracking mechanism handles subsequent batches */ + } + } + + AR_MSG(DBG_MED_PRIO, "CAPI History Buffer: DAM cfg sent successfully!"); + + return result; +} diff --git a/fwk/spf/modules/history_buffer/capi/src/capi_history_buffer_imcl_utils.h b/fwk/spf/modules/history_buffer/capi/src/capi_history_buffer_imcl_utils.h index 0c30083e..ffb7f673 100644 --- a/fwk/spf/modules/history_buffer/capi/src/capi_history_buffer_imcl_utils.h +++ b/fwk/spf/modules/history_buffer/capi/src/capi_history_buffer_imcl_utils.h @@ -217,21 +217,20 @@ capi_err_t capi_history_buffer_handle_intf_extn_ctrl_port_operation(capi_history capi_err_t capi_history_buffer_handle_incoming_imc_message(capi_history_buffer_t *me_ptr, capi_buf_t *params_ptr); /* ========================================================================= - * FUNCTION : capi_history_buffer_send_flow_ctrl_msg_to_dam + * FUNCTION : capi_history_buffer_send_flow_ctrl_v2_msg_to_dam * DESCRIPTION: Sends flow control IMC message to DAM. - * is_gate_open = TRUE : sends gate open, DAM will start draining the - * buffered data + * is_gate_open = TRUE : sends gate open with flow intent, DAM will start + * draining the buffered data * is_gate_open = FALSE: sends gate close, DAM will stop draining data and - * goes back to buffering mode. + * goes back to buffering mode. * * Sending a intent to the peer module involves two steps, - * STEP-A) Get recurring buffer from framework, for this module must have registered for - * recurring buffers. If not module can request for onetime buffers. + * STEP-A) request one time buffer from framework. * STEP-B) Populate the payload of intent buffer and raise an event to send IMC message * to peer module. * ========================================================================= */ -capi_err_t capi_history_buffer_send_flow_ctrl_msg_to_dam(capi_history_buffer_t * me_ptr, - param_id_audio_dam_data_flow_ctrl_t *param_ptr); +capi_err_t capi_history_buffer_send_flow_ctrl_v2_msg_to_dam(capi_history_buffer_t * me_ptr, + param_id_audio_dam_data_flow_ctrl_v2_t *param_ptr); /* ========================================================================= * FUNCTION : capi_history_buffer_imcl_send_resize_to_dam @@ -240,6 +239,21 @@ capi_err_t capi_history_buffer_send_flow_ctrl_msg_to_dam(capi_history_buffer_t * * ========================================================================= */ capi_err_t capi_history_buffer_imcl_send_resize_to_dam(capi_history_buffer_t *me_ptr); +/* ========================================================================= + * FUNCTION : capi_history_buffer_resize_and_batch_gate_open_to_dam + * + * Utility to send resize and batch gate open command to audio dam module + * ========================================================================= */ +capi_err_t capi_history_buffer_resize_and_batch_gate_open_to_dam(capi_history_buffer_t *me_ptr); + +/* ========================================================================= + * FUNCTION : capi_history_buffer_send_allow_dcm_island_entry_to_dam + * + * Sends PARAM_ID_AUDIO_DAM_ALLOW_DCM_ISLAND_ENTRY to DAM via IMCL. + * Called at ctrl port connect (after gate open) to trigger island entry for the first batch. + * ========================================================================= */ +capi_err_t capi_history_buffer_send_allow_dcm_island_entry_to_dam(capi_history_buffer_t *me_ptr); + /* ========================================================================= * FUNCTION : capi_history_buffer_validate_intent_id * diff --git a/fwk/spf/modules/priority_sync/build/Android.mk b/fwk/spf/modules/priority_sync/build/Android.mk index 36d4e6de..1e3bf713 100644 --- a/fwk/spf/modules/priority_sync/build/Android.mk +++ b/fwk/spf/modules/priority_sync/build/Android.mk @@ -11,7 +11,7 @@ include $(BUILD_HEADER_LIBRARY) include $(CLEAR_VARS) -LOCAL_MODULE := capi_priority_sync +LOCAL_MODULE := lib_priority_sync LOCAL_MODULE_TAGS := optional LOCAL_VENDOR_MODULE := true LOCAL_C_INCLUDES := \ @@ -42,5 +42,16 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_HEADER_LIBRARIES := libposal_headers libspf_api libspf_interfaces_headers libspf_utils_headers libapm_headers libamdb_headers LOCAL_STATIC_LIBRARIES := libposal libspf_interfaces libapm libamdb -include $(BUILD_STATIC_LIBRARY) +LOCAL_SPF_MODULE_KCONFIG := CONFIG_PRIORITY_SYNC +LOCAL_SPF_MODULE_NAME := $(LOCAL_MODULE) +LOCAL_SPF_MODULE_MAJOR_VER := 1 +LOCAL_SPF_MODULE_MINOR_VER := 0 +LOCAL_SPF_MODULE_AMDB_ITYPE := "capi" +LOCAL_SPF_MODULE_AMDB_MTYPE := "generic" +LOCAL_SPF_MODULE_AMDB_MID := "0x07001028" +LOCAL_SPF_MODULE_AMDB_TAG := "capi_priority_sync" +LOCAL_SPF_MODULE_AMDB_MOD_NAME := "MODULE_ID_PRIORITY_SYNC" +LOCAL_SPF_MODULE_H2XML_HEADERS := "$(LOCAL_PATH)/api/priority_sync_api.h" + +include $(BUILD_ARE_MODULES) diff --git a/fwk/spf/modules/sh_mem_pull_push_mode/api/sh_mem_pull_push_mode_api.h b/fwk/spf/modules/sh_mem_pull_push_mode/api/sh_mem_pull_push_mode_api.h index 846f9d9f..bda9582f 100644 --- a/fwk/spf/modules/sh_mem_pull_push_mode/api/sh_mem_pull_push_mode_api.h +++ b/fwk/spf/modules/sh_mem_pull_push_mode/api/sh_mem_pull_push_mode_api.h @@ -427,6 +427,104 @@ struct sh_mem_pull_push_mode_cfg_t ; typedef struct sh_mem_pull_push_mode_cfg_t sh_mem_pull_push_mode_cfg_t; +/*============================================================================== + Param ID +==============================================================================*/ + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Identifier of the parameter that configures header information for Push mode. + This parameter enables timestamp information to be written alongside PCM data + in the shared circular buffer. + + @msgpayload + sh_mem_push_mode_header_cfg_t + */ +#define PARAM_ID_SH_MEM_PUSH_MODE_HEADER_CFG 0x08001BDF +/** @h2xmlp_parameter {"PARAM_ID_SH_MEM_PUSH_MODE_HEADER_CFG", PARAM_ID_SH_MEM_PUSH_MODE_HEADER_CFG} + @h2xmlp_description {Configures the header info.\n} + @h2xmlp_toolPolicy {Calibration} */ + +/*============================================================================== + Param structure definitions +==============================================================================*/ +#include "spf_begin_pack.h" +struct sh_mem_push_mode_header_cfg_t +{ + uint32_t header_type; + /**< Bit field to enable/disable additional information to be sent along with + the audio data in the buffer. + + Bit 0: Include UTC timestamp (0=disabled, 1=enabled) + Bits 1-31: Reserved for future use*/ + + /*#< @h2xmle_description {Bit field to enable/disable additional header information. + Bit 0: UTC timestamp + Bits 1-31: Reserved} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +typedef struct sh_mem_push_mode_header_cfg_t sh_mem_push_mode_header_cfg_t; + +/*============================================================================== + Header Structure Definitions +==============================================================================*/ + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Sync word for header validation. Value is ASCII "SPFM" (0x5350464D). */ +#define SH_MEM_PUSH_MODE_HEADER_SYNC_WORD 0x5350464D + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Batch header structure that appears at the start of each batch in shared memory. + Contains sync word for validation. */ +struct sh_mem_push_mode_batch_header_t +{ + uint32_t sync_word; + /**< Sync word for validation. Must be 0x5350464D ("SPFM"). */ +}; + +typedef struct sh_mem_push_mode_batch_header_t sh_mem_push_mode_batch_header_t; + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Parameter header type information structure (PARAM_ID + SIZE). + This header precedes each header type data/payload in the batch header. */ +struct sh_mem_push_mode_param_header_t +{ + uint32_t param_id; + /**< Parameter ID identifying the type of data that follows. */ + + uint32_t actual_size; + /**< Actual size of the payload in bytes */ + + uint32_t padding_size; + /**< Size of the padded bytes in param payload, to make next header SYNC_WORD 4-byte aligned. */ +}; + +typedef struct sh_mem_push_mode_param_header_t sh_mem_push_mode_param_header_t; + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Header Parameter ID for UTC timestamp. */ +#define PARAM_ID_HEADER_TYPE_UTC_TIMESTAMP 0x08001BE0 + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Timestamp parameter payload structure. + Can be used for both Propagated timestamp and UTC timestamp parameters. */ +struct sh_mem_push_mode_timestamp_payload_t +{ + uint32_t timestamp_us_lsw; + /**< Lower 32 bits of the 64-bit timestamp, in microseconds*/ + + uint32_t timestamp_us_msw; + /**< Upper 32 bits of the 64-bit timestamp, in microseconds*/ +}; + +typedef struct sh_mem_push_mode_timestamp_payload_t sh_mem_push_mode_timestamp_payload_t; + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Header Parameter ID for PCM data. */ +#define PARAM_ID_HEADER_TYPE_PCM_DATA 0x08001BE1 /** @ingroup ar_spf_mod_ep_shmempp_mods Identifier for the Shared Memory Pull mode module, which writes data to the @@ -531,6 +629,8 @@ typedef struct sh_mem_pull_push_mode_cfg_t sh_mem_pull_push_mode_cfg_t; @h2xmlm_InsertParameter @h2xml_Select {"event_cfg_sh_mem_pull_push_mode_watermark_t"} @h2xmlm_InsertParameter + @h2xml_Select {"sh_mem_push_mode_header_cfg_t"} + @h2xmlm_InsertParameter @} <-- End of the Module --> */ diff --git a/fwk/spf/modules/sh_mem_pull_push_mode/src/capi_sh_mem_pull_push_mode.c b/fwk/spf/modules/sh_mem_pull_push_mode/src/capi_sh_mem_pull_push_mode.c index 29343a43..ef56949b 100644 --- a/fwk/spf/modules/sh_mem_pull_push_mode/src/capi_sh_mem_pull_push_mode.c +++ b/fwk/spf/modules/sh_mem_pull_push_mode/src/capi_sh_mem_pull_push_mode.c @@ -58,7 +58,8 @@ static void capi_pm_check_n_enable_module_buffer_access_extension(capi_pm_t *me_ // note that push/pull module only process CAPI_INTERLEAVED format, hence just checking for validaty is sufficient bool_t need_to_enable_extension = (TRUE == pull_push_check_media_fmt_validity(&me_ptr->pull_push_mode_info)) && - (CAPI_INTERLEAVED == me_ptr->pull_push_mode_info.media_fmt.data_interleaving); + (CAPI_INTERLEAVED == me_ptr->pull_push_mode_info.media_fmt.data_interleaving) && + (FALSE == me_ptr->is_header_enabled); // check if circular buffer size is set and mulitple of container framelength if (me_ptr->pull_push_mode_info.shared_circ_buf_size && me_ptr->frame_dur_us) @@ -306,7 +307,6 @@ capi_err_t capi_push_mode_init(capi_t *_pif, capi_proplist_t *init_set_propertie me_ptr->vtbl.vtbl_ptr = &push_mode_vtbl; me_ptr->pull_push_mode_info.mode = PUSH_MODE; - memset(&me_ptr->pull_push_mode_info.media_fmt, 0, sizeof(pm_media_fmt_t)); capi_result = capi_pm_process_init(me_ptr, init_set_properties); @@ -323,6 +323,21 @@ static capi_err_t capi_pm_end(capi_t *_pif) } capi_pm_t *me_ptr = (capi_pm_t *)_pif; + // Free UTC time module if allocated + if (NULL != me_ptr->ts_data.utc_time_module_ptr) + { + posal_memory_free(me_ptr->ts_data.utc_time_module_ptr); + me_ptr->ts_data.utc_time_module_ptr = NULL; + } + + // Free header buffer if allocated (PUSH mode specific cleanup) + if (NULL != me_ptr->header_buffer_ptr) + { + posal_memory_free(me_ptr->header_buffer_ptr); + me_ptr->header_buffer_ptr = NULL; + me_ptr->header_buffer_size = 0; + } + pull_push_mode_deinit(&(me_ptr->pull_push_mode_info)); return capi_result; @@ -391,6 +406,116 @@ static capi_err_t capi_pm_set_param(capi_t *_pif, } break; } + case PARAM_ID_SH_MEM_PUSH_MODE_HEADER_CFG: + { + // Validate this parameter is only for PUSH mode + if (PUSH_MODE != me_ptr->pull_push_mode_info.mode) + { + PULL_PUSH_MSG(miid, DBG_ERROR_PRIO, + "param id 0x%lX only supported for PUSH mode", param_id); + CAPI_SET_ERROR(capi_result, CAPI_EUNSUPPORTED); + break; + } + + // Validate payload size + if (params_ptr->actual_data_len < sizeof(sh_mem_push_mode_header_cfg_t)) + { + PULL_PUSH_MSG(miid, DBG_ERROR_PRIO, + "param id 0x%lX: Insufficient payload size %d", + param_id, + params_ptr->actual_data_len); + CAPI_SET_ERROR(capi_result, CAPI_ENEEDMORE); + break; + } + + // Get the configuration payload + sh_mem_push_mode_header_cfg_t *cfg_ptr = + (sh_mem_push_mode_header_cfg_t *)params_ptr->data_ptr; + + // Validate reserved bits + uint32_t unreserved_bits = cfg_ptr->header_type & ~(HEADER_TYPE_RESERVED_BITS); + if (unreserved_bits == 0) + { + PULL_PUSH_MSG(miid, DBG_ERROR_PRIO, + "No Supported header type found, header type received is 0x%x", + cfg_ptr->header_type); + break; + } + + // Calculate required header buffer size based on enabled header types + uint32_t required_size = sizeof(sh_mem_push_mode_batch_header_t) + sizeof(sh_mem_push_mode_param_header_t); // Sync word + PCM header + + if (cfg_ptr->header_type & HEADER_TYPE_UTC_TIMESTAMP) + { + required_size += sizeof(sh_mem_push_mode_param_header_t); // Timestamp param header + required_size += sizeof(sh_mem_push_mode_timestamp_payload_t); // Timestamp payload + + if(me_ptr->ts_data.utc_time_module_ptr) + { + posal_reset_utc_time_module((void *)me_ptr->ts_data.utc_time_module_ptr); + } + else + { + uint32_t posal_timer_size = posal_get_time_module_size(); + if(posal_timer_size) + { + uint8_t* ptr = (uint8_t *)posal_memory_malloc(posal_timer_size, (POSAL_HEAP_ID)me_ptr->heap_mem.heap_id); + if(NULL == ptr) + { + PULL_PUSH_MSG(miid, DBG_HIGH_PRIO, "Failed to allocated time module of size %lu", posal_timer_size); + return CAPI_EFAILED; + } + me_ptr->ts_data.utc_time_module_ptr = ptr; + posal_reset_utc_time_module((void *)me_ptr->ts_data.utc_time_module_ptr); + } + } + } + + // Free existing buffer if already allocated and size not same + if (NULL != me_ptr->header_buffer_ptr && required_size != me_ptr->header_buffer_size) + { + posal_memory_free(me_ptr->header_buffer_ptr); + me_ptr->header_buffer_ptr = NULL; + me_ptr->header_buffer_size = 0; + + PULL_PUSH_MSG(miid, DBG_HIGH_PRIO, "Freed existing header buffer"); + + } + + if(NULL == me_ptr->header_buffer_ptr) + { + // Allocate new header buffer + me_ptr->header_buffer_ptr = + (uint8_t *)posal_memory_malloc(required_size, me_ptr->heap_mem.heap_id); + + if (NULL == me_ptr->header_buffer_ptr) + { + PULL_PUSH_MSG(miid, DBG_ERROR_PRIO, + "Failed to allocate header buffer of size %d", required_size); + CAPI_SET_ERROR(capi_result, CAPI_ENOMEMORY); + break; + } + + me_ptr->header_buffer_size = required_size; + } + + // Initialize buffer to zero + memset(me_ptr->header_buffer_ptr, 0, required_size); + + // Store the header type flags + me_ptr->header_type_flags = cfg_ptr->header_type; + // Update the module state + me_ptr->is_header_enabled = TRUE; + me_ptr->is_update_header = TRUE; + + PULL_PUSH_MSG(miid, DBG_MED_PRIO, + "Header buffer allocated: size=%d bytes, type=0x%x, enabled=%d", + required_size, + me_ptr->header_type_flags, + me_ptr->is_header_enabled); + + break; + } case PARAM_ID_MEDIA_FORMAT: { if (params_ptr->actual_data_len < sizeof(media_format_t)) @@ -597,6 +722,55 @@ static capi_err_t capi_pm_set_param(capi_t *_pif, capi_pm_check_n_enable_module_buffer_access_extension(me_ptr); break; } + case INTF_EXTN_PARAM_ID_CNTR_DUTY_CYCLING_ENABLED: + { + if (params_ptr->actual_data_len < sizeof(intf_extn_param_id_cntr_duty_cycling_enabled_t)) + { + AR_MSG(DBG_ERROR_PRIO, + "Invalid payload size for CNTR_DUTY_CYCLING_ENABLED %d", + params_ptr->actual_data_len); + return CAPI_ENEEDMORE; + } + intf_extn_param_id_cntr_duty_cycling_enabled_t *payload_ptr = + (intf_extn_param_id_cntr_duty_cycling_enabled_t *)params_ptr->data_ptr; + + me_ptr->is_cntr_duty_cycle_enabled = payload_ptr->is_cntr_duty_cycling; + + bool_t allow_duty_cycling = TRUE; + intf_extn_event_id_allow_duty_cycling_v2_t event_payload; + PULL_PUSH_MSG(miid, DBG_HIGH_PRIO, "Raise allow_duty_cycling: %d", allow_duty_cycling); + + event_payload.allow_duty_cycling = allow_duty_cycling; + + /* Create event */ + capi_event_data_to_dsp_service_t to_send; + to_send.param_id = INTF_EXTN_EVENT_ID_ALLOW_DUTY_CYCLING; + to_send.payload.actual_data_len = sizeof(intf_extn_event_id_allow_duty_cycling_v2_t); + to_send.payload.max_data_len = sizeof(intf_extn_event_id_allow_duty_cycling_v2_t); + to_send.payload.data_ptr = (int8_t *)&event_payload; + + /* Create event info */ + capi_event_info_t event_info; + event_info.port_info.is_input_port = FALSE; + event_info.port_info.is_valid = FALSE; + event_info.payload.actual_data_len = sizeof(to_send); + event_info.payload.max_data_len = sizeof(to_send); + event_info.payload.data_ptr = (int8_t *)&to_send; + + capi_result = me_ptr->cb_info.event_cb(me_ptr->cb_info.event_context, CAPI_EVENT_DATA_TO_DSP_SERVICE, &event_info); + + if (CAPI_EOK != capi_result) + { + PULL_PUSH_MSG(miid, DBG_ERROR_PRIO, "Failed to raise INTF_EXTN_EVENT_ID_ALLOW_DUTY_CYCLING event"); + } + else + { + PULL_PUSH_MSG(miid, DBG_HIGH_PRIO, "Raised INTF_EXTN_EVENT_ID_ALLOW_DUTY_CYCLING event allow_duty_cycling:%d", event_payload.allow_duty_cycling); + } + + PULL_PUSH_MSG(miid, DBG_LOW_PRIO, "is_cntr_duty_cycle_enabled configured to %lu", me_ptr->is_cntr_duty_cycle_enabled); + break; + } default: { CAPI_SET_ERROR(capi_result, CAPI_EUNSUPPORTED); @@ -826,15 +1000,33 @@ static capi_err_t capi_pm_set_properties(capi_t *_pif, capi_proplist_t *props_pt case CAPI_ALGORITHMIC_RESET: { PULL_PUSH_MSG(pm_info_ptr->miid, DBG_HIGH_PRIO, "Set property received for algorithmic reset"); - + if ((PUSH_MODE == me_ptr->pull_push_mode_info.mode) && me_ptr->is_header_enabled && !me_ptr->is_update_header && (me_ptr->pcm_bytes_written > 0)) + { + PULL_PUSH_MSG(pm_info_ptr->miid, DBG_HIGH_PRIO, + "Algo reset: finalizing in-progress batch " + "(pcm_bytes_written=%lu) before reset", + me_ptr->pcm_bytes_written); + push_mode_end_header_batch(me_ptr, posal_timer_get_time()); + } if (NULL != me_ptr->pull_push_mode_info.shared_pos_buf_ptr) { - PULL_PUSH_MSG(pm_info_ptr->miid, DBG_HIGH_PRIO, "Resetting shared position structure"); - memset(me_ptr->pull_push_mode_info.shared_pos_buf_ptr, - 0, - sizeof(sh_mem_pull_push_mode_position_buffer_t)); - - me_ptr->pull_push_mode_info.next_read_index = 0; + if (PUSH_MODE == me_ptr->pull_push_mode_info.mode && me_ptr->is_header_enabled) + { + /* Defer position buffer reset to the next process call so HLOS can + * still read the last finalized batch. Resetting here would move + * pos_buf->index back to 0, making the just-written batch unreadable. */ + me_ptr->is_pending_pos_buf_reset = TRUE; + PULL_PUSH_MSG(pm_info_ptr->miid, DBG_HIGH_PRIO, + "Algo reset: deferring position buffer reset to next process call"); + } + else + { + PULL_PUSH_MSG(pm_info_ptr->miid, DBG_HIGH_PRIO, "Resetting shared position structure"); + memset(me_ptr->pull_push_mode_info.shared_pos_buf_ptr, + 0, + sizeof(sh_mem_pull_push_mode_position_buffer_t)); + me_ptr->pull_push_mode_info.next_read_index = 0; + } } break; } @@ -1111,7 +1303,7 @@ static capi_err_t capi_pm_process_get_properties(capi_pm_t *me_ptr, capi_proplis { /** Can pass the list of IE list supported by this module to * be updated in the common utlitlity */ - uint32_t supported_extension_list[] = { INTF_EXTN_IMCL, INTF_EXTN_MODULE_BUFFER_ACCESS }; + uint32_t supported_extension_list[] = { INTF_EXTN_IMCL, INTF_EXTN_MODULE_BUFFER_ACCESS, INTF_EXTN_DUTY_CYCLING_ISLAND_MODE }; uint32_t num_supported_extns = sizeof(supported_extension_list) / sizeof(uint32_t); capi_result = capi_cmn_check_and_update_intf_extn_status(num_supported_extns, supported_extension_list, diff --git a/fwk/spf/modules/sh_mem_pull_push_mode/src/pull_push_mode.c b/fwk/spf/modules/sh_mem_pull_push_mode/src/pull_push_mode.c index 0edc1108..d791b298 100644 --- a/fwk/spf/modules/sh_mem_pull_push_mode/src/pull_push_mode.c +++ b/fwk/spf/modules/sh_mem_pull_push_mode/src/pull_push_mode.c @@ -28,6 +28,7 @@ INCLUDE FILES FOR MODULE #else #include "test_util.h" #endif +#include "dam_batch_metadata_api.h" // Important: Disabling code to bump up thread priority whenever position buffer gets updated. // Initially priority change was introduced for the thread to be able to update position buffer @@ -564,6 +565,248 @@ capi_err_t pull_mode_read_input(capi_t *_pif, capi_stream_data_t *input[], capi_ return result; } +static capi_err_t push_mode_write_batch_header(capi_pm_t *me_ptr, + uint32_t *write_index_ptr, + uint64_t timestamp) +{ + capi_err_t result = CAPI_EOK; + + // Validate input parameters + if (NULL == me_ptr || NULL == write_index_ptr) + { + PULL_PUSH_MSG(MIID_UNKNOWN, DBG_ERROR_PRIO, "Invalid parameters for header write"); + return CAPI_EBADPARAM; + } + + uint32_t miid = me_ptr->pull_push_mode_info.miid; + + // Validate header buffer is allocated + if (NULL == me_ptr->header_buffer_ptr || 0 == me_ptr->header_buffer_size) + { + PULL_PUSH_MSG(miid, DBG_ERROR_PRIO, "Header buffer not allocated"); + return CAPI_EFAILED; + } + + // Use pre-allocated buffer + uint8_t *local_header_buf_ptr = me_ptr->header_buffer_ptr; + uint32_t max_size = me_ptr->header_buffer_size; + uint32_t local_offset = 0; + + // Clear buffer + memset(local_header_buf_ptr, 0, max_size); + + // Save the starting write index to calculate DDR addresses later + uint32_t header_start_index = *write_index_ptr; + + // 1. Write Batch Header - Sync Word + sh_mem_push_mode_batch_header_t *batch_hdr_ptr = + (sh_mem_push_mode_batch_header_t *)&local_header_buf_ptr[local_offset]; + batch_hdr_ptr->sync_word = SH_MEM_PUSH_MODE_HEADER_SYNC_WORD; + local_offset += sizeof(sh_mem_push_mode_batch_header_t); + + PULL_PUSH_MSG(miid, DBG_LOW_PRIO, + "Batch header: sync_word=0x%x", batch_hdr_ptr->sync_word); + + // 2. Write UTC Timestamp Parameter (if enabled) + if (me_ptr->header_type_flags & HEADER_TYPE_UTC_TIMESTAMP) + { + // Write parameter header + sh_mem_push_mode_param_header_t *ts_param_hdr_ptr = + (sh_mem_push_mode_param_header_t *)&local_header_buf_ptr[local_offset]; + ts_param_hdr_ptr->param_id = PARAM_ID_HEADER_TYPE_UTC_TIMESTAMP; + ts_param_hdr_ptr->actual_size = sizeof(sh_mem_push_mode_timestamp_payload_t); + ts_param_hdr_ptr->padding_size = 0; // No padding needed for timestamp + local_offset += sizeof(sh_mem_push_mode_param_header_t); + + // Write timestamp payload + sh_mem_push_mode_timestamp_payload_t *ts_payload_ptr = + (sh_mem_push_mode_timestamp_payload_t *)&local_header_buf_ptr[local_offset]; + + uint32_t utc_ts_lsw = (uint32_t)(timestamp & 0xFFFFFFFF); + uint32_t utc_ts_msw = (uint32_t)(timestamp >> 32); + PULL_PUSH_MSG(miid, DBG_LOW_PRIO, + "PRE UTC timestamp: 0x%08x%08x", + utc_ts_msw, + utc_ts_lsw); + + posal_query_utc_time_from_nw((void *)me_ptr->ts_data.utc_time_module_ptr, TIME_USEC); + + posal_date_time_get_utc_time((void *)me_ptr->ts_data.utc_time_module_ptr, (posal_time)timestamp,TIME_USEC, &utc_ts_msw, &utc_ts_lsw); + ts_payload_ptr->timestamp_us_lsw = utc_ts_lsw; + ts_payload_ptr->timestamp_us_msw = utc_ts_msw; + local_offset += sizeof(sh_mem_push_mode_timestamp_payload_t); + + PULL_PUSH_MSG(miid, DBG_LOW_PRIO, + "UTC timestamp: 0x%08x%08x", + ts_payload_ptr->timestamp_us_msw, + ts_payload_ptr->timestamp_us_lsw); + } + + // 3. Write PCM Data Parameter Header (size will be updated later) + sh_mem_push_mode_param_header_t *pcm_param_hdr_ptr = + (sh_mem_push_mode_param_header_t *)&local_header_buf_ptr[local_offset]; + pcm_param_hdr_ptr->param_id = PARAM_ID_HEADER_TYPE_PCM_DATA; + pcm_param_hdr_ptr->actual_size = 0; // Will be updated when batch ends + pcm_param_hdr_ptr->padding_size = 0; // Will be updated when batch ends + + + uint32_t pcm_param_actual_size_offset = (uint8_t*)&pcm_param_hdr_ptr->actual_size - local_header_buf_ptr; + uint32_t pcm_param_padding_size_offset = (uint8_t*)&pcm_param_hdr_ptr->padding_size - local_header_buf_ptr; + + local_offset += sizeof(sh_mem_push_mode_param_header_t); + + // Sanity check: ensure we didn't overflow the buffer + if (local_offset > max_size) + { + PULL_PUSH_MSG(miid, DBG_ERROR_PRIO, + "Header size %d exceeds allocated size %d", + local_offset, max_size); + return CAPI_EFAILED; + } + + // 4. Write header to DDR with wrap-around handling + pull_push_mode_t *pm_ptr = &me_ptr->pull_push_mode_info; + uint32_t circ_buf_size = pm_ptr->shared_circ_buf_size; + uint32_t bytes_to_write = local_offset; + uint32_t current_write_index = *write_index_ptr; + uint32_t bytes_written = 0; + + while (bytes_to_write) + { + // Calculate space available till end of buffer + uint32_t rem_lin_size = circ_buf_size - current_write_index; + uint32_t bytes_to_copy = MIN(bytes_to_write, rem_lin_size); + + // Copy to DDR + memscpy(pm_ptr->shared_circ_buf_start_ptr + current_write_index, + bytes_to_copy, + &local_header_buf_ptr[bytes_written], + bytes_to_copy); + + bytes_to_write -= bytes_to_copy; + bytes_written += bytes_to_copy; + + current_write_index = current_write_index + bytes_to_copy; + if (current_write_index >= pm_ptr->shared_circ_buf_size) + { + current_write_index = 0; + } + } + + // 5. Calculate DDR indices with wrap-around + uint32_t param_actual_size_sh_mem_index = + (header_start_index + pcm_param_actual_size_offset) % circ_buf_size; + me_ptr->pcm_param_actual_size_ptr = + (uint32_t *)(pm_ptr->shared_circ_buf_start_ptr + param_actual_size_sh_mem_index); + + uint32_t param_padding_sh_mem_index = + (header_start_index + pcm_param_padding_size_offset) % circ_buf_size; + me_ptr->pcm_param_padding_size_ptr = + (uint32_t *)(pm_ptr->shared_circ_buf_start_ptr + param_padding_sh_mem_index); + + + PULL_PUSH_MSG(miid, DBG_HIGH_PRIO, + "Batch header written to DDR: size=%d bytes, start_index=%d, end_index=%d", + bytes_written, *write_index_ptr, current_write_index); + + PULL_PUSH_MSG(miid, DBG_LOW_PRIO, + "SH MEM: actual_size=0x%lx (index=%d), padding_size=0x%lx (index=%d)", + *me_ptr->pcm_param_actual_size_ptr, param_actual_size_sh_mem_index, + *me_ptr->pcm_param_padding_size_ptr, param_padding_sh_mem_index); + + *write_index_ptr = current_write_index; + me_ptr->batch_bytes_written = local_offset; + + return result; +} + +capi_err_t push_mode_end_header_batch(capi_pm_t *_pif, uint64_t timestamp) +{ + capi_pm_t *capi_ptr = (capi_pm_t *)_pif; + pull_push_mode_t *me_ptr = &(capi_ptr->pull_push_mode_info); + uint32_t rem_lin_size, temp_wr_ind, padding_bytes = 0; + int8_t *write_ptr = NULL; + sh_mem_pull_push_mode_position_buffer_t *pos_buf_ptr = me_ptr->shared_pos_buf_ptr; + uint32_t miid = me_ptr->miid; + + // add padding bytes if write_index is not 4-byte aligned + uint32_t misaligned_bytes = capi_ptr->pcm_bytes_written % BYTE_FOR_HEADER_ALIGNMENT; + + if(misaligned_bytes) + { + padding_bytes = BYTE_FOR_HEADER_ALIGNMENT - misaligned_bytes; + + rem_lin_size = me_ptr->shared_circ_buf_size - capi_ptr->batch_write_index; + + write_ptr = (int8_t *)(me_ptr->shared_circ_buf_start_ptr + capi_ptr->batch_write_index); + if(padding_bytes <= rem_lin_size) + { + memset(write_ptr, 0, padding_bytes); + capi_ptr->batch_write_index += padding_bytes; + } + else + { + PULL_PUSH_MSG(miid, DBG_ERROR_PRIO, "Padding bytes %d exceeds remaining linear memory %d, shared memory is not 4-byte aligned", + padding_bytes, rem_lin_size); + + memset(write_ptr, 0, rem_lin_size); + capi_ptr->batch_write_index += rem_lin_size; + } + + if (capi_ptr->batch_write_index >= me_ptr->shared_circ_buf_size) + { + capi_ptr->batch_write_index = 0; + } + } + + + // Update header size + *capi_ptr->pcm_param_actual_size_ptr = capi_ptr->pcm_bytes_written; + *capi_ptr->pcm_param_padding_size_ptr = padding_bytes; + capi_ptr->batch_bytes_written += (capi_ptr->pcm_bytes_written + padding_bytes); + + temp_wr_ind = pos_buf_ptr->index; + write_ptr = (int8_t *)(me_ptr->shared_circ_buf_start_ptr + temp_wr_ind); + rem_lin_size = me_ptr->shared_circ_buf_size - temp_wr_ind; + + //cache flush now, check for watermark event and update index (Handle the wrap around case here) + if(capi_ptr->batch_bytes_written < rem_lin_size) + { +#ifndef DISABLE_CACHE_OPERATIONS + posal_cache_flush_v2(&write_ptr, capi_ptr->batch_bytes_written); +#endif + pull_push_mode_check_send_watermark_event(capi_ptr, temp_wr_ind, capi_ptr->batch_write_index); + } + else + { +#ifndef DISABLE_CACHE_OPERATIONS + posal_cache_flush_v2(&write_ptr, rem_lin_size); +#endif + pull_push_mode_check_send_watermark_event(capi_ptr, temp_wr_ind, me_ptr->shared_circ_buf_size); + + if(0 != capi_ptr->batch_write_index) + { + write_ptr = (int8_t *)(me_ptr->shared_circ_buf_start_ptr); + temp_wr_ind = 0; +#ifndef DISABLE_CACHE_OPERATIONS + posal_cache_flush_v2(&write_ptr, capi_ptr->batch_bytes_written - rem_lin_size); +#endif + pull_push_mode_check_send_watermark_event(capi_ptr, temp_wr_ind, capi_ptr->batch_write_index); + } + } + + /** update position buffer with new index*/ + pull_mode_update_pos_buffer(pos_buf_ptr, me_ptr->ist_priority, capi_ptr->batch_write_index , timestamp); + + PULL_PUSH_MSG(miid, DBG_HIGH_PRIO, + "Batch written actual bytes %lu, padding bytes %lu, next batch starts at index %d", + *capi_ptr->pcm_param_actual_size_ptr, *capi_ptr->pcm_param_padding_size_ptr, capi_ptr->batch_write_index); + + capi_ptr->is_update_header = TRUE; + capi_ptr->pcm_bytes_written = 0; + return CAPI_EOK; +} + capi_err_t push_mode_write_output(capi_t *_pif, capi_stream_data_t *input[], capi_stream_data_t *output[]) { capi_err_t result = CAPI_EOK; @@ -588,8 +831,45 @@ capi_err_t push_mode_write_output(capi_t *_pif, capi_stream_data_t *input[], cap pos_buf_ptr); return CAPI_EFAILED; } + + // Deferred from algo reset: reset pos buffer now + if (capi_ptr->is_pending_pos_buf_reset) + { + PULL_PUSH_MSG(miid, DBG_HIGH_PRIO, "Applying deferred position buffer reset before new write"); + if (NULL != me_ptr->shared_pos_buf_ptr) { + memset(me_ptr->shared_pos_buf_ptr, 0, sizeof(sh_mem_pull_push_mode_position_buffer_t)); + } + me_ptr->next_read_index = 0; + capi_ptr->is_pending_pos_buf_reset = FALSE; + } + + // Track last valid timestamp for invalid timestamp handling + if ((*input)->flags.is_timestamp_valid) + { + capi_ptr->last_valid_timestamp = (*input)->timestamp; + } + + if (capi_ptr->is_header_enabled) + { + if (!(*input)->flags.is_timestamp_valid) + { + PULL_PUSH_MSG(miid, DBG_ERROR_PRIO, + "Invalid timestamp detected, dropping frame with %lu bytes", + module_buf_ptr[0].actual_data_len); + + if (!capi_ptr->is_update_header && (capi_ptr->pcm_bytes_written > 0)) + { + PULL_PUSH_MSG(miid, DBG_HIGH_PRIO, + "Finalizing in-progress batch (pcm_bytes=%lu) before dropping invalid timestamp frame", + capi_ptr->pcm_bytes_written); + push_mode_end_header_batch(capi_ptr, capi_ptr->last_valid_timestamp); + } + + return CAPI_EOK; + } + } - uint64_t timestamp = (*input)->flags.is_timestamp_valid ? (*input)->timestamp : posal_timer_get_time(); + uint64_t timestamp = (*input)->flags.is_timestamp_valid ? (*input)->timestamp : posal_timer_get_time(); uint32_t write_index = pos_buf_ptr->index, temp_wr_ind; // input data not is not available, nothing to do @@ -600,6 +880,10 @@ capi_err_t push_mode_write_output(capi_t *_pif, capi_stream_data_t *input[], cap me_ptr->curr_shared_buf_ptr = NULL; module_buf_ptr[0].data_ptr = NULL; } + if(capi_ptr->is_header_enabled) + { + write_index = capi_ptr->batch_write_index; + } } else if (me_ptr->curr_shared_buf_ptr) { @@ -669,6 +953,32 @@ capi_err_t push_mode_write_output(capi_t *_pif, capi_stream_data_t *input[], cap } else // buffer access extension is disabled. { + // Use batch_write_index for tracking within batch when headers enabled + if (capi_ptr->is_header_enabled) + { + // Write batch header at the start of a new batch (when headers enabled and not in middle of batch) + if (capi_ptr->is_update_header && 0 != module_buf_ptr[0].actual_data_len) + { + capi_ptr->pcm_bytes_written = 0; + // Initialize batch tracking + capi_ptr->batch_write_index = write_index; + if (CAPI_FAILED(result = push_mode_write_batch_header(capi_ptr, &capi_ptr->batch_write_index, timestamp))) + { + PULL_PUSH_MSG(miid, DBG_ERROR_PRIO, "Failed to write batch header"); + return result; + } + + capi_ptr->is_update_header = FALSE; + + PULL_PUSH_MSG(miid, DBG_HIGH_PRIO, + "Batch header written at index %d, PCM data starts at index %d", + write_index, capi_ptr->batch_write_index); + } + + write_index = capi_ptr->batch_write_index; + + } + uint32_t bytes_to_copy, bytes_copied = 0, bytes_copied_per_channel = 0, bytes_copied_per_channel_now = 0; while (module_buf_ptr[0].actual_data_len > 0) { @@ -683,8 +993,12 @@ capi_err_t push_mode_write_output(capi_t *_pif, capi_stream_data_t *input[], cap memscpy(write_ptr, bytes_to_copy, (module_buf_ptr[0].data_ptr + bytes_copied), bytes_to_copy); #ifndef DISABLE_CACHE_OPERATIONS - posal_cache_flush_v2(&write_ptr, bytes_to_copy); + if (!capi_ptr->is_header_enabled) + { + posal_cache_flush_v2(&write_ptr, bytes_to_copy); + } #endif + module_buf_ptr[0].actual_data_len -= bytes_to_copy; bytes_copied += bytes_to_copy; } @@ -715,7 +1029,10 @@ capi_err_t push_mode_write_output(capi_t *_pif, capi_stream_data_t *input[], cap } #ifndef DISABLE_CACHE_OPERATIONS - posal_cache_flush_v2(&write_ptr, bytes_to_copy); + if (!capi_ptr->is_header_enabled) + { + posal_cache_flush_v2(&write_ptr, bytes_to_copy); + } #endif bytes_copied_per_channel_now = bytes_to_copy / me_ptr->media_fmt.num_channels; @@ -727,9 +1044,17 @@ capi_err_t push_mode_write_output(capi_t *_pif, capi_stream_data_t *input[], cap bytes_copied_per_channel += bytes_copied_per_channel_now; } - temp_wr_ind = write_index; - write_index += bytes_to_copy; - pull_push_mode_check_send_watermark_event(capi_ptr, temp_wr_ind, write_index); + // Only check watermark if headers disabled (will check at batch end if enabled) + if (!capi_ptr->is_header_enabled) + { + temp_wr_ind = write_index; + write_index += bytes_to_copy; + pull_push_mode_check_send_watermark_event(capi_ptr, temp_wr_ind, write_index); + } + else + { + write_index += bytes_to_copy; + } if (write_index >= me_ptr->shared_circ_buf_size) { write_index = 0; @@ -740,16 +1065,51 @@ capi_err_t push_mode_write_output(capi_t *_pif, capi_stream_data_t *input[], cap if (CAPI_INTERLEAVED == me_ptr->media_fmt.data_interleaving) { module_buf_ptr[0].actual_data_len = bytes_copied; + capi_ptr->pcm_bytes_written += bytes_copied; } else { // for unpacked v2 only first ch buffer lens need to be used. module_buf_ptr[0].actual_data_len = bytes_copied_per_channel; + capi_ptr->pcm_bytes_written += (bytes_copied_per_channel * me_ptr->media_fmt.num_channels); } } - /** update position buffer with new index*/ - pull_mode_update_pos_buffer(pos_buf_ptr, me_ptr->ist_priority, write_index, timestamp); + if (!capi_ptr->is_header_enabled) + { + /** update position buffer with new index*/ + pull_mode_update_pos_buffer(pos_buf_ptr, me_ptr->ist_priority, write_index, timestamp); + } + else + { + capi_ptr->batch_write_index = write_index; + capi_stream_data_v2_t *inputv2 = (capi_stream_data_v2_t *)input[0]; + bool_t is_batch_completed = (input[0]->flags.marker_eos || input[0]->flags.end_of_frame) ? TRUE: FALSE; + + //check for dam batch marker md + if (NULL != inputv2->metadata_list_ptr && !is_batch_completed) + { + module_cmn_md_list_t *node_ptr = inputv2->metadata_list_ptr; + module_cmn_md_list_t *next_ptr = NULL; + while (node_ptr) + { + module_cmn_md_t * md_ptr = (module_cmn_md_t *)node_ptr->obj_ptr; + next_ptr = node_ptr->next_ptr; + if (DAM_BATCH_END_MD_ID_MARKER == md_ptr->metadata_id) + { + is_batch_completed = TRUE; + break; + } + + node_ptr = next_ptr; + } + } + + if(is_batch_completed) + { + push_mode_end_header_batch(capi_ptr, timestamp); + } + } // raise EOS marker event if ((*input)->flags.marker_eos) diff --git a/fwk/spf/modules/sh_mem_pull_push_mode/src/pull_push_mode.h b/fwk/spf/modules/sh_mem_pull_push_mode/src/pull_push_mode.h index b1b18f45..2f895c8a 100644 --- a/fwk/spf/modules/sh_mem_pull_push_mode/src/pull_push_mode.h +++ b/fwk/spf/modules/sh_mem_pull_push_mode/src/pull_push_mode.h @@ -20,6 +20,7 @@ #include "capi_util.h" #endif #include "posal_timer.h" +#include "posal_time.h" #include "sh_mem_pull_push_mode_api.h" #include "ar_error_codes.h" #include "capi_types.h" @@ -37,6 +38,11 @@ extern "C" { #define MAX_EVENT_CLIENTS 4 +#define HEADER_TYPE_UTC_TIMESTAMP 0x00000001 + +#define HEADER_TYPE_RESERVED_BITS 0xFFFFFFFE +#define BYTE_FOR_HEADER_ALIGNMENT 4 + /* debug message */ #define MIID_UNKNOWN 0 #define PULL_PUSH_MSG_PREFIX "CAPI PM:[%lX] " @@ -47,6 +53,7 @@ extern "C" { * Structure definitions * ----------------------------------------------------------------------*/ #define QFORMAT_TO_BIT_WIDTH(q) ((PCM_Q_FACTOR_15 == q) ? 16 : ( (PCM_Q_FACTOR_27 == q ) ? 24 : 32) ) +#define TIME_USEC 1 typedef struct pm_media_fmt_t { @@ -106,6 +113,11 @@ typedef struct capi_pm_media_fmt_t capi_standard_data_format_t std; } capi_pm_media_fmt_t; + +typedef struct capi_push_ts_data_t { + void *utc_time_module_ptr; // assign this is UTC TS is needed +} capi_push_ts_data_t; + typedef struct capi_pm_t { /* v-table pointer */ @@ -121,6 +133,27 @@ typedef struct capi_pm_t // container frame duration. uint32_t frame_dur_us; + + bool_t is_cntr_duty_cycle_enabled; + + /*header related parameter*/ + bool_t is_header_enabled; + bool_t is_update_header; + bool_t is_pending_pos_buf_reset; + uint32_t header_type_flags; + uint8_t *header_buffer_ptr; + uint32_t header_buffer_size; + + uint32_t *pcm_param_actual_size_ptr; + uint32_t *pcm_param_padding_size_ptr; + + uint32_t batch_write_index; + uint32_t pcm_bytes_written; + uint32_t batch_bytes_written; + // UTC timestamp handling + capi_push_ts_data_t ts_data; + uint64_t last_valid_timestamp; // tracks last valid timestamp received in current batch + } capi_pm_t; /*------------------------------------------------------------------------ @@ -156,6 +189,7 @@ void pull_push_mode_deinit(pull_push_mode_t *pm_ptr); capi_err_t pull_mode_read_input(capi_t *_pif, capi_stream_data_t *input[], capi_stream_data_t *output[]); capi_err_t push_mode_write_output(capi_t *_pif, capi_stream_data_t *input[], capi_stream_data_t *output[]); +capi_err_t push_mode_end_header_batch(capi_pm_t *_pif, uint64_t timestamp); capi_err_t pull_push_mode_watermark_levels_init(pull_push_mode_t *pm_ptr, uint32_t num_water_mark_levels, diff --git a/fwk/spf/modules/simple_splitter/build/Android.mk b/fwk/spf/modules/simple_splitter/build/Android.mk index 6c0d8854..641502f7 100644 --- a/fwk/spf/modules/simple_splitter/build/Android.mk +++ b/fwk/spf/modules/simple_splitter/build/Android.mk @@ -11,7 +11,7 @@ include $(BUILD_HEADER_LIBRARY) include $(CLEAR_VARS) -LOCAL_MODULE := capi_splitter +LOCAL_MODULE := lib_splitter LOCAL_MODULE_TAGS := optional LOCAL_VENDOR_MODULE := true LOCAL_C_INCLUDES := \ @@ -22,6 +22,7 @@ LOCAL_C_INCLUDES := \ LOCAL_SRC_FILES := \ capi/src/capi_splitter.c \ capi/src/capi_splitter_island.c \ + capi/src/capi_splitter_md_island.c \ capi/src/capi_splitter_utils.c LOCAL_CFLAGS += -flto -O3 -Wall -ffixed-x18 -std=c17 -g @@ -40,5 +41,16 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_HEADER_LIBRARIES := libposal_headers libspf_api libspf_interfaces_headers libspf_utils_headers libapm_headers libamdb_headers LOCAL_STATIC_LIBRARIES := libposal libspf_interfaces libapm libamdb -include $(BUILD_STATIC_LIBRARY) +LOCAL_SPF_MODULE_KCONFIG := CONFIG_SPLITTER +LOCAL_SPF_MODULE_NAME := $(LOCAL_MODULE) +LOCAL_SPF_MODULE_MAJOR_VER := 1 +LOCAL_SPF_MODULE_MINOR_VER := 0 +LOCAL_SPF_MODULE_AMDB_ITYPE := "capi" +LOCAL_SPF_MODULE_AMDB_MTYPE := "generic" +LOCAL_SPF_MODULE_AMDB_MID := "0x07001011" +LOCAL_SPF_MODULE_AMDB_TAG := "capi_splitter" +LOCAL_SPF_MODULE_AMDB_MOD_NAME := "MODULE_ID_SPLITTER" +LOCAL_SPF_MODULE_H2XML_HEADERS := "$(LOCAL_PATH)/api/splitter_api.h" + +include $(BUILD_ARE_MODULES) diff --git a/fwk/spf/modules/sync_module/build/Android.mk b/fwk/spf/modules/sync_module/build/Android.mk index 16c94970..fbcad2f2 100644 --- a/fwk/spf/modules/sync_module/build/Android.mk +++ b/fwk/spf/modules/sync_module/build/Android.mk @@ -11,7 +11,7 @@ include $(BUILD_HEADER_LIBRARY) include $(CLEAR_VARS) -LOCAL_MODULE := capi_sync +LOCAL_MODULE := lib_sync LOCAL_MODULE_TAGS := optional LOCAL_VENDOR_MODULE := true LOCAL_C_INCLUDES := \ @@ -45,5 +45,16 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_HEADER_LIBRARIES := libposal_headers libspf_api libspf_interfaces_headers libspf_utils_headers libapm_headers libamdb_headers LOCAL_STATIC_LIBRARIES := libposal libspf_interfaces libapm libamdb -include $(BUILD_STATIC_LIBRARY) +LOCAL_SPF_MODULE_KCONFIG := CONFIG_SYNC +LOCAL_SPF_MODULE_NAME := $(LOCAL_MODULE) +LOCAL_SPF_MODULE_MAJOR_VER := 1 +LOCAL_SPF_MODULE_MINOR_VER := 0 +LOCAL_SPF_MODULE_AMDB_ITYPE := "capi" +LOCAL_SPF_MODULE_AMDB_MTYPE := "generic" +LOCAL_SPF_MODULE_AMDB_MID := "0x07001038" +LOCAL_SPF_MODULE_AMDB_TAG := "capi_sync" +LOCAL_SPF_MODULE_AMDB_MOD_NAME := "MODULE_ID_SYNC" +LOCAL_SPF_MODULE_H2XML_HEADERS := "$(LOCAL_PATH)/api/sync_api.h" + +include $(BUILD_ARE_MODULES) diff --git a/fwk/spf/utils/build/Android.mk b/fwk/spf/utils/build/Android.mk index 4edfe000..eb6d0511 100644 --- a/fwk/spf/utils/build/Android.mk +++ b/fwk/spf/utils/build/Android.mk @@ -69,13 +69,10 @@ LOCAL_SHARED_LIBRARIES := \ liblx-osal \ libar-gpr \ libdiag \ - libtinyalsa + liboss_tinyalsa LOCAL_HEADER_LIBRARIES := libposal_headers libspf_api libspf_interfaces_headers libapm_headers libamdb_headers libirm_headers libdls_headers LOCAL_STATIC_LIBRARIES := \ - capi_priority_sync \ - capi_splitter \ - capi_sync \ libamdb \ libapm \ libdls \