Repository navigation
KWD: merge with release branch #1462
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0bcc480
6b4aeda
5c6c90c
b69b47a
1517583
ab40a04
1fec568
a652651
b190d1a
649bfc9
bc4887f
508e245
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,8 +29,8 @@ | |
| #define ACTIVATION_DEFAULT_THRESHOLD_S16 \ | ||
| ((int16_t)((INT16_MAX) * (ACTIVATION_DEFAULT_THRESHOLD))) | ||
|
|
||
| /* number of samples to be treated as a full keyphrase */ | ||
| #define KEYPHRASE_DEFAULT_PREAMBLE_LENGTH (30 * 1024) | ||
| /* default number of samples before detection is activated */ | ||
| #define KEYPHRASE_DEFAULT_PREAMBLE_LENGTH 0 | ||
|
|
||
| struct comp_data { | ||
| struct sof_detect_test_config config; | ||
|
|
@@ -40,6 +40,7 @@ struct comp_data { | |
| uint32_t detect_preamble; /**< current keyphrase preamble length */ | ||
| uint32_t keyphrase_samples; /**< keyphrase length in samples */ | ||
| uint32_t buf_copy_pos; /**< current copy position for incoming data */ | ||
| uint32_t history_depth; /** defines draining size in bytes. */ | ||
|
|
||
| struct notify_data event; | ||
| struct kpb_event_data event_data; | ||
|
|
@@ -70,12 +71,10 @@ static void notify_kpb(struct comp_dev *dev) | |
| cd->client_data.r_ptr = NULL; | ||
| cd->client_data.sink = NULL; | ||
| cd->client_data.id = 0; /**< TODO: acquire proper id from kpb */ | ||
| cd->client_data.history_end = 0; /**< keyphrase end, 0 is now */ | ||
| cd->client_data.history_begin = cd->detect_preamble; | ||
|
mrajwa marked this conversation as resolved.
Resolved
|
||
| /* time in milliseconds */ | ||
| cd->client_data.history_depth = cd->detect_preamble / | ||
| (dev->params.rate / 1000); | ||
|
|
||
| cd->client_data.history_depth = (cd->history_depth != 0) ? | ||
| cd->history_depth : | ||
| cd->config.history_depth; | ||
| cd->event_data.event_id = KPB_EVENT_BEGIN_DRAINING; | ||
| cd->event_data.client_data = &cd->client_data; | ||
|
|
||
|
|
@@ -118,6 +117,12 @@ static void default_detect_test(struct comp_dev *dev, | |
|
|
||
| if (cd->detect_preamble >= cd->keyphrase_samples) { | ||
| if (cd->activation >= cd->config.activation_threshold) { | ||
| /* The algorithm shall use cd->history_depth | ||
| * to specify its draining size request. | ||
| * Zero value means default config value | ||
| * will be used. | ||
| */ | ||
| cd->history_depth = 0; | ||
| detect_test_notify(dev); | ||
| cd->detected = 1; | ||
| } | ||
|
|
@@ -280,14 +285,8 @@ static int test_keyword_params(struct comp_dev *dev) | |
| dev->frame_bytes = comp_frame_bytes(dev); | ||
|
|
||
| /* calculate the length of the preamble */ | ||
| if (cd->config.keyphrase_length) { | ||
| if (cd->config.keyphrase_length > KPB_MAX_BUFF_TIME) { | ||
| trace_keyword_error("test_keyword_params() " | ||
| "error: kp length too long"); | ||
| return -EINVAL; | ||
| } | ||
|
|
||
| cd->keyphrase_samples = cd->config.keyphrase_length * | ||
| if (cd->config.preamble_time) { | ||
| cd->keyphrase_samples = cd->config.preamble_time * | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here the naming "keyphrase_length" sounds more reasonable to me. :P
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or "keyphrase_ms"?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Hah really? To me "keyphrase length" is just confusing. It suggest how much buffered data we want to get which is what @lgirdwood what do you think?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mrajwa do you mean that those data before preamble_time will be ignored and dropped?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @keyonjie, they are ignored but not dropped - they will always be stored in history buffer inside KPB but detector won't trigger detection before preamble time is over. |
||
| (dev->params.rate / 1000); | ||
| } else { | ||
| cd->keyphrase_samples = KEYPHRASE_DEFAULT_PREAMBLE_LENGTH; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,7 @@ | |
| #include <sof/list.h> | ||
| #include <sof/audio/buffer.h> | ||
| #include <sof/ut.h> | ||
| #include <sof/clk.h> | ||
|
|
||
| /* KPB private data, runtime data */ | ||
| struct comp_data { | ||
|
|
@@ -33,8 +34,8 @@ struct comp_data { | |
| uint32_t source_period_bytes; /**< source number of period bytes */ | ||
| uint32_t sink_period_bytes; /**< sink number of period bytes */ | ||
| struct sof_kpb_config config; /**< component configuration data */ | ||
| struct comp_buffer *rt_sink; /**< real time sink (channel selector ) */ | ||
| struct comp_buffer *cli_sink; /**< draining sink (client) */ | ||
| struct comp_buffer *sel_sink; /**< real time sink (channel selector ) */ | ||
| struct comp_buffer *host_sink; /**< draining sink (client) */ | ||
|
mrajwa marked this conversation as resolved.
Resolved
|
||
| struct hb *history_buffer; | ||
| bool is_internal_buffer_full; | ||
| size_t buffered_data; | ||
|
|
@@ -53,9 +54,13 @@ static size_t kpb_allocate_history_buffer(struct comp_data *kpb); | |
| static void kpb_clear_history_buffer(struct hb *buff); | ||
| static void kpb_free_history_buffer(struct hb *buff); | ||
| static bool kpb_has_enough_history_data(struct comp_data *kpb, | ||
| struct hb *buff, size_t his_req); | ||
| struct hb *buff, size_t his_req); | ||
| static inline bool kpb_is_sample_width_supported(uint32_t sampling_width); | ||
|
|
||
| static void kpb_copy_samples(struct comp_buffer *sink, | ||
| struct comp_buffer *source, size_t size, | ||
| size_t sample_width); | ||
| static void kpb_drain_samples(void *source, struct comp_buffer *sink, | ||
| size_t size, size_t sample_width); | ||
|
|
||
| /** | ||
| * \brief Create a key phrase buffer component. | ||
|
|
@@ -379,10 +384,10 @@ static int kpb_prepare(struct comp_dev *dev) | |
| } | ||
| if (sink->sink->comp.type == SOF_COMP_SELECTOR) { | ||
| /* We found proper real time sink */ | ||
| cd->rt_sink = sink; | ||
| cd->sel_sink = sink; | ||
| } else if (sink->sink->comp.type == SOF_COMP_HOST) { | ||
| /* We found proper host sink */ | ||
| cd->cli_sink = sink; | ||
| cd->host_sink = sink; | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -462,17 +467,14 @@ static int kpb_copy(struct comp_dev *dev) | |
| /* Get source and sink buffers */ | ||
| source = list_first_item(&dev->bsource_list, struct comp_buffer, | ||
| sink_list); | ||
| sink = (kpb->state == KPB_STATE_BUFFERING) ? kpb->rt_sink | ||
| : kpb->cli_sink; | ||
|
|
||
| /* Pause selector copy during draining and/or draining on demand. | ||
| * We keep selector in this "paused" state as long as draining | ||
| * is going and later during direct copy to client's/host sink, | ||
| * in so called "draining on demand" state. In order to rearm | ||
| * detection algorithm kpb_reset is needed. | ||
| */ | ||
| if (kpb->state != KPB_STATE_BUFFERING) | ||
| sink = (kpb->state == KPB_STATE_BUFFERING) ? kpb->sel_sink | ||
| : kpb->host_sink; | ||
|
|
||
| /* Stop copying downstream if in draining mode */ | ||
| if (kpb->state == KPB_STATE_DRAINING) { | ||
| comp_update_buffer_consume(source, source->avail); | ||
| return PPL_STATUS_PATH_STOP; | ||
| } | ||
|
|
||
| /* Process source data */ | ||
| /* Check if there are valid pointers */ | ||
|
|
@@ -500,7 +502,8 @@ static int kpb_copy(struct comp_dev *dev) | |
|
|
||
| /* Sink and source are both ready and have space */ | ||
| copy_bytes = MIN(sink->free, source->avail); | ||
| assert(!memcpy_s(sink->w_ptr, copy_bytes, source->r_ptr, copy_bytes)); | ||
| kpb_copy_samples(sink, source, copy_bytes, | ||
| kpb->config.sampling_width); | ||
|
|
||
| /* Buffer source data internally in history buffer for future | ||
| * use by clients. | ||
|
|
@@ -689,10 +692,11 @@ static int kpb_register_client(struct comp_data *kpb, struct kpb_client *cli) | |
| */ | ||
| static void kpb_init_draining(struct comp_data *kpb, struct kpb_client *cli) | ||
| { | ||
| bool is_sink_ready = (kpb->cli_sink->sink->state == COMP_STATE_ACTIVE); | ||
| bool is_sink_ready = (kpb->host_sink->sink->state == COMP_STATE_ACTIVE); | ||
| size_t sample_width = kpb->config.sampling_width; | ||
| size_t history_depth = cli->history_depth * kpb->config.no_channels * | ||
| (kpb->config.sampling_freq / 1000) * | ||
| (kpb->config.sampling_width / 8); | ||
| (sample_width / 8); | ||
| struct hb *buff = kpb->history_buffer; | ||
| struct hb *first_buff = buff; | ||
| size_t buffered = 0; | ||
|
|
@@ -769,16 +773,17 @@ static void kpb_init_draining(struct comp_data *kpb, struct kpb_client *cli) | |
| trace_kpb("kpb_init_draining(), schedule draining task"); | ||
|
|
||
| /* Add one-time draining task into the scheduler. */ | ||
| kpb->draining_task_data.sink = kpb->cli_sink; | ||
| kpb->draining_task_data.sink = kpb->host_sink; | ||
| kpb->draining_task_data.history_buffer = buff; | ||
| kpb->draining_task_data.history_depth = history_depth; | ||
| kpb->draining_task_data.state = &kpb->state; | ||
| kpb->draining_task_data.sample_width = sample_width; | ||
|
|
||
| /* Pause selector copy. */ | ||
| kpb->rt_sink->sink->state = COMP_STATE_PAUSED; | ||
| /* Change KPB internal state to DRAINING */ | ||
| kpb->state = KPB_STATE_DRAINING; | ||
|
|
||
| /* Set host-sink copy mode to blocking */ | ||
| comp_set_attribute(kpb->cli_sink->sink, | ||
| comp_set_attribute(kpb->host_sink->sink, | ||
| COMP_ATTR_COPY_BLOCKING, 1); | ||
|
|
||
| /* Schedule draining task */ | ||
|
|
@@ -801,12 +806,18 @@ static uint64_t kpb_draining_task(void *arg) | |
| struct comp_buffer *sink = draining_data->sink; | ||
| struct hb *buff = draining_data->history_buffer; | ||
| size_t history_depth = draining_data->history_depth; | ||
| size_t sample_width = draining_data->sample_width; | ||
| size_t size_to_read; | ||
| size_t size_to_copy; | ||
| bool move_buffer = false; | ||
| uint32_t drained = 0; | ||
| uint64_t time_start; | ||
| uint64_t time_end; | ||
|
|
||
| trace_kpb("kpb_draining_task(), start."); | ||
|
|
||
| time_start = platform_timer_get(platform_timer); | ||
|
|
||
| while (history_depth > 0) { | ||
| size_to_read = (uint32_t)buff->end_addr - (uint32_t)buff->r_ptr; | ||
|
|
||
|
|
@@ -824,10 +835,12 @@ static uint64_t kpb_draining_task(void *arg) | |
| } | ||
| } | ||
|
|
||
| assert(!memcpy_s(sink->w_ptr, size_to_copy, buff->r_ptr, | ||
| size_to_copy)); | ||
| kpb_drain_samples(buff->r_ptr, sink, size_to_copy, | ||
| sample_width); | ||
|
|
||
| buff->r_ptr += (uint32_t)size_to_copy; | ||
| history_depth -= size_to_copy; | ||
| drained += size_to_copy; | ||
|
|
||
| if (move_buffer) { | ||
| buff->r_ptr = buff->start_addr; | ||
|
|
@@ -838,19 +851,54 @@ static uint64_t kpb_draining_task(void *arg) | |
| comp_update_buffer_produce(sink, size_to_copy); | ||
| } | ||
|
|
||
| time_end = platform_timer_get(platform_timer); | ||
|
mrajwa marked this conversation as resolved.
Resolved
|
||
|
|
||
| /* Draining is done. Now switch KPB to copy real time stream | ||
| * to client's sink | ||
| * to client's sink. This state is called "draining on demand" | ||
| */ | ||
| *draining_data->state = KPB_STATE_DRAINING_ON_DEMAND; | ||
| *draining_data->state = KPB_STATE_HOST_COPY; | ||
|
|
||
| /* Reset host-sink copy mode back to unblocking */ | ||
| comp_set_attribute(sink->sink, COMP_ATTR_COPY_BLOCKING, 0); | ||
|
|
||
| trace_kpb("kpb_draining_task(), done."); | ||
| trace_kpb("kpb_draining_task(), done. %u drained in %d ms.", | ||
| drained, | ||
| (time_end - time_start) | ||
| / clock_ms_to_ticks(PLATFORM_DEFAULT_CLOCK, 1)); | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| /** | ||
| * \brief Drain data samples safe, according to configuration. | ||
| * | ||
| * \param[in] dev - kpb component device pointer | ||
| * \param[in] sink - pointer to sink buffer. | ||
| * \param[in] source - pointer to source buffer. | ||
| * \param[in] size - requested copy size in bytes. | ||
| * | ||
| * \return none. | ||
| */ | ||
| static void kpb_drain_samples(void *source, struct comp_buffer *sink, | ||
| size_t size, size_t sample_width) | ||
| { | ||
| int16_t *dest; | ||
| int16_t *src = (int16_t *)source; | ||
| uint32_t i; | ||
| uint32_t j = 0; | ||
| uint32_t channel; | ||
| uint32_t frames = KPB_BYTES_TO_FRAMES(size, sample_width); | ||
|
|
||
| for (i = 0; i < frames; i++) { | ||
| for (channel = 0; channel < KPB_NR_OF_CHANNELS; channel++) { | ||
| dest = buffer_write_frag_s16(sink, j); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How shall we handle it once we are running with 24bit captured data? better to get it from fmt?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The support for more sampling options will be provided as separate patch. |
||
| *dest = *src; | ||
| src++; | ||
| j++; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * \brief Initialize history buffer by zeroing its memory. | ||
| * \param[in] buff - pointer to current history buffer. | ||
|
|
@@ -941,6 +989,37 @@ static inline bool kpb_is_sample_width_supported(uint32_t sampling_width) | |
| return ret; | ||
| } | ||
|
|
||
| /** | ||
| * \brief Copy data samples safe, according to configuration. | ||
| * | ||
| * \param[in] dev - kpb component device pointer | ||
| * \param[in] sink - pointer to sink buffer. | ||
| * \param[in] source - pointer to source buffer. | ||
| * \param[in] size - requested copy size in bytes. | ||
| * | ||
| * \return none. | ||
| */ | ||
| static void kpb_copy_samples(struct comp_buffer *sink, | ||
| struct comp_buffer *source, size_t size, | ||
| size_t sample_width) | ||
| { | ||
| int16_t *src; | ||
| int16_t *dest; | ||
| uint32_t i; | ||
| uint32_t j = 0; | ||
| uint32_t channel; | ||
| uint32_t frames = KPB_BYTES_TO_FRAMES(size, sample_width); | ||
|
|
||
| for (i = 0; i < frames; i++) { | ||
| for (channel = 0; channel < KPB_NR_OF_CHANNELS; channel++) { | ||
| src = buffer_read_frag_s16(source, j); | ||
| dest = buffer_write_frag_s16(sink, j); | ||
| *dest = *src; | ||
| j++; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| struct comp_driver comp_kpb = { | ||
| .type = SOF_COMP_KPB, | ||
| .ops = { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ | |
|
|
||
| #include <sof/platform.h> | ||
| #include <platform/interrupt.h> | ||
| #include <platform/clk.h> | ||
|
|
||
| struct sof; | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.