[alsa-devel] [PATCH - alsa-lib 1/4] pcm_file: add support for infile reading in non interleaved mode

Adam Miartus amiartus at de.adit-jv.com
Tue May 21 13:47:14 CEST 2019


add helper function to copy input file data to buffer mapped by areas,
in case of an error, do not fill the areas, allowing device read buffer
to be provided to api caller

previously unused rbuf variable is reused for this purpose

Signed-off-by: Adam Miartus <amiartus at de.adit-jv.com>
Reviewed-by: Timo Wischer <twischer at de.adit-jv.com>

diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c
index 3a19cef..3c68265 100644
--- a/src/pcm/pcm_file.c
+++ b/src/pcm/pcm_file.c
@@ -77,6 +77,7 @@ typedef struct {
 	snd_pcm_uframes_t appl_ptr;
 	snd_pcm_uframes_t file_ptr_bytes;
 	snd_pcm_uframes_t wbuf_size;
+	snd_pcm_uframes_t rbuf_size;
 	size_t wbuf_size_bytes;
 	size_t wbuf_used_bytes;
 	char *wbuf;
@@ -266,6 +267,39 @@ static int snd_pcm_file_open_output_file(snd_pcm_file_t *file)
 	return 0;
 }
 
+/* fill areas with data from input file, return bytes red */
+static int snd_pcm_file_areas_read_infile(snd_pcm_t *pcm,
+					  const snd_pcm_channel_area_t *areas,
+					  snd_pcm_uframes_t offset,
+					  snd_pcm_uframes_t frames)
+{
+	snd_pcm_file_t *file = pcm->private_data;
+	snd_pcm_channel_area_t areas_if[pcm->channels];
+	ssize_t bytes;
+
+	if (file->ifd < 0)
+		return -EBADF;
+
+	if (file->rbuf == NULL)
+		return -ENOMEM;
+
+	if (file->rbuf_size < frames) {
+		SYSERR("requested more frames than pcm buffer");
+		return -ENOMEM;
+	}
+
+	bytes = read(file->ifd, file->rbuf, snd_pcm_frames_to_bytes(pcm, frames));
+	if (bytes < 0) {
+		SYSERR("read from file failed, error: %d", bytes);
+		return bytes;
+	}
+
+	snd_pcm_areas_from_buf(pcm, areas_if, file->rbuf);
+	snd_pcm_areas_copy(areas, offset, areas_if, 0, pcm->channels, snd_pcm_bytes_to_frames(pcm, bytes), pcm->format);
+
+	return bytes;
+}
+
 static void setup_wav_header(snd_pcm_t *pcm, struct wav_fmt *fmt)
 {
 	fmt->fmt = TO_LE16(0x01);
@@ -568,19 +602,19 @@ static snd_pcm_sframes_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, snd_pcm
 {
 	snd_pcm_file_t *file = pcm->private_data;
 	snd_pcm_channel_area_t areas[pcm->channels];
-	snd_pcm_sframes_t n;
+	snd_pcm_sframes_t frames;
 
-	if (file->ifd >= 0) {
-		SNDERR("DEBUG: Noninterleaved read not yet implemented.\n");
-		return 0;	/* TODO: Noninterleaved read */
-	}
+	__snd_pcm_lock(pcm);
+	frames = _snd_pcm_readn(file->gen.slave, bufs, size);
+	if (frames <= 0)
+		return frames;
 
-	n = _snd_pcm_readn(file->gen.slave, bufs, size);
-	if (n > 0) {
-		snd_pcm_areas_from_bufs(pcm, areas, bufs);
-		snd_pcm_file_add_frames(pcm, areas, 0, n);
-	}
-	return n;
+	snd_pcm_areas_from_bufs(pcm, areas, bufs);
+	snd_pcm_file_areas_read_infile(pcm, areas, 0, frames);
+	snd_pcm_file_add_frames(pcm, areas, 0, frames);
+
+	__snd_pcm_unlock(pcm);
+	return frames;
 }
 
 static snd_pcm_sframes_t snd_pcm_file_mmap_commit(snd_pcm_t *pcm,
@@ -609,9 +643,11 @@ static int snd_pcm_file_hw_free(snd_pcm_t *pcm)
 	free(file->wbuf);
 	free(file->wbuf_areas);
 	free(file->final_fname);
+	free(file->rbuf);
 	file->wbuf = NULL;
 	file->wbuf_areas = NULL;
 	file->final_fname = NULL;
+	file->rbuf = NULL;
 	return snd_pcm_hw_free(file->gen.slave);
 }
 
@@ -638,6 +674,15 @@ static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 		snd_pcm_file_hw_free(pcm);
 		return -ENOMEM;
 	}
+	assert(!file->rbuf);
+	file->rbuf_size = slave->buffer_size;
+	file->rbuf_size_bytes = snd_pcm_frames_to_bytes(slave, file->rbuf_size);
+	file->rbuf_used_bytes = 0;
+	file->rbuf = malloc(file->rbuf_size_bytes);
+	if (file->rbuf == NULL) {
+		snd_pcm_file_hw_free(pcm);
+		return -ENOMEM;
+	}
 	file->appl_ptr = file->file_ptr_bytes = 0;
 	for (channel = 0; channel < slave->channels; ++channel) {
 		snd_pcm_channel_area_t *a = &file->wbuf_areas[channel];
-- 
2.7.4



More information about the Alsa-devel mailing list