mirror of https://github.com/thesofproject/sof.git
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:
parent
0a82b71a5b
commit
1b57609a1e
|
@ -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:
|
||||||
|
|
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue