diff --git a/src/audio/kpb.c b/src/audio/kpb.c index ec0104bf671c..f76dc665e859 100644 --- a/src/audio/kpb.c +++ b/src/audio/kpb.c @@ -1143,13 +1143,23 @@ static void kpb_micselect_copy16(struct comp_buffer *sink, ae_int16 *out_ptr; for (ch = 0; ch < micsel_channels; ch++) { - const ae_int16 *input_data = (const ae_int16 *)(in_ptr) + offsets[ch]; + const ae_int16 *input_frame = in_ptr; + size_t copied = 0; out_ptr = audio_stream_get_wptr(ostream); out_ptr += ch; - for (i = 0; i < samples_per_chan; i++) { - AE_L16_XP(d16, input_data, in_offset); - AE_S16_0_XC(d16, out_ptr, out_offset); + while (copied < samples_per_chan) { + size_t frames = audio_stream_frames_without_wrap(istream, input_frame); + const ae_int16 *input_data = input_frame + offsets[ch]; + + frames = MIN(frames, samples_per_chan - copied); + for (i = 0; i < frames; i++) { + AE_L16_XP(d16, input_data, in_offset); + AE_S16_0_XC(d16, out_ptr, out_offset); + } + input_frame = audio_stream_wrap(istream, + (void *)(input_frame + frames * in_channels)); + copied += frames; } } } @@ -1178,13 +1188,23 @@ static void kpb_micselect_copy32(struct comp_buffer *sink, ae_int32 *out_ptr; for (ch = 0; ch < micsel_channels; ch++) { - const ae_int32 *input_data = (const ae_int32 *)(in_ptr) + offsets[ch]; + const ae_int32 *input_frame = in_ptr; + size_t copied = 0; out_ptr = audio_stream_get_wptr(ostream); out_ptr += ch; - for (i = 0; i < samples_per_chan; i++) { - AE_L32_XP(d32, input_data, in_offset); - AE_S32_L_XC(d32, out_ptr, out_offset); + while (copied < samples_per_chan) { + size_t frames = audio_stream_frames_without_wrap(istream, input_frame); + const ae_int32 *input_data = input_frame + offsets[ch]; + + frames = MIN(frames, samples_per_chan - copied); + for (i = 0; i < frames; i++) { + AE_L32_XP(d32, input_data, in_offset); + AE_S32_L_XC(d32, out_ptr, out_offset); + } + input_frame = audio_stream_wrap(istream, + (void *)(input_frame + frames * in_channels)); + copied += frames; } } } @@ -1211,12 +1231,16 @@ static void kpb_micselect_copy16(struct comp_buffer *sink, out_data = audio_stream_get_wptr(ostream); for (size_t i = 0; i < samples_per_chan * in_channels; i += in_channels) { + const int16_t *in_sample = audio_stream_get_frag(istream, in_data, + i + offsets[ch], + sizeof(*in_sample)); + if (&out_data[out_samples + ch] >= (int16_t *)audio_stream_get_end_addr(ostream)) { out_data = (int16_t *)audio_stream_get_addr(ostream); out_samples = 0; } - out_data[out_samples + ch] = in_data[i + offsets[ch]]; + out_data[out_samples + ch] = *in_sample; out_samples += micsel_channels; } } @@ -1242,12 +1266,16 @@ static void kpb_micselect_copy32(struct comp_buffer *sink, out_data = audio_stream_get_wptr(ostream); for (size_t i = 0; i < samples_per_chan * in_channels; i += in_channels) { + const int32_t *in_sample = audio_stream_get_frag(istream, in_data, + i + offsets[ch], + sizeof(*in_sample)); + if (&out_data[out_samples + ch] >= (int32_t *)audio_stream_get_end_addr(ostream)) { out_data = (int32_t *)audio_stream_get_addr(ostream); out_samples = 0; } - out_data[out_samples + ch] = in_data[i + offsets[ch]]; + out_data[out_samples + ch] = *in_sample; out_samples += micsel_channels; } } @@ -1326,7 +1354,6 @@ static int kpb_copy(struct comp_dev *dev) case KPB_STATE_RUN: /* In normal RUN state we simply copy to our sink. */ sink = kpb->sel_sink; - ret = PPL_STATUS_PATH_STOP; if (!sink) { comp_err(dev, "no sink."); @@ -1339,6 +1366,7 @@ static int kpb_copy(struct comp_dev *dev) copy_bytes = audio_stream_get_avail_bytes(&source->stream); comp_update_buffer_consume(source, copy_bytes); comp_dbg(dev, "KD not active, dropping %zu bytes...", copy_bytes); + ret = PPL_STATUS_PATH_STOP; break; } @@ -1354,7 +1382,8 @@ static int kpb_copy(struct comp_dev *dev) comp_err(dev, "nothing to copy sink->free %u source->avail %u", audio_stream_get_free_bytes(&sink->stream), audio_stream_get_avail_bytes(&source->stream)); - ret = PPL_STATUS_PATH_STOP; + if (!audio_stream_get_avail_bytes(&sink->stream)) + ret = PPL_STATUS_PATH_STOP; break; } @@ -1375,7 +1404,8 @@ static int kpb_copy(struct comp_dev *dev) comp_err(dev, "nothing to copy sink->free %u source->avail %u", free, avail); - ret = PPL_STATUS_PATH_STOP; + if (!audio_stream_get_avail_bytes(&sink->stream)) + ret = PPL_STATUS_PATH_STOP; break; } kpb_micselect_copy(dev, sink, source, produced_bytes, channels); @@ -1390,7 +1420,6 @@ static int kpb_copy(struct comp_dev *dev) comp_err(dev, "internal buffering failed."); break; } - ret = PPL_STATUS_PATH_STOP; /* Update buffered size. NOTE! We only record buffered * data up to the size of history buffer. @@ -1708,7 +1737,6 @@ static int kpb_register_client(struct comp_data *kpb, struct kpb_client *cli) static void kpb_init_draining(struct comp_dev *dev, struct kpb_client *cli) { struct comp_data *kpb = comp_get_drvdata(dev); - bool is_sink_ready = (comp_buffer_get_sink_state(kpb->host_sink) == COMP_STATE_ACTIVE); size_t sample_width = kpb->config.sampling_width; size_t drain_req = (size_t)cli->drain_req * kpb->config.channels * (kpb->config.sampling_freq / 1000) * @@ -1727,12 +1755,18 @@ static void kpb_init_draining(struct comp_dev *dev, struct kpb_client *cli) comp_info(dev, "requested draining of %d [ms] from history buffer", cli->drain_req); + /* The drain pin stays unbound when a client only signals detections. */ + if (!kpb->host_sink) { + comp_dbg(dev, "no draining sink, ignoring request"); + return; + } + if (kpb->state != KPB_STATE_RUN) { comp_err(dev, "wrong KPB state"); } else if (cli->id > KPB_MAX_NO_OF_CLIENTS) { comp_err(dev, "wrong client id"); /* TODO: check also if client is registered */ - } else if (!is_sink_ready) { + } else if (comp_buffer_get_sink_state(kpb->host_sink) != COMP_STATE_ACTIVE) { comp_err(dev, "sink not ready for draining"); } else if (kpb->hd.buffered < drain_req || cli->drain_req > KPB_MAX_DRAINING_REQ) {