volume: do not schedule ramping as separate task

We should not be scheduling ramping as a separate task.
This patch makes it a part of copy function, which allows
for removal of entire schedule related code.
Ramping is done in maximum of 1 ms chunks by using functions
for retrieval of nearest zero crossing frame.

Signed-off-by: Tomasz Lauda <tomasz.lauda@linux.intel.com>
This commit is contained in:
Tomasz Lauda 2020-03-26 17:48:03 +01:00 committed by Tomasz Lauda
parent 0a82b71a5b
commit 1b57609a1e
2 changed files with 58 additions and 95 deletions

View File

@ -28,9 +28,6 @@
#include <sof/list.h> #include <sof/list.h>
#include <sof/math/numbers.h> #include <sof/math/numbers.h>
#include <sof/platform.h> #include <sof/platform.h>
#include <sof/schedule/ll_schedule.h>
#include <sof/schedule/schedule.h>
#include <sof/schedule/task.h>
#include <sof/string.h> #include <sof/string.h>
#include <sof/trace/trace.h> #include <sof/trace/trace.h>
#include <sof/ut.h> #include <sof/ut.h>
@ -40,6 +37,7 @@
#include <user/trace.h> #include <user/trace.h>
#include <config.h> #include <config.h>
#include <errno.h> #include <errno.h>
#include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@ -52,10 +50,6 @@ static const struct comp_driver comp_volume;
DECLARE_SOF_UUID("volume", volume_uuid, 0xb77e677e, 0x5ff4, 0x4188, DECLARE_SOF_UUID("volume", volume_uuid, 0xb77e677e, 0x5ff4, 0x4188,
0xaf, 0x14, 0xfb, 0xa8, 0xbd, 0xbf, 0x86, 0x82); 0xaf, 0x14, 0xfb, 0xa8, 0xbd, 0xbf, 0x86, 0x82);
/* 34dc0385-fc2f-4f7f-82d2-6cee444533e0 */
DECLARE_SOF_UUID("volume-task", volume_task_uuid, 0x34dc0385, 0xfc2f, 0x4f7f,
0x82, 0xd2, 0x6c, 0xee, 0x44, 0x45, 0x33, 0xe0);
#if CONFIG_FORMAT_S16LE #if CONFIG_FORMAT_S16LE
/** /**
* \brief Used to find nearest zero crossing frame for 16 bit format. * \brief Used to find nearest zero crossing frame for 16 bit format.
@ -215,16 +209,12 @@ static void vol_sync_host(struct comp_dev *dev, unsigned int num_channels)
/** /**
* \brief Ramps volume changes over time. * \brief Ramps volume changes over time.
* \param[in,out] data Volume base component device. * \param[in,out] dev Volume base component device.
* \param[in] delay Update time.
* \return Time until next work.
*/ */
static enum task_state vol_work(void *data) static void volume_ramp(struct comp_dev *dev)
{ {
struct comp_dev *dev = (struct comp_dev *)data;
struct comp_data *cd = comp_get_drvdata(dev); struct comp_data *cd = comp_get_drvdata(dev);
int32_t vol; int32_t vol;
int again = 0;
int i; int i;
/* No need to ramp in idle state, jump volume to request. */ /* No need to ramp in idle state, jump volume to request. */
@ -233,7 +223,8 @@ static enum task_state vol_work(void *data)
cd->volume[i] = cd->tvolume[i]; cd->volume[i] = cd->tvolume[i];
vol_sync_host(dev, PLATFORM_MAX_CHANNELS); vol_sync_host(dev, PLATFORM_MAX_CHANNELS);
return SOF_TASK_STATE_COMPLETED; cd->ramp_finished = true;
return;
} }
/* The first is set and cleared to indicate ongoing ramp, the /* The first is set and cleared to indicate ongoing ramp, the
@ -241,7 +232,6 @@ static enum task_state vol_work(void *data)
* in stream start. * in stream start.
*/ */
cd->vol_ramp_active = true; cd->vol_ramp_active = true;
cd->ramp_started = true;
/* inc/dec each volume if it's not at target for active channels */ /* inc/dec each volume if it's not at target for active channels */
for (i = 0; i < cd->channels; i++) { for (i = 0; i < cd->channels; i++) {
@ -259,9 +249,10 @@ static enum task_state vol_work(void *data)
if (vol >= cd->tvolume[i] || vol >= cd->vol_max) { if (vol >= cd->tvolume[i] || vol >= cd->vol_max) {
cd->ramp_increment[i] = 0; cd->ramp_increment[i] = 0;
cd->volume[i] = cd->tvolume[i]; cd->volume[i] = cd->tvolume[i];
cd->ramp_finished = true;
cd->vol_ramp_active = false;
} else { } else {
cd->volume[i] = vol; cd->volume[i] = vol;
again = 1;
} }
} else { } else {
/* ramp down */ /* ramp down */
@ -275,9 +266,10 @@ static enum task_state vol_work(void *data)
vol <= cd->vol_min) { vol <= cd->vol_min) {
cd->ramp_increment[i] = 0; cd->ramp_increment[i] = 0;
cd->volume[i] = cd->tvolume[i]; cd->volume[i] = cd->tvolume[i];
cd->ramp_finished = true;
cd->vol_ramp_active = false;
} else { } else {
cd->volume[i] = vol; cd->volume[i] = vol;
again = 1;
} }
} }
} }
@ -286,44 +278,6 @@ static enum task_state vol_work(void *data)
/* sync host with new value */ /* sync host with new value */
vol_sync_host(dev, cd->channels); vol_sync_host(dev, cd->channels);
/* do we need to continue ramping */
if (again)
return SOF_TASK_STATE_RESCHEDULE;
cd->vol_ramp_active = 0;
return SOF_TASK_STATE_COMPLETED;
}
/**
* \brief Allocates task of volume component.
* \param[in,out] dev Volume base component device.
* \return Error code.
*/
static int vol_task_init(struct comp_dev *dev)
{
struct comp_data *cd = comp_get_drvdata(dev);
int ret;
/* initialize task if necessary */
if (cd->volwork)
return 0;
cd->volwork = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM,
sizeof(*cd->volwork));
if (!cd->volwork)
return -ENOMEM;
ret = schedule_task_init_ll(cd->volwork, SOF_UUID(volume_task_uuid),
SOF_SCHEDULE_LL_TIMER,
SOF_TASK_PRI_MED, vol_work, dev,
cpu_get_id(), 0);
if (ret < 0) {
rfree(cd->volwork);
return ret;
}
return 0;
} }
/** /**
@ -426,12 +380,6 @@ static void volume_free(struct comp_dev *dev)
comp_dbg(dev, "volume_free()"); comp_dbg(dev, "volume_free()");
/* remove scheduling */
if (cd->volwork) {
schedule_task_free(cd->volwork);
rfree(cd->volwork);
}
rfree(cd); rfree(cd);
rfree(dev); rfree(dev);
} }
@ -480,6 +428,7 @@ static inline int volume_set_chan(struct comp_dev *dev, int chan,
/* Check ramp type */ /* Check ramp type */
switch (pga->ramp) { switch (pga->ramp) {
case SOF_VOLUME_LINEAR: case SOF_VOLUME_LINEAR:
case SOF_VOLUME_LINEAR_ZC:
/* Get volume transition delta and absolute value */ /* Get volume transition delta and absolute value */
delta = cd->tvolume[chan] - cd->volume[chan]; delta = cd->tvolume[chan] - cd->volume[chan];
delta_abs = ABS(delta); delta_abs = ABS(delta);
@ -524,7 +473,6 @@ static inline int volume_set_chan(struct comp_dev *dev, int chan,
cd->ramp_increment[chan]); cd->ramp_increment[chan]);
break; break;
case SOF_VOLUME_LOG: case SOF_VOLUME_LOG:
case SOF_VOLUME_LINEAR_ZC:
case SOF_VOLUME_LOG_ZC: case SOF_VOLUME_LOG_ZC:
default: default:
comp_err(dev, "volume_set_chan(): invalid ramp type %d", comp_err(dev, "volume_set_chan(): invalid ramp type %d",
@ -612,12 +560,8 @@ static int volume_ctrl_set_cmd(struct comp_dev *dev,
} }
if (!cd->vol_ramp_active) { if (!cd->vol_ramp_active) {
ret = vol_task_init(dev); cd->ramp_finished = false;
if (ret < 0) volume_ramp(dev);
return ret;
schedule_task(cd->volwork, VOL_RAMP_UPDATE_US,
VOL_RAMP_UPDATE_US);
} }
break; break;
@ -642,12 +586,8 @@ static int volume_ctrl_set_cmd(struct comp_dev *dev,
} }
if (!cd->vol_ramp_active) { if (!cd->vol_ramp_active) {
ret = vol_task_init(dev); cd->ramp_finished = false;
if (ret < 0) volume_ramp(dev);
return ret;
schedule_task(cd->volwork, VOL_RAMP_UPDATE_US,
VOL_RAMP_UPDATE_US);
} }
break; break;
@ -741,17 +681,19 @@ static int volume_trigger(struct comp_dev *dev, int cmd)
*/ */
static int volume_copy(struct comp_dev *dev) static int volume_copy(struct comp_dev *dev)
{ {
struct sof_ipc_comp_volume *pga =
COMP_GET_IPC(dev, sof_ipc_comp_volume);
struct comp_copy_limits c; struct comp_copy_limits c;
struct comp_data *cd = comp_get_drvdata(dev); struct comp_data *cd = comp_get_drvdata(dev);
struct comp_buffer *source; struct comp_buffer *source;
struct comp_buffer *sink; struct comp_buffer *sink;
uint32_t source_bytes;
uint32_t sink_bytes;
uint32_t frames;
int64_t prev_sum = 0;
comp_dbg(dev, "volume_copy()"); comp_dbg(dev, "volume_copy()");
if (!cd->ramp_started)
schedule_task(cd->volwork, VOL_RAMP_UPDATE_US,
VOL_RAMP_UPDATE_US);
source = list_first_item(&dev->bsource_list, struct comp_buffer, source = list_first_item(&dev->bsource_list, struct comp_buffer,
sink_list); sink_list);
sink = list_first_item(&dev->bsink_list, struct comp_buffer, sink = list_first_item(&dev->bsink_list, struct comp_buffer,
@ -763,14 +705,36 @@ static int volume_copy(struct comp_dev *dev)
comp_dbg(dev, "volume_copy(), source_bytes = 0x%x, sink_bytes = 0x%x", comp_dbg(dev, "volume_copy(), source_bytes = 0x%x, sink_bytes = 0x%x",
c.source_bytes, c.sink_bytes); c.source_bytes, c.sink_bytes);
while (c.frames) {
if (cd->ramp_finished || cd->vol_ramp_frames > c.frames) {
/* without ramping process all at once */
frames = c.frames;
} else if (pga->ramp == SOF_VOLUME_LINEAR_ZC) {
/* with ZC ramping look for next ZC offset */
frames = cd->zc_get(&source->stream,
cd->vol_ramp_frames, &prev_sum);
} else {
/* without ZC process max ramp chunk */
frames = cd->vol_ramp_frames;
}
source_bytes = frames * c.source_frame_bytes;
sink_bytes = frames * c.sink_frame_bytes;
/* copy and scale volume */ /* copy and scale volume */
buffer_invalidate(source, c.source_bytes); buffer_invalidate(source, source_bytes);
cd->scale_vol(dev, &sink->stream, &source->stream, c.frames); cd->scale_vol(dev, &sink->stream, &source->stream, frames);
buffer_writeback(sink, c.sink_bytes); buffer_writeback(sink, sink_bytes);
/* calculate new free and available */ /* calculate new free and available */
comp_update_buffer_produce(sink, c.sink_bytes); comp_update_buffer_produce(sink, sink_bytes);
comp_update_buffer_consume(source, c.source_bytes); comp_update_buffer_consume(source, source_bytes);
if (!cd->ramp_finished)
volume_ramp(dev);
c.frames -= frames;
}
return 0; return 0;
} }
@ -856,22 +820,21 @@ static int volume_prepare(struct comp_dev *dev)
vol_sync_host(dev, PLATFORM_MAX_CHANNELS); vol_sync_host(dev, PLATFORM_MAX_CHANNELS);
/* Set current volume to min to ensure ramp starts from minimum /* Set current volume to min to ensure ramp starts from minimum
* to previous volume request. Copy() checks for ramp started * to previous volume request. Copy() checks for ramp finished
* and schedules it if it has not yet started as result of * and executes it if it has not yet finished as result of
* driver commands. Ramp is not constant rate to ensure it lasts * driver commands. Ramp is not constant rate to ensure it lasts
* for entire topology specified time. * for entire topology specified time.
*/ */
cd->ramp_started = false; cd->ramp_finished = true;
cd->vol_ramp_frames = dev->frames / (dev->period / VOL_RAMP_UPDATE_US);
cd->channels = sinkb->stream.channels; cd->channels = sinkb->stream.channels;
for (i = 0; i < cd->channels; i++) { for (i = 0; i < cd->channels; i++) {
cd->volume[i] = cd->vol_min; cd->volume[i] = cd->vol_min;
volume_set_chan(dev, i, cd->tvolume[i], false); volume_set_chan(dev, i, cd->tvolume[i], false);
if (cd->volume[i] != cd->tvolume[i])
cd->ramp_finished = false;
} }
ret = vol_task_init(dev);
if (ret < 0)
return ret;
return 0; return 0;
err: err:

View File

@ -19,7 +19,6 @@
#include <sof/audio/component.h> #include <sof/audio/component.h>
#include <sof/bit.h> #include <sof/bit.h>
#include <sof/common.h> #include <sof/common.h>
#include <sof/schedule/task.h>
#include <sof/trace/trace.h> #include <sof/trace/trace.h>
#include <ipc/stream.h> #include <ipc/stream.h>
#include <user/trace.h> #include <user/trace.h>
@ -95,7 +94,6 @@ typedef uint32_t (*vol_zc_func)(const struct audio_stream *source,
* Gain amplitude value is between 0 (mute) ... 2^16 (0dB) ... 2^24 (~+48dB). * Gain amplitude value is between 0 (mute) ... 2^16 (0dB) ... 2^24 (~+48dB).
*/ */
struct comp_data { struct comp_data {
struct task *volwork; /**< volume scheduled work function */
struct sof_ipc_ctrl_value_chan *hvol; /**< host volume readback */ struct sof_ipc_ctrl_value_chan *hvol; /**< host volume readback */
int32_t volume[SOF_IPC_MAX_CHANNELS]; /**< current volume */ int32_t volume[SOF_IPC_MAX_CHANNELS]; /**< current volume */
int32_t tvolume[SOF_IPC_MAX_CHANNELS]; /**< target volume */ int32_t tvolume[SOF_IPC_MAX_CHANNELS]; /**< target volume */
@ -104,10 +102,12 @@ struct comp_data {
int32_t vol_min; /**< minimum volume */ int32_t vol_min; /**< minimum volume */
int32_t vol_max; /**< maximum volume */ int32_t vol_max; /**< maximum volume */
int32_t vol_ramp_range; /**< max ramp transition */ int32_t vol_ramp_range; /**< max ramp transition */
/**< max number of frames to process per ramp transition */
uint32_t vol_ramp_frames;
unsigned int channels; /**< current channels count */ unsigned int channels; /**< current channels count */
bool muted[SOF_IPC_MAX_CHANNELS]; /**< set if channel is muted */ bool muted[SOF_IPC_MAX_CHANNELS]; /**< set if channel is muted */
bool vol_ramp_active; /**< set if volume is ramped */ bool vol_ramp_active; /**< set if volume is ramped */
bool ramp_started; /**< control ramp launch */ bool ramp_finished; /**< control ramp launch */
vol_scale_func scale_vol; /**< volume processing function */ vol_scale_func scale_vol; /**< volume processing function */
vol_zc_func zc_get; /**< function getting nearest zero crossing frame */ vol_zc_func zc_get; /**< function getting nearest zero crossing frame */
}; };