[Sound-open-firmware] [PATCH] volume: fix copy size incorrect issue

Keyon Jie yang.jie at linux.intel.com
Thu Nov 16 16:04:18 CET 2017


The copy sizes for src and sink may be different,
here add fix to handle it.

Signed-off-by: Keyon Jie <yang.jie at linux.intel.com>
---
 src/audio/volume.c              | 38 +++++++++++++++++++++++++++++---------
 src/include/reef/audio/buffer.h | 19 +++++++++++++++++++
 2 files changed, 48 insertions(+), 9 deletions(-)

diff --git a/src/audio/volume.c b/src/audio/volume.c
index 415a853..9cf766b 100644
--- a/src/audio/volume.c
+++ b/src/audio/volume.c
@@ -535,13 +535,27 @@ static int volume_cmd(struct comp_dev *dev, int cmd, void *data)
 	}
 }
 
+static uint32_t get_frame_bytes(enum sof_ipc_frame frame_fmt, uint32_t chan)
+{
+	switch (frame_fmt) {
+	case SOF_IPC_FRAME_S16_LE:
+		return 2 * chan;
+	case SOF_IPC_FRAME_S24_4LE:
+	case SOF_IPC_FRAME_S32_LE:
+		return 4 * chan;
+	default:
+		return 0;
+	}
+}
+
 /* copy and process stream data from source to sink buffers */
 static int volume_copy(struct comp_dev *dev)
 {
 	struct comp_data *cd = comp_get_drvdata(dev);
 	struct comp_buffer *sink;
 	struct comp_buffer *source;
-	uint32_t copy_bytes;
+	uint32_t copy_src_bytes, copy_sink_bytes;
+	uint32_t copy_frames, src_frame_bytes, sink_frame_bytes;
 
 	tracev_volume("cpy");
 
@@ -549,16 +563,22 @@ static int volume_copy(struct comp_dev *dev)
 	source = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list);
 	sink = list_first_item(&dev->bsink_list, struct comp_buffer, source_list);
 
+	src_frame_bytes = get_frame_bytes(cd->source_format, dev->params.channels);
+	sink_frame_bytes = get_frame_bytes(cd->sink_format, dev->params.channels);
+
 	/* get max number of bytes that can be copied */
-	copy_bytes = comp_buffer_get_copy_bytes(dev, source, sink);
+	copy_frames = comp_buffer_get_copy_frames(source, src_frame_bytes,
+					sink, sink_frame_bytes);
+	copy_src_bytes = copy_frames * src_frame_bytes;
+	copy_sink_bytes = copy_frames * sink_frame_bytes;
 
 	/* Run volume if buffers have enough room */
-	if (copy_bytes < cd->source_period_bytes) {
-		comp_underrun(dev, source, copy_bytes, cd->source_period_bytes);
+	if (copy_src_bytes < cd->source_period_bytes) {
+		comp_underrun(dev, source, copy_src_bytes, cd->source_period_bytes);
 		return 0;
 	}
-	if (copy_bytes < cd->sink_period_bytes) {
-		comp_overrun(dev, sink, copy_bytes, cd->sink_period_bytes);
+	if (copy_sink_bytes < cd->sink_period_bytes) {
+		comp_overrun(dev, sink, copy_sink_bytes, cd->sink_period_bytes);
 		return 0;
 	}
 
@@ -566,10 +586,10 @@ static int volume_copy(struct comp_dev *dev)
 	cd->scale_vol(dev, sink, source, dev->frames);
 
 	/* calc new free and available */
-	comp_update_buffer_produce(sink, cd->sink_period_bytes);
-	comp_update_buffer_consume(source, cd->source_period_bytes);
+	comp_update_buffer_produce(sink, copy_sink_bytes);
+	comp_update_buffer_consume(source, copy_src_bytes);
 
-	return dev->frames;
+	return copy_frames;
 }
 
 /*
diff --git a/src/include/reef/audio/buffer.h b/src/include/reef/audio/buffer.h
index d1d0869..45aa3ce 100644
--- a/src/include/reef/audio/buffer.h
+++ b/src/include/reef/audio/buffer.h
@@ -164,6 +164,25 @@ static inline uint32_t comp_buffer_get_copy_bytes(struct comp_dev *dev,
 	return copy_bytes;
 }
 
+/* get the max number of frames that can be copied between sink and source */
+static inline uint32_t comp_buffer_get_copy_frames
+	(struct comp_buffer *source, uint32_t source_frame_bytes,
+	struct comp_buffer *sink, uint32_t sink_frame_bytes)
+{
+	uint32_t copy_frames, src_avail_frames, sink_free_frames;
+
+	src_avail_frames = source->avail / source_frame_bytes;
+	sink_free_frames = sink->free / sink_frame_bytes;
+
+	/* Check that source has enough frames available and sink
+	 * has enough free frames.
+	 */
+	copy_frames = src_avail_frames > sink_free_frames ?
+		sink_free_frames : src_avail_frames;
+
+	return copy_frames;
+}
+
 static inline void buffer_reset_pos(struct comp_buffer *buffer)
 {
 	buffer->r_ptr = buffer->addr;
-- 
2.11.0



More information about the Sound-open-firmware mailing list