All of lore.kernel.org
 help / color / mirror / Atom feed
* PCM parameters in file plugin
@ 2009-01-05 20:54 Pavel Hofman
  2009-01-06  9:51 ` Pavel Hofman
  0 siblings, 1 reply; 11+ messages in thread
From: Pavel Hofman @ 2009-01-05 20:54 UTC (permalink / raw)
  To: alsa-devel

Hello,

I am working on a file plugin patch to allow adding PCM parameters 
(rate, format) to  the name of the file created (plus the ability to run 
an external command via popen, such as upsampling with sox). I got stuck 
in trying to obtain these parameters in pcm_file.c:_snd_pcm_file_open(). 
Is it actually possible or the information is not available at the time 
of opening the file (and the whole patch is thus nonsense)?

Thanks a lot for help.

Pavel.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: PCM parameters in file plugin
  2009-01-05 20:54 PCM parameters in file plugin Pavel Hofman
@ 2009-01-06  9:51 ` Pavel Hofman
  2009-01-06 10:31   ` Jaroslav Kysela
  0 siblings, 1 reply; 11+ messages in thread
From: Pavel Hofman @ 2009-01-06  9:51 UTC (permalink / raw)
  To: alsa-devel

Pavel Hofman napsal(a):
> Hello,
> 
> I am working on a file plugin patch to allow adding PCM parameters 
> (rate, format) to  the name of the file created (plus the ability to run 
> an external command via popen, such as upsampling with sox). I got stuck 
> in trying to obtain these parameters in pcm_file.c:_snd_pcm_file_open(). 
> Is it actually possible or the information is not available at the time 
> of opening the file (and the whole patch is thus nonsense)?
> 
> Thanks a lot for help.
> 

I am now opening the output file in pcm_file.c:snd_pcm_file_write_bytes.
Surprisingly it seems to work fine. Could such hack be accepted as a
patch to the plugin (if coded properly)? Is there a better place to open 
the file?

Thanks,

Pavel.


-- 
-----------------

inSITE, s.r.o.

Rubesova 29, 326 00 Plzen
Tel. +420 377 449 358
Fax  +420 222 745 553
GSM: +420 603 163 973
Email: pavel.hofman@insite.cz

www.educity.cz, www.jobcity.cz
www.meetings.cz, www.hrzive.cz
www.comben.cz, www.insite.cz

-------------------------------
Navstivte www.educity.cz, server
s nejvetsi nabidkou profesniho
vzdelavani na ceskem internetu.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: PCM parameters in file plugin
  2009-01-06  9:51 ` Pavel Hofman
@ 2009-01-06 10:31   ` Jaroslav Kysela
  2009-01-06 11:33     ` Pavel Hofman
  0 siblings, 1 reply; 11+ messages in thread
From: Jaroslav Kysela @ 2009-01-06 10:31 UTC (permalink / raw)
  To: Pavel Hofman; +Cc: alsa-devel

On Tue, 6 Jan 2009, Pavel Hofman wrote:

> Pavel Hofman napsal(a):
> > Hello,
> > 
> > I am working on a file plugin patch to allow adding PCM parameters 
> > (rate, format) to  the name of the file created (plus the ability to run 
> > an external command via popen, such as upsampling with sox). I got stuck 
> > in trying to obtain these parameters in pcm_file.c:_snd_pcm_file_open(). 
> > Is it actually possible or the information is not available at the time 
> > of opening the file (and the whole patch is thus nonsense)?
> > 
> > Thanks a lot for help.
> > 
> 
> I am now opening the output file in pcm_file.c:snd_pcm_file_write_bytes.
> Surprisingly it seems to work fine. Could such hack be accepted as a
> patch to the plugin (if coded properly)? Is there a better place to open 
> the file?

The file should be opened in the hw_params callback (all PCM parameters 
are known in this time). Also, extending filename with PCM parameters 
should be optional (configurable). But the idea looks nice.

						Jaroslav

-----
Jaroslav Kysela <perex@perex.cz>
Linux Kernel Sound Maintainer
ALSA Project, Red Hat, Inc.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: PCM parameters in file plugin
  2009-01-06 10:31   ` Jaroslav Kysela
@ 2009-01-06 11:33     ` Pavel Hofman
  2009-01-19 22:20       ` [PATCH] " Pavel Hofman
  0 siblings, 1 reply; 11+ messages in thread
From: Pavel Hofman @ 2009-01-06 11:33 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: alsa-devel

[-- Attachment #1: Type: text/plain, Size: 1800 bytes --]

Jaroslav Kysela wrote:
> On Tue, 6 Jan 2009, Pavel Hofman wrote:
> 
>> Pavel Hofman napsal(a):
>>> Hello,
>>>
>>> I am working on a file plugin patch to allow adding PCM parameters 
>>> (rate, format) to  the name of the file created (plus the ability to run 
>>> an external command via popen, such as upsampling with sox). I got stuck 
>>> in trying to obtain these parameters in pcm_file.c:_snd_pcm_file_open(). 
>>> Is it actually possible or the information is not available at the time 
>>> of opening the file (and the whole patch is thus nonsense)?
>>>
>>> Thanks a lot for help.
>>>
>> I am now opening the output file in pcm_file.c:snd_pcm_file_write_bytes.
>> Surprisingly it seems to work fine. Could such hack be accepted as a
>> patch to the plugin (if coded properly)? Is there a better place to open 
>> the file?
> 
> The file should be opened in the hw_params callback (all PCM parameters 
> are known in this time). Also, extending filename with PCM parameters 
> should be optional (configurable). But the idea looks nice.
> 
> 						Jaroslav


Hi,

Thanks a lot for your hint. Here is a preliminary version of the patch 
for review (no docs updated, no clean formatting).

The changes are moving the opening of output file to hw_params callback, 
support for replacement codes in the file parameter,  and support for 
piping to external commands when the file parameter starts with |.

This is a working ".asoundrc on steroids" (upsampling to 96kHz using the 
quality algorithm of sox)

pcm.raw {
          type file
          slave {
                  pcm null
          }
          format "raw"
          file "| sox -V -c %c -%b -r %r -s -t raw - -t raw -4 - rate -v 
-s 96000 | aplay -v -t raw -r 96000 -c %c -f S32_LE -Dhw:0"
}

Thanks a lot for comments.

Regards,

Pavel.

[-- Attachment #2: pcm_file.c.patch --]
[-- Type: text/x-diff, Size: 9485 bytes --]

diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c
index 82823a0..df2ee0e 100644
--- a/src/pcm/pcm_file.c
+++ b/src/pcm/pcm_file.c
@@ -29,6 +29,7 @@
 #include <endian.h>
 #include <byteswap.h>
 #include <ctype.h>
+#include <string.h>
 #include "pcm_local.h"
 #include "pcm_plugin.h"
 
@@ -39,6 +40,21 @@ const char *_snd_module_pcm_file = "";
 
 #ifndef DOC_HIDDEN
 
+#define RATE_KEY "%r"
+#define CHANNELS_KEY "%c"
+#define BWIDTH_KEY "%b"
+#define FORMAT_KEY "%f"
+#define DECIMAL_INT_LEN 7
+
+static const char* keys[] = {
+	RATE_KEY,
+	CHANNELS_KEY,
+	BWIDTH_KEY,
+	FORMAT_KEY,
+};
+
+#define NUM_OF(x) (sizeof (x) / sizeof *(x))
+
 typedef enum _snd_pcm_file_format {
 	SND_PCM_FILE_FORMAT_RAW,
 	SND_PCM_FILE_FORMAT_WAV
@@ -57,6 +73,9 @@ struct wav_fmt {
 typedef struct {
 	snd_pcm_generic_t gen;
 	char *fname;
+	char *final_fname;
+	int trunc;
+	int perm;
 	int fd;
 	char *ifname;
 	int ifd;
@@ -84,6 +103,198 @@ typedef struct {
 #define TO_LE16(x)	bswap_16(x)
 #endif
 
+/* old_string MUST contain key! */
+int snd_pcm_file_replace_key(char *old_string, char *key, char *value, char **newstring_p)
+{
+	int str_index, newstr_index, key_index, end, new_len, old_len, cpy_len, first_key_index;
+	char *c, *first_c, *newstring;
+	int keys_count;
+
+	first_c = c = (char *) strstr(old_string, key);
+	new_len        = strlen(value);
+	old_len        = strlen(key);
+	end            = strlen(old_string)   - old_len;
+	first_key_index = key_index = c - old_string;
+
+	/* first run - finding nb of keys for calculating allocation size */
+	str_index = 0;
+	keys_count = 0;
+	while(str_index <= end && c != NULL)
+	{
+		keys_count ++;
+		str_index    = key_index + old_len;
+		/* Check for another pattern match */
+		if((c = (char *) strstr(old_string+str_index, key)) != NULL)
+			key_index = c - old_string;
+	}
+	/* now we can allocate exactly the right size */
+	newstring = malloc(strlen(old_string) + keys_count*(new_len - old_len) + 1);
+	if (!newstring)
+		return -ENOMEM;		
+	/* second run - actually replacing */
+	str_index = 0;
+	newstr_index = 0;
+	key_index = first_key_index;
+	c = first_c;
+	while(str_index <= end && c != NULL)
+	{
+		/* Copy characters from the left of matched pattern occurence */
+		cpy_len = key_index-str_index;
+		strncpy(newstring+newstr_index, old_string+str_index, cpy_len);
+		newstr_index += cpy_len;
+		str_index    += cpy_len;
+
+		/* Copy replacement characters instead of matched pattern */
+		strcpy(newstring+newstr_index, value);
+		newstr_index += new_len;
+		str_index    += old_len;
+
+		/* Check for another pattern match */
+		if((c = (char *) strstr(old_string+str_index, key)) != NULL)
+			key_index = c - old_string;
+	}
+	/* Copy remaining characters from the right of last matched pattern */
+	strcpy(newstring+newstr_index, old_string+str_index);
+	*(newstring_p) = newstring;
+	return 0;
+} 
+
+int snd_pcm_file_replace_fname(snd_pcm_file_t *file, char ** new_fname_p) 
+{
+	char* value;
+	char* old_fname = NULL;
+	int err;
+	char* fname = file->fname;
+	snd_pcm_t *pcm = file->gen.slave;
+
+	value = malloc(DECIMAL_INT_LEN);
+	if (! value) {
+		return -ENOMEM;
+	}
+	/* we want to keep fname, const */
+	old_fname = *(new_fname_p) = fname;
+
+	if (strstr(old_fname, RATE_KEY)) {
+		sprintf(value, "%d", pcm->rate);
+		err = snd_pcm_file_replace_key(old_fname, RATE_KEY, value, new_fname_p);
+		/* fname must not be freed */
+		if (old_fname != fname)
+			free(old_fname);
+		old_fname = *(new_fname_p);
+		if (err < 0)
+			return err;
+	}
+	if (strstr(old_fname, CHANNELS_KEY)) {
+		sprintf(value, "%d", pcm->channels);
+		err = snd_pcm_file_replace_key(old_fname, CHANNELS_KEY, value, new_fname_p);
+		if (old_fname != fname)
+			free(old_fname);
+		old_fname = *(new_fname_p);
+		if (err < 0)
+			return err;
+	}
+	if (strstr(old_fname, BWIDTH_KEY)) {
+		sprintf(value, "%d", pcm->frame_bits / (8 * pcm->channels));
+		err = snd_pcm_file_replace_key(old_fname, BWIDTH_KEY, value, new_fname_p);
+		if (old_fname != fname)
+			free(old_fname);
+		old_fname = *(new_fname_p);
+		if (err < 0)
+			return err;
+	}
+	if (strstr(old_fname, FORMAT_KEY)) {
+		sprintf(value, "%d", pcm->format);
+		err = snd_pcm_file_replace_key(old_fname, FORMAT_KEY, value, new_fname_p);
+		if (old_fname != fname)
+			free(old_fname);
+		old_fname = *(new_fname_p);
+		if (err < 0)
+			return err;
+	}
+	
+	free(value);
+	return 0;
+
+}
+
+int snd_pcm_file_has_keys(char* string)
+{
+	int i, n;
+
+	n = NUM_OF(keys);
+	for (i = 0; i < n; ++i) {
+		if (strstr(string, keys[i]) != NULL)
+			return 1;
+	}
+	/* none found */
+	return 0;
+}
+
+int snd_pcm_file_open_output_file(snd_pcm_file_t *file)
+{
+	int err, fd;
+
+	/* fname can contain keys, generating final_fname */
+	if (snd_pcm_file_has_keys(file->fname)) {
+		err = snd_pcm_file_replace_fname(file, &(file->final_fname));
+		if (err < 0)
+			return err;
+		/*printf("DEBUG - original fname: %s, final fname: %s\n", file->fname, file->final_fname);*/
+	}
+	else {
+		/* no changes */
+		file->final_fname = malloc(strlen(file->fname) + 1);
+		if (! file->final_fname)
+			return -ENOMEM;
+		strcpy(file->final_fname, file->fname);
+	}
+
+	if (file->final_fname[0] == '|') {
+		/* pipe mode */
+		FILE * pipe;
+		/* clearing */
+		file->final_fname[0] = ' ';
+		pipe = popen(file->final_fname, "w");
+		if (! pipe) {
+			SYSERR("running %s for writing failed", file->final_fname);
+			return -errno;
+		}
+		fd = fileno(pipe);
+	}
+	else {
+		if (file->trunc)
+			fd = open(file->final_fname, O_WRONLY|O_CREAT|O_TRUNC, file->perm);
+		else {
+			fd = open(file->final_fname, O_WRONLY|O_CREAT|O_EXCL, file->perm);
+			if (fd < 0) {
+				char *tmpfname = NULL;
+				int idx, len;
+				len = strlen(file->final_fname) + 6;
+				tmpfname = malloc(len);
+				if (!tmpfname)
+					return -ENOMEM;
+				for (idx = 1; idx < 10000; idx++) {
+					snprintf(tmpfname, len,
+							"%s.%04d",file->final_fname, idx);
+					fd = open(tmpfname, O_WRONLY|O_CREAT|O_EXCL, file->perm);
+					if (fd >= 0) {
+						free(file->final_fname);
+						file->final_fname = tmpfname;
+						break;
+					}
+				}
+				if (fd < 0) {
+					SYSERR("open %s for writing failed", file->final_fname);
+					free(tmpfname);
+					return -errno;
+				}
+			}
+		}
+	}
+	file->fd = fd;
+	return 0;
+}
+
 static void setup_wav_header(snd_pcm_t *pcm, struct wav_fmt *fmt)
 {
 	fmt->fmt = TO_LE16(0x01);
@@ -152,6 +363,8 @@ static void fixup_wav_header(snd_pcm_t *pcm)
 }
 #endif /* DOC_HIDDEN */
 
+
+
 static void snd_pcm_file_write_bytes(snd_pcm_t *pcm, size_t bytes)
 {
 	snd_pcm_file_t *file = pcm->private_data;
@@ -442,6 +655,13 @@ static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 		a->first = slave->sample_bits * channel;
 		a->step = slave->frame_bits;
 	}
+	if (file->fd < 0) {
+		err = snd_pcm_file_open_output_file(file);
+		if (err < 0) {
+			SYSERR("failed opening output file %s", file->fname);
+			return err;
+		}
+	}
 	return 0;
 }
 
@@ -452,6 +672,9 @@ static void snd_pcm_file_dump(snd_pcm_t *pcm, snd_output_t *out)
 		snd_output_printf(out, "File PCM (file=%s)\n", file->fname);
 	else
 		snd_output_printf(out, "File PCM (fd=%d)\n", file->fd);
+	if (file->final_fname)
+		snd_output_printf(out, "Final file PCM (file=%s)\n", file->final_fname);
+
 	if (pcm->setup) {
 		snd_output_printf(out, "Its setup is:\n");
 		snd_pcm_dump_setup(pcm, out);
@@ -533,7 +756,6 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 	snd_pcm_file_t *file;
 	snd_pcm_file_format_t format;
 	struct timespec timespec;
-	char *tmpname = NULL;
 	int err;
 
 	assert(pcmp);
@@ -546,58 +768,26 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 		SNDERR("file format %s is unknown", fmt);
 		return -EINVAL;
 	}
-	if (fname) {
-		if (trunc)
-			fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, perm);
-		else {
-			fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, perm);
-			if (fd < 0) {
-				int idx, len;
-				len = strlen(fname) + 6;
-				tmpname = malloc(len);
-				if (!tmpname)
-					return -ENOMEM;
-				for (idx = 1; idx < 10000; idx++) {
-					snprintf(tmpname, len,
-						 "%s.%04d", fname, idx);
-					fd = open(tmpname, O_WRONLY|O_CREAT|O_EXCL, perm);
-					if (fd >= 0) {
-						fname = tmpname;
-						break;
-					}
-				}
-			}
-		}
-		if (fd < 0) {
-			SYSERR("open %s for writing failed", fname);
-			free(tmpname);
-			return -errno;
-		}
-	}
 	file = calloc(1, sizeof(snd_pcm_file_t));
 	if (!file) {
-		if (fname)
-			close(fd);
-		free(tmpname);
 		return -ENOMEM;
 	}
 
+	/* opening output fname is delayed until writing, when PCM params are known */
+	if (fname)
+		file->fname = strdup(fname);
+	file->trunc = trunc;
+	file->perm = perm;
+
 	if (ifname) {
 		ifd = open(ifname, O_RDONLY);	/* TODO: mind blocking mode */
 		if (ifd < 0) {
 			SYSERR("open %s for reading failed", ifname);
-			if (fname)
-				close(fd);
 			free(file);
-			free(tmpname);
 			return -errno;
 		}
-	}
-
-	if (fname)
-		file->fname = strdup(fname);
-	if (ifname)
 		file->ifname = strdup(ifname);
+	}
 	file->fd = fd;
 	file->ifd = ifd;
 	file->format = format;
@@ -608,7 +798,6 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 	if (err < 0) {
 		free(file->fname);
 		free(file);
-		free(tmpname);
 		return err;
 	}
 	pcm->ops = &snd_pcm_file_ops;
@@ -625,8 +814,6 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 	snd_pcm_link_hw_ptr(pcm, slave);
 	snd_pcm_link_appl_ptr(pcm, slave);
 	*pcmp = pcm;
-
-	free(tmpname);
 	return 0;
 }
 

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] PCM parameters in file plugin
  2009-01-06 11:33     ` Pavel Hofman
@ 2009-01-19 22:20       ` Pavel Hofman
  2009-01-26 14:28         ` Pavel Hofman
  2009-01-28 15:41         ` Takashi Iwai
  0 siblings, 2 replies; 11+ messages in thread
From: Pavel Hofman @ 2009-01-19 22:20 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: alsa-devel

[-- Attachment #1: Type: text/plain, Size: 1514 bytes --]

Pavel Hofman wrote:
> Jaroslav Kysela wrote:
>> On Tue, 6 Jan 2009, Pavel Hofman wrote:
>>
>>> Pavel Hofman napsal(a):
>>>> Hello,
>>>>
>>>> I am working on a file plugin patch to allow adding PCM parameters 
>>>> (rate, format) to  the name of the file created (plus the ability to 
>>>> run an external command via popen, such as upsampling with sox). I 
>>>> got stuck in trying to obtain these parameters in 
>>>> pcm_file.c:_snd_pcm_file_open(). Is it actually possible or the 
>>>> information is not available at the time of opening the file (and 
>>>> the whole patch is thus nonsense)?
>>>>
>>>> Thanks a lot for help.
>>>>
>>> I am now opening the output file in pcm_file.c:snd_pcm_file_write_bytes.
>>> Surprisingly it seems to work fine. Could such hack be accepted as a
>>> patch to the plugin (if coded properly)? Is there a better place to 
>>> open the file?
>>
>> The file should be opened in the hw_params callback (all PCM 
>> parameters are known in this time). Also, extending filename with PCM 
>> parameters should be optional (configurable). But the idea looks nice.
>>
>>                         Jaroslav
> 

Hello,

please find enclosed a patch for the file plugin. The
checkpatch.pl script throws 5 bogus errors in doxygen comments.

Signed-off-by: Pavel Hofman <pavel.hofman@insite.cz>

* added support for including pcm stream params in the output filename
* added support for piping the stream to a shell command if the filename
string starts with a pipe char

Thanks a lot,

Pavel.


[-- Attachment #2: pcm_file.c.diff --]
[-- Type: text/x-patch, Size: 10892 bytes --]

diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c
index 82823a0..40f9760 100644
--- a/src/pcm/pcm_file.c
+++ b/src/pcm/pcm_file.c
@@ -29,6 +29,7 @@
 #include <endian.h>
 #include <byteswap.h>
 #include <ctype.h>
+#include <string.h>
 #include "pcm_local.h"
 #include "pcm_plugin.h"
 
@@ -39,6 +40,24 @@ const char *_snd_module_pcm_file = "";
 
 #ifndef DOC_HIDDEN
 
+/* keys to be replaced by real values in the filename */
+#define RATE_KEY	"%r"
+#define CHANNELS_KEY	"%c"
+#define BWIDTH_KEY	"%b"
+#define FORMAT_KEY	"%f"
+
+/* maximum length of a value */
+#define VALUE_MAXLEN	10
+
+static const char *keys[] = {
+	RATE_KEY,
+	CHANNELS_KEY,
+	BWIDTH_KEY,
+	FORMAT_KEY,
+};
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof *(x))
+
 typedef enum _snd_pcm_file_format {
 	SND_PCM_FILE_FORMAT_RAW,
 	SND_PCM_FILE_FORMAT_WAV
@@ -57,6 +76,9 @@ struct wav_fmt {
 typedef struct {
 	snd_pcm_generic_t gen;
 	char *fname;
+	char *final_fname;
+	int trunc;
+	int perm;
 	int fd;
 	char *ifname;
 	int ifd;
@@ -84,6 +106,211 @@ typedef struct {
 #define TO_LE16(x)	bswap_16(x)
 #endif
 
+/* old_string MUST contain the key! */
+int snd_pcm_file_replace_key(char *old_string, char *key, char *value,
+		char **newstring_p)
+{
+	int str_index, newstr_index, key_index, end, new_len, old_len, cpy_len,
+	    first_key_index;
+	char *c, *first_c, *newstring;
+	int keys_count;
+
+	first_c = c = (char *) strstr(old_string, key);
+	new_len        = strlen(value);
+	old_len        = strlen(key);
+	end            = strlen(old_string)   - old_len;
+	first_key_index = key_index = c - old_string;
+
+	/* first run - finding nb of keys for calculating allocation size */
+	str_index = 0;
+	keys_count = 0;
+	while (str_index <= end && c != NULL) {
+		keys_count++;
+		str_index    = key_index + old_len;
+		/* Check for another pattern match */
+		c = (char *) strstr(old_string+str_index, key);
+		if (c != NULL)
+			key_index = c - old_string;
+	}
+	/* now we can allocate exactly the right size */
+	newstring = malloc(strlen(old_string) +
+			keys_count*(new_len - old_len) + 1);
+	if (!newstring)
+		return -ENOMEM;
+	/* second run - actually replacing */
+	str_index = 0;
+	newstr_index = 0;
+	key_index = first_key_index;
+	c = first_c;
+	while (str_index <= end && c != NULL) {
+		/* Copy characters from the left of matched pattern occurence */
+		cpy_len = key_index-str_index;
+		strncpy(newstring+newstr_index, old_string+str_index, cpy_len);
+		newstr_index += cpy_len;
+		str_index    += cpy_len;
+
+		/* Copy replacement characters instead of matched pattern */
+		strcpy(newstring+newstr_index, value);
+		newstr_index += new_len;
+		str_index    += old_len;
+
+		/* Check for another pattern match */
+		c = (char *) strstr(old_string+str_index, key);
+		if (c != NULL)
+			key_index = c - old_string;
+	}
+	/* Copy remaining characters from the right of last matched pattern */
+	strcpy(newstring+newstr_index, old_string+str_index);
+	*(newstring_p) = newstring;
+	return 0;
+}
+
+int snd_pcm_file_replace_fname(snd_pcm_file_t *file, char **new_fname_p)
+{
+	char *value;
+	char *old_fname = NULL;
+	int err;
+	char *fname = file->fname;
+	snd_pcm_t *pcm = file->gen.slave;
+
+	value = malloc(VALUE_MAXLEN);
+	if (!value)
+		return -ENOMEM;
+	/* we want to keep fname, const */
+	old_fname = *(new_fname_p) = fname;
+
+	if (strstr(old_fname, RATE_KEY)) {
+		snprintf(value, VALUE_MAXLEN, "%d", pcm->rate);
+		err = snd_pcm_file_replace_key(old_fname, RATE_KEY, value,
+				new_fname_p);
+		/* fname must not be freed */
+		if (old_fname != fname)
+			free(old_fname);
+		old_fname = *(new_fname_p);
+		if (err < 0)
+			return err;
+	}
+	if (strstr(old_fname, CHANNELS_KEY)) {
+		snprintf(value, VALUE_MAXLEN, "%d", pcm->channels);
+		err = snd_pcm_file_replace_key(old_fname, CHANNELS_KEY, value,
+				new_fname_p);
+		if (old_fname != fname)
+			free(old_fname);
+		old_fname = *(new_fname_p);
+		if (err < 0)
+			return err;
+	}
+	if (strstr(old_fname, BWIDTH_KEY)) {
+		snprintf(value, VALUE_MAXLEN, "%d",
+				pcm->frame_bits/(8 * pcm->channels));
+		err = snd_pcm_file_replace_key(old_fname, BWIDTH_KEY, value,
+				new_fname_p);
+		if (old_fname != fname)
+			free(old_fname);
+		old_fname = *(new_fname_p);
+		if (err < 0)
+			return err;
+	}
+	if (strstr(old_fname, FORMAT_KEY)) {
+		snprintf(value, VALUE_MAXLEN, "%s",
+				snd_pcm_format_name(pcm->format));
+		err = snd_pcm_file_replace_key(old_fname, FORMAT_KEY, value,
+				new_fname_p);
+		if (old_fname != fname)
+			free(old_fname);
+		old_fname = *(new_fname_p);
+		if (err < 0)
+			return err;
+	}
+	free(value);
+	return 0;
+
+}
+
+int snd_pcm_file_has_keys(char *string)
+{
+	int i, n = ARRAY_SIZE(keys);
+	static const char **key = keys;
+
+	for (i = 0; i < n; i++) {
+		if (strstr(string, *key++) != NULL)
+			return 1;
+	}
+	/* none found */
+	return 0;
+}
+
+int snd_pcm_file_open_output_file(snd_pcm_file_t *file)
+{
+	int err, fd;
+
+	/* fname can contain keys, generating final_fname */
+	if (snd_pcm_file_has_keys(file->fname)) {
+		err = snd_pcm_file_replace_fname(file, &(file->final_fname));
+		if (err < 0)
+			return err;
+		/*printf("DEBUG - original fname: %s, final fname: %s\n",
+		  file->fname, file->final_fname);*/
+	} else {
+		/* no changes */
+		file->final_fname = malloc(strlen(file->fname) + 1);
+		if (!file->final_fname)
+			return -ENOMEM;
+		strcpy(file->final_fname, file->fname);
+	}
+
+	if (file->final_fname[0] == '|') {
+		/* pipe mode */
+		FILE *pipe;
+		/* clearing */
+		file->final_fname[0] = ' ';
+		pipe = popen(file->final_fname, "w");
+		if (!pipe) {
+			SYSERR("running %s for writing failed",
+					file->final_fname);
+			return -errno;
+		}
+		fd = fileno(pipe);
+	} else {
+		if (file->trunc)
+			fd = open(file->final_fname, O_WRONLY|O_CREAT|O_TRUNC,
+					file->perm);
+		else {
+			fd = open(file->final_fname, O_WRONLY|O_CREAT|O_EXCL,
+					file->perm);
+			if (fd < 0) {
+				char *tmpfname = NULL;
+				int idx, len;
+				len = strlen(file->final_fname) + 6;
+				tmpfname = malloc(len);
+				if (!tmpfname)
+					return -ENOMEM;
+				for (idx = 1; idx < 10000; idx++) {
+					snprintf(tmpfname, len,
+						"%s.%04d", file->final_fname,
+						idx);
+					fd = open(tmpfname,
+							O_WRONLY|O_CREAT|O_EXCL,
+							file->perm);
+					if (fd >= 0) {
+						free(file->final_fname);
+						file->final_fname = tmpfname;
+						break;
+					}
+				}
+				if (fd < 0) {
+					SYSERR("open %s for writing failed",
+							file->final_fname);
+					free(tmpfname);
+					return -errno;
+				}
+			}
+		}
+	}
+	file->fd = fd;
+	return 0;
+}
+
 static void setup_wav_header(snd_pcm_t *pcm, struct wav_fmt *fmt)
 {
 	fmt->fmt = TO_LE16(0x01);
@@ -152,6 +379,8 @@ static void fixup_wav_header(snd_pcm_t *pcm)
 }
 #endif /* DOC_HIDDEN */
 
+
+
 static void snd_pcm_file_write_bytes(snd_pcm_t *pcm, size_t bytes)
 {
 	snd_pcm_file_t *file = pcm->private_data;
@@ -442,6 +671,13 @@ static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 		a->first = slave->sample_bits * channel;
 		a->step = slave->frame_bits;
 	}
+	if (file->fd < 0) {
+		err = snd_pcm_file_open_output_file(file);
+		if (err < 0) {
+			SYSERR("failed opening output file %s", file->fname);
+			return err;
+		}
+	}
 	return 0;
 }
 
@@ -452,6 +688,10 @@ static void snd_pcm_file_dump(snd_pcm_t *pcm, snd_output_t *out)
 		snd_output_printf(out, "File PCM (file=%s)\n", file->fname);
 	else
 		snd_output_printf(out, "File PCM (fd=%d)\n", file->fd);
+	if (file->final_fname)
+		snd_output_printf(out, "Final file PCM (file=%s)\n",
+				file->final_fname);
+
 	if (pcm->setup) {
 		snd_output_printf(out, "Its setup is:\n");
 		snd_pcm_dump_setup(pcm, out);
@@ -533,7 +773,6 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 	snd_pcm_file_t *file;
 	snd_pcm_file_format_t format;
 	struct timespec timespec;
-	char *tmpname = NULL;
 	int err;
 
 	assert(pcmp);
@@ -546,58 +785,27 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 		SNDERR("file format %s is unknown", fmt);
 		return -EINVAL;
 	}
-	if (fname) {
-		if (trunc)
-			fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, perm);
-		else {
-			fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, perm);
-			if (fd < 0) {
-				int idx, len;
-				len = strlen(fname) + 6;
-				tmpname = malloc(len);
-				if (!tmpname)
-					return -ENOMEM;
-				for (idx = 1; idx < 10000; idx++) {
-					snprintf(tmpname, len,
-						 "%s.%04d", fname, idx);
-					fd = open(tmpname, O_WRONLY|O_CREAT|O_EXCL, perm);
-					if (fd >= 0) {
-						fname = tmpname;
-						break;
-					}
-				}
-			}
-		}
-		if (fd < 0) {
-			SYSERR("open %s for writing failed", fname);
-			free(tmpname);
-			return -errno;
-		}
-	}
 	file = calloc(1, sizeof(snd_pcm_file_t));
 	if (!file) {
-		if (fname)
-			close(fd);
-		free(tmpname);
 		return -ENOMEM;
 	}
 
+	/* opening output fname is delayed until writing,
+	 when PCM params are known */
+	if (fname)
+		file->fname = strdup(fname);
+	file->trunc = trunc;
+	file->perm = perm;
+
 	if (ifname) {
 		ifd = open(ifname, O_RDONLY);	/* TODO: mind blocking mode */
 		if (ifd < 0) {
 			SYSERR("open %s for reading failed", ifname);
-			if (fname)
-				close(fd);
 			free(file);
-			free(tmpname);
 			return -errno;
 		}
-	}
-
-	if (fname)
-		file->fname = strdup(fname);
-	if (ifname)
 		file->ifname = strdup(ifname);
+	}
 	file->fd = fd;
 	file->ifd = ifd;
 	file->format = format;
@@ -608,7 +816,6 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 	if (err < 0) {
 		free(file->fname);
 		free(file);
-		free(tmpname);
 		return err;
 	}
 	pcm->ops = &snd_pcm_file_ops;
@@ -625,8 +832,6 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 	snd_pcm_link_hw_ptr(pcm, slave);
 	snd_pcm_link_appl_ptr(pcm, slave);
 	*pcmp = pcm;
-
-	free(tmpname);
 	return 0;
 }
 
@@ -634,8 +839,9 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 
 \section pcm_plugins_file Plugin: File
 
-This plugin stores contents of a PCM stream to file, and optionally
-uses an existing file as an input data source (i.e., "virtual mic")
+This plugin stores contents of a PCM stream to file or pipes the stream
+to a command, and optionally uses an existing file as an input data source
+(i.e., "virtual mic")
 
 \code
 pcm.name {
@@ -647,7 +853,16 @@ pcm.name {
                 # or
                 pcm { }         # Slave PCM definition
         }
-	file STR		# Output filename
+	file STR		# Output filename (or shell command the stream
+				# will be piped to if STR starts with the pipe
+				# char).
+				# STR can contain format keys, replaced by
+				# real values corresponding to the stream:
+				# %r	rate (replaced with: 48000)
+				# %c	channels (replaced with: 2)
+				# %b	bytes per sample (replaced with: 2)
+				# %f	sample format string
+				#			(replaced with: S16_LE)
 	or
 	file INT		# Output file descriptor number
 	infile STR		# Input filename - only raw format


[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] PCM parameters in file plugin
  2009-01-19 22:20       ` [PATCH] " Pavel Hofman
@ 2009-01-26 14:28         ` Pavel Hofman
  2009-01-28 15:41         ` Takashi Iwai
  1 sibling, 0 replies; 11+ messages in thread
From: Pavel Hofman @ 2009-01-26 14:28 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: alsa-devel

Pavel Hofman wrote:
> Pavel Hofman wrote:
>> Jaroslav Kysela wrote:
>>> On Tue, 6 Jan 2009, Pavel Hofman wrote:
>>>
>>>> Pavel Hofman napsal(a):
>>>>> Hello,
>>>>>
>>>>> I am working on a file plugin patch to allow adding PCM parameters 
>>>>> (rate, format) to  the name of the file created (plus the ability 
>>>>> to run an external command via popen, such as upsampling with sox). 
>>>>> I got stuck in trying to obtain these parameters in 
>>>>> pcm_file.c:_snd_pcm_file_open(). Is it actually possible or the 
>>>>> information is not available at the time of opening the file (and 
>>>>> the whole patch is thus nonsense)?
>>>>>
>>>>> Thanks a lot for help.
>>>>>
>>>> I am now opening the output file in 
>>>> pcm_file.c:snd_pcm_file_write_bytes.
>>>> Surprisingly it seems to work fine. Could such hack be accepted as a
>>>> patch to the plugin (if coded properly)? Is there a better place to 
>>>> open the file?
>>>
>>> The file should be opened in the hw_params callback (all PCM 
>>> parameters are known in this time). Also, extending filename with PCM 
>>> parameters should be optional (configurable). But the idea looks nice.
>>>
>>>                         Jaroslav
>>
> 
> Hello,
> 
> please find enclosed a patch for the file plugin. The
> checkpatch.pl script throws 5 bogus errors in doxygen comments.
> 
> Signed-off-by: Pavel Hofman <pavel.hofman@insite.cz>
> 
> * added support for including pcm stream params in the output filename
> * added support for piping the stream to a shell command if the filename
> string starts with a pipe char
> 
> Thanks a lot,
> 
> Pavel.

Hi,

Please let me know if there some areas to work on before the patch can
be accepted for merge.

Thanks a lot,

Pavel.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] PCM parameters in file plugin
  2009-01-19 22:20       ` [PATCH] " Pavel Hofman
  2009-01-26 14:28         ` Pavel Hofman
@ 2009-01-28 15:41         ` Takashi Iwai
  2009-01-28 23:00           ` Pavel Hofman
  1 sibling, 1 reply; 11+ messages in thread
From: Takashi Iwai @ 2009-01-28 15:41 UTC (permalink / raw)
  To: Pavel Hofman; +Cc: alsa-devel

At Mon, 19 Jan 2009 23:20:49 +0100,
Pavel Hofman wrote:
> 
> @@ -84,6 +106,211 @@ typedef struct {
>  #define TO_LE16(x)	bswap_16(x)
>  #endif
>  
> +/* old_string MUST contain the key! */
> +int snd_pcm_file_replace_key(char *old_string, char *key, char *value,
> +		char **newstring_p)

Make this static.

> +{
> +	int str_index, newstr_index, key_index, end, new_len, old_len, cpy_len,
> +	    first_key_index;
> +	char *c, *first_c, *newstring;
> +	int keys_count;
> +
> +	first_c = c = (char *) strstr(old_string, key);

I guess this parser doesn't handle '%%' properly like printf()?

> +int snd_pcm_file_replace_fname(snd_pcm_file_t *file, char **new_fname_p)

Make it static.

> +int snd_pcm_file_has_keys(char *string)

Ditto.

> +int snd_pcm_file_open_output_file(snd_pcm_file_t *file)

Ditto.

> +	if (file->final_fname[0] == '|') {
> +		/* pipe mode */
> +		FILE *pipe;
> +		/* clearing */
> +		file->final_fname[0] = ' ';
> +		pipe = popen(file->final_fname, "w");

Pass "file->final_fname + 1", and you don't have to replace the pipe
with a space.


thanks,

Takashi

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] PCM parameters in file plugin
  2009-01-28 15:41         ` Takashi Iwai
@ 2009-01-28 23:00           ` Pavel Hofman
  2009-01-29  8:28             ` Takashi Iwai
  0 siblings, 1 reply; 11+ messages in thread
From: Pavel Hofman @ 2009-01-28 23:00 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel

[-- Attachment #1: Type: text/plain, Size: 1335 bytes --]

Takashi Iwai wrote:
> At Mon, 19 Jan 2009 23:20:49 +0100,
> Pavel Hofman wrote:
>> @@ -84,6 +106,211 @@ typedef struct {
>>  #define TO_LE16(x)	bswap_16(x)
>>  #endif
>>  
>> +/* old_string MUST contain the key! */
>> +int snd_pcm_file_replace_key(char *old_string, char *key, char *value,
>> +		char **newstring_p)
> 
> Make this static.
> 
>> +{
>> +	int str_index, newstr_index, key_index, end, new_len, old_len, cpy_len,
>> +	    first_key_index;
>> +	char *c, *first_c, *newstring;
>> +	int keys_count;
>> +
>> +	first_c = c = (char *) strstr(old_string, key);
> 
> I guess this parser doesn't handle '%%' properly like printf()?
> 
>> +int snd_pcm_file_replace_fname(snd_pcm_file_t *file, char **new_fname_p)
> 
> Make it static.
> 
>> +int snd_pcm_file_has_keys(char *string)
> 
> Ditto.
> 
>> +int snd_pcm_file_open_output_file(snd_pcm_file_t *file)
> 
> Ditto.
> 
>> +	if (file->final_fname[0] == '|') {
>> +		/* pipe mode */
>> +		FILE *pipe;
>> +		/* clearing */
>> +		file->final_fname[0] = ' ';
>> +		pipe = popen(file->final_fname, "w");
> 
> Pass "file->final_fname + 1", and you don't have to replace the pipe
> with a space.
> 
> 
> thanks,
> 
> Takashi

Hi Takashi,

Thanks a lot for your comments.

Please find enclosed a reworked patch which reflects your requests 
including the %% functionality.

Thanks,

Pavel.

[-- Attachment #2: pcm_file.c.patch --]
[-- Type: text/x-patch, Size: 9666 bytes --]

diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c
index 82823a0..8e0f2dc 100644
--- a/src/pcm/pcm_file.c
+++ b/src/pcm/pcm_file.c
@@ -29,6 +29,7 @@
 #include <endian.h>
 #include <byteswap.h>
 #include <ctype.h>
+#include <string.h>
 #include "pcm_local.h"
 #include "pcm_plugin.h"
 
@@ -39,6 +40,16 @@ const char *_snd_module_pcm_file = "";
 
 #ifndef DOC_HIDDEN
 
+/* keys to be replaced by real values in the filename */
+#define LEADING_KEY	'%'	/* i.e. %r, %c, %b ... */
+#define RATE_KEY	'r'
+#define CHANNELS_KEY	'c'
+#define BWIDTH_KEY	'b'
+#define FORMAT_KEY	'f'
+
+/* maximum length of a value */
+#define VALUE_MAXLEN	10
+
 typedef enum _snd_pcm_file_format {
 	SND_PCM_FILE_FORMAT_RAW,
 	SND_PCM_FILE_FORMAT_WAV
@@ -57,6 +68,9 @@ struct wav_fmt {
 typedef struct {
 	snd_pcm_generic_t gen;
 	char *fname;
+	char *final_fname;
+	int trunc;
+	int perm;
 	int fd;
 	char *ifname;
 	int ifd;
@@ -84,6 +98,183 @@ typedef struct {
 #define TO_LE16(x)	bswap_16(x)
 #endif
 
+static int snd_pcm_file_replace_key(char format, const void *value_p,
+		char **string_p, char **index_ch_p, int *len_p)
+{
+	char *value_str, *string, *index_ch;
+	int index, len;
+	/* input pointer values */
+	len = *(len_p);
+	string = *(string_p);
+	index_ch = *(index_ch_p);
+
+	/* converting general-type value to its string representation */
+	value_str = malloc(VALUE_MAXLEN + 1);
+	if (!value_str)
+		return -ENOMEM;
+	switch (format) {
+	case 'd':
+		snprintf(value_str, VALUE_MAXLEN, "%d",	*((int *) value_p));
+		break;
+	case 's':
+		snprintf(value_str, VALUE_MAXLEN, "%s",	(char *) value_p);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* reallocation to accommodate the value */
+	index = index_ch - string;
+	len += VALUE_MAXLEN;
+	string = realloc(string, len + 1);
+	if (!string) {
+		free(value_str);
+		return -ENOMEM;
+	}
+	index_ch = string + index;
+	/* concatenating the new value */
+	strcpy(index_ch, value_str);
+	index_ch += strlen(value_str);
+	free(value_str);
+	/* return values */
+	*(len_p) = len;
+	*(string_p) = string;
+	*(index_ch_p) = index_ch;
+	return 0;
+}
+
+static int snd_pcm_file_replace_fname(snd_pcm_file_t *file, char **new_fname_p)
+{
+	char *fname = file->fname;
+	char *new_fname = NULL;
+	char *old_last_ch, *old_index_ch, *new_index_ch;
+	int old_len, new_len, width, err;
+
+	snd_pcm_t *pcm = file->gen.slave;
+
+	/* we want to keep fname, const */
+	old_len = new_len = strlen(fname);
+	old_last_ch = fname + old_len;
+	new_fname = malloc(new_len + 1);
+	if (!new_fname)
+		return -ENOMEM;
+
+	old_index_ch = fname;	/* first character of the old name */
+	new_index_ch = new_fname;	/* first char of the new name */
+
+	while (old_index_ch <= old_last_ch) {
+		/* char by char */
+		if (*(old_index_ch) != '%') {
+			/* plain copying */
+			*(new_index_ch++) = *(old_index_ch++);
+			continue;
+		}
+		/* is %, skipping and checking next letter */
+		switch (*(++old_index_ch)) {
+		case RATE_KEY:
+			err = snd_pcm_file_replace_key('d', &(pcm->rate),
+					&new_fname, &new_index_ch, &new_len);
+			if (err < 0)
+				return err;
+			break;
+
+		case CHANNELS_KEY:
+			err = snd_pcm_file_replace_key('d', &(pcm->channels),
+					&new_fname, &new_index_ch, &new_len);
+			if (err < 0)
+				return err;
+			break;
+
+		case BWIDTH_KEY:
+			width = pcm->frame_bits/(8 * pcm->channels);
+			err = snd_pcm_file_replace_key('d', &width, &new_fname,
+					&new_index_ch, &new_len);
+			if (err < 0)
+				return err;
+			break;
+
+		case FORMAT_KEY:
+			err = snd_pcm_file_replace_key('s',
+					snd_pcm_format_name(pcm->format),
+					&new_fname, &new_index_ch, &new_len);
+			if (err < 0)
+				return err;
+			break;
+
+		default:
+			*(new_index_ch++) = *(old_index_ch);
+		}
+		/* next old letter */
+		old_index_ch++;
+	}
+	*(new_index_ch) = '\0';
+	*(new_fname_p) = new_fname;
+	return 0;
+
+}
+
+static int snd_pcm_file_open_output_file(snd_pcm_file_t *file)
+{
+	int err, fd;
+
+	/* fname can contain keys, generating final_fname */
+	err = snd_pcm_file_replace_fname(file, &(file->final_fname));
+	if (err < 0)
+		return err;
+	/*printf("DEBUG - original fname: %s, final fname: %s\n",
+	  file->fname, file->final_fname);*/
+
+	if (file->final_fname[0] == '|') {
+		/* pipe mode */
+		FILE *pipe;
+		/* clearing */
+		pipe = popen(file->final_fname + 1, "w");
+		if (!pipe) {
+			SYSERR("running %s for writing failed",
+					file->final_fname);
+			return -errno;
+		}
+		fd = fileno(pipe);
+	} else {
+		if (file->trunc)
+			fd = open(file->final_fname, O_WRONLY|O_CREAT|O_TRUNC,
+					file->perm);
+		else {
+			fd = open(file->final_fname, O_WRONLY|O_CREAT|O_EXCL,
+					file->perm);
+			if (fd < 0) {
+				char *tmpfname = NULL;
+				int idx, len;
+				len = strlen(file->final_fname) + 6;
+				tmpfname = malloc(len);
+				if (!tmpfname)
+					return -ENOMEM;
+				for (idx = 1; idx < 10000; idx++) {
+					snprintf(tmpfname, len,
+						"%s.%04d", file->final_fname,
+						idx);
+					fd = open(tmpfname,
+							O_WRONLY|O_CREAT|O_EXCL,
+							file->perm);
+					if (fd >= 0) {
+						free(file->final_fname);
+						file->final_fname = tmpfname;
+						break;
+					}
+				}
+				if (fd < 0) {
+					SYSERR("open %s for writing failed",
+							file->final_fname);
+					free(tmpfname);
+					return -errno;
+				}
+			}
+		}
+	}
+	file->fd = fd;
+	return 0;
+}
+
 static void setup_wav_header(snd_pcm_t *pcm, struct wav_fmt *fmt)
 {
 	fmt->fmt = TO_LE16(0x01);
@@ -152,6 +343,8 @@ static void fixup_wav_header(snd_pcm_t *pcm)
 }
 #endif /* DOC_HIDDEN */
 
+
+
 static void snd_pcm_file_write_bytes(snd_pcm_t *pcm, size_t bytes)
 {
 	snd_pcm_file_t *file = pcm->private_data;
@@ -442,6 +635,13 @@ static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 		a->first = slave->sample_bits * channel;
 		a->step = slave->frame_bits;
 	}
+	if (file->fd < 0) {
+		err = snd_pcm_file_open_output_file(file);
+		if (err < 0) {
+			SYSERR("failed opening output file %s", file->fname);
+			return err;
+		}
+	}
 	return 0;
 }
 
@@ -452,6 +652,10 @@ static void snd_pcm_file_dump(snd_pcm_t *pcm, snd_output_t *out)
 		snd_output_printf(out, "File PCM (file=%s)\n", file->fname);
 	else
 		snd_output_printf(out, "File PCM (fd=%d)\n", file->fd);
+	if (file->final_fname)
+		snd_output_printf(out, "Final file PCM (file=%s)\n",
+				file->final_fname);
+
 	if (pcm->setup) {
 		snd_output_printf(out, "Its setup is:\n");
 		snd_pcm_dump_setup(pcm, out);
@@ -533,7 +737,6 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 	snd_pcm_file_t *file;
 	snd_pcm_file_format_t format;
 	struct timespec timespec;
-	char *tmpname = NULL;
 	int err;
 
 	assert(pcmp);
@@ -546,58 +749,27 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 		SNDERR("file format %s is unknown", fmt);
 		return -EINVAL;
 	}
-	if (fname) {
-		if (trunc)
-			fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, perm);
-		else {
-			fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, perm);
-			if (fd < 0) {
-				int idx, len;
-				len = strlen(fname) + 6;
-				tmpname = malloc(len);
-				if (!tmpname)
-					return -ENOMEM;
-				for (idx = 1; idx < 10000; idx++) {
-					snprintf(tmpname, len,
-						 "%s.%04d", fname, idx);
-					fd = open(tmpname, O_WRONLY|O_CREAT|O_EXCL, perm);
-					if (fd >= 0) {
-						fname = tmpname;
-						break;
-					}
-				}
-			}
-		}
-		if (fd < 0) {
-			SYSERR("open %s for writing failed", fname);
-			free(tmpname);
-			return -errno;
-		}
-	}
 	file = calloc(1, sizeof(snd_pcm_file_t));
 	if (!file) {
-		if (fname)
-			close(fd);
-		free(tmpname);
 		return -ENOMEM;
 	}
 
+	/* opening output fname is delayed until writing,
+	 when PCM params are known */
+	if (fname)
+		file->fname = strdup(fname);
+	file->trunc = trunc;
+	file->perm = perm;
+
 	if (ifname) {
 		ifd = open(ifname, O_RDONLY);	/* TODO: mind blocking mode */
 		if (ifd < 0) {
 			SYSERR("open %s for reading failed", ifname);
-			if (fname)
-				close(fd);
 			free(file);
-			free(tmpname);
 			return -errno;
 		}
-	}
-
-	if (fname)
-		file->fname = strdup(fname);
-	if (ifname)
 		file->ifname = strdup(ifname);
+	}
 	file->fd = fd;
 	file->ifd = ifd;
 	file->format = format;
@@ -608,7 +780,6 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 	if (err < 0) {
 		free(file->fname);
 		free(file);
-		free(tmpname);
 		return err;
 	}
 	pcm->ops = &snd_pcm_file_ops;
@@ -625,8 +796,6 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 	snd_pcm_link_hw_ptr(pcm, slave);
 	snd_pcm_link_appl_ptr(pcm, slave);
 	*pcmp = pcm;
-
-	free(tmpname);
 	return 0;
 }
 
@@ -634,8 +803,9 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 
 \section pcm_plugins_file Plugin: File
 
-This plugin stores contents of a PCM stream to file, and optionally
-uses an existing file as an input data source (i.e., "virtual mic")
+This plugin stores contents of a PCM stream to file or pipes the stream
+to a command, and optionally uses an existing file as an input data source
+(i.e., "virtual mic")
 
 \code
 pcm.name {
@@ -647,7 +817,17 @@ pcm.name {
                 # or
                 pcm { }         # Slave PCM definition
         }
-	file STR		# Output filename
+	file STR		# Output filename (or shell command the stream
+				# will be piped to if STR starts with the pipe
+				# char).
+				# STR can contain format keys, replaced by
+				# real values corresponding to the stream:
+				# %r	rate (replaced with: 48000)
+				# %c	channels (replaced with: 2)
+				# %b	bytes per sample (replaced with: 2)
+				# %f	sample format string
+				#			(replaced with: S16_LE)
+				# %%	replaced with %
 	or
 	file INT		# Output file descriptor number
 	infile STR		# Input filename - only raw format

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] PCM parameters in file plugin
  2009-01-28 23:00           ` Pavel Hofman
@ 2009-01-29  8:28             ` Takashi Iwai
  2009-01-29 10:54               ` Pavel Hofman
  0 siblings, 1 reply; 11+ messages in thread
From: Takashi Iwai @ 2009-01-29  8:28 UTC (permalink / raw)
  To: Pavel Hofman; +Cc: alsa-devel

At Thu, 29 Jan 2009 00:00:08 +0100,
Pavel Hofman wrote:
> 
> Takashi Iwai wrote:
> > At Mon, 19 Jan 2009 23:20:49 +0100,
> > Pavel Hofman wrote:
> >> @@ -84,6 +106,211 @@ typedef struct {
> >>  #define TO_LE16(x)	bswap_16(x)
> >>  #endif
> >>  
> >> +/* old_string MUST contain the key! */
> >> +int snd_pcm_file_replace_key(char *old_string, char *key, char *value,
> >> +		char **newstring_p)
> > 
> > Make this static.
> > 
> >> +{
> >> +	int str_index, newstr_index, key_index, end, new_len, old_len, cpy_len,
> >> +	    first_key_index;
> >> +	char *c, *first_c, *newstring;
> >> +	int keys_count;
> >> +
> >> +	first_c = c = (char *) strstr(old_string, key);
> > 
> > I guess this parser doesn't handle '%%' properly like printf()?
> > 
> >> +int snd_pcm_file_replace_fname(snd_pcm_file_t *file, char **new_fname_p)
> > 
> > Make it static.
> > 
> >> +int snd_pcm_file_has_keys(char *string)
> > 
> > Ditto.
> > 
> >> +int snd_pcm_file_open_output_file(snd_pcm_file_t *file)
> > 
> > Ditto.
> > 
> >> +	if (file->final_fname[0] == '|') {
> >> +		/* pipe mode */
> >> +		FILE *pipe;
> >> +		/* clearing */
> >> +		file->final_fname[0] = ' ';
> >> +		pipe = popen(file->final_fname, "w");
> > 
> > Pass "file->final_fname + 1", and you don't have to replace the pipe
> > with a space.
> > 
> > 
> > thanks,
> > 
> > Takashi
> 
> Hi Takashi,
> 
> Thanks a lot for your comments.
> 
> Please find enclosed a reworked patch which reflects your requests 
> including the %% functionality.

Thanks, it gets better now.

> +static int snd_pcm_file_replace_key(char format, const void *value_p,
> +		char **string_p, char **index_ch_p, int *len_p)

I think it could be easier to make value_str in the caller side.
That is,

static int snd_pcm_file_replace_key(char **string_p, char **index_ch_p,
	int *len_p, const char *value_str)
{
	char *value_str, *string, *index_ch;
	int index, len, value_len;
	/* input pointer values */
	len = *(len_p);
	string = *(string_p);
	index_ch = *(index_ch_p);

	/* reallocation to accommodate the value */
	index = index_ch - string;
	value_len = strlen(value_str);
	len += value_len;
	string = realloc(string, len + 1);
	if (!string)
		return -ENOMEM;
	index_ch = string + index;
	/* concatenating the new value */
	strcpy(index_ch, value_str);
	index_ch += value_len;
	/* return values */
	*(len_p) = len;
	*(string_p) = string;
	*(index_ch_p) = index_ch;
	return 0;
}

static int snd_pcm_file_replace_fname(snd_pcm_file_t *file, char **new_fname_p)
{
	char value[64];
...
	while (old_index_ch <= old_last_ch) {
...
		/* is %, skipping and checking next letter */
		switch (*(++old_index_ch)) {
		case RATE_KEY:
			snprintf(value, sizeof(value), "%d', pcm->rate);
			err = snd_pcm_file_replace_key(&new_fname,
				&new_index_ch, &new_len, value);
			if (err < 0)
				return err;
			break;

		case CHANNELS_KEY:
			snprintf(value, sizeof(value), "%d', pcm->channels);
			err = snd_pcm_file_replace_key(&new_fname,
				&new_index_ch, &new_len, value);
			if (err < 0)
				return err;
			break;
....
		case FORMAT_KEY:
			err = snd_pcm_file_replace_key(&new_fname,
				&new_index_ch, &new_len,
				snd_pcm_format_name(pcm->format));
			if (err < 0)
				return err;
			break;
...


Takashi

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] PCM parameters in file plugin
  2009-01-29  8:28             ` Takashi Iwai
@ 2009-01-29 10:54               ` Pavel Hofman
  2009-01-29 11:01                 ` Takashi Iwai
  0 siblings, 1 reply; 11+ messages in thread
From: Pavel Hofman @ 2009-01-29 10:54 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel

[-- Attachment #1: Type: text/plain, Size: 617 bytes --]

Takashi Iwai wrote:
> 
> Thanks, it gets better now.
> 
>> +static int snd_pcm_file_replace_key(char format, const void *value_p,
>> +		char **string_p, char **index_ch_p, int *len_p)
> 
> I think it could be easier to make value_str in the caller side.
> That is,
> ........

Hi Takashi,

Thanks for your valuable comments. I am enclosing a fixed and tested 
version.

Regards,

Pavel.

Signed-off-by: Pavel Hofman <pavel.hofman@insite.cz>

* added support for including pcm stream params in the output filename
* added support for piping the stream to a shell command if the filename
string starts with a pipe char

[-- Attachment #2: pcm_file.c.patch --]
[-- Type: text/x-diff, Size: 9914 bytes --]

diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c
index 82823a0..6ddf14f 100644
--- a/src/pcm/pcm_file.c
+++ b/src/pcm/pcm_file.c
@@ -29,6 +29,7 @@
 #include <endian.h>
 #include <byteswap.h>
 #include <ctype.h>
+#include <string.h>
 #include "pcm_local.h"
 #include "pcm_plugin.h"
 
@@ -39,6 +40,16 @@ const char *_snd_module_pcm_file = "";
 
 #ifndef DOC_HIDDEN
 
+/* keys to be replaced by real values in the filename */
+#define LEADING_KEY	'%'	/* i.e. %r, %c, %b ... */
+#define RATE_KEY	'r'
+#define CHANNELS_KEY	'c'
+#define BWIDTH_KEY	'b'
+#define FORMAT_KEY	'f'
+
+/* maximum length of a value */
+#define VALUE_MAXLEN	64
+
 typedef enum _snd_pcm_file_format {
 	SND_PCM_FILE_FORMAT_RAW,
 	SND_PCM_FILE_FORMAT_WAV
@@ -57,6 +68,9 @@ struct wav_fmt {
 typedef struct {
 	snd_pcm_generic_t gen;
 	char *fname;
+	char *final_fname;
+	int trunc;
+	int perm;
 	int fd;
 	char *ifname;
 	int ifd;
@@ -84,6 +98,175 @@ typedef struct {
 #define TO_LE16(x)	bswap_16(x)
 #endif
 
+static int snd_pcm_file_append_value(char **string_p, char **index_ch_p,
+		int *len_p, const char *value)
+{
+	char *string, *index_ch;
+	int index, len, value_len;
+	/* input pointer values */
+	len = *(len_p);
+	string = *(string_p);
+	index_ch = *(index_ch_p);
+
+	value_len = strlen(value);
+	/* reallocation to accommodate the value */
+	index = index_ch - string;
+	len += value_len;
+	string = realloc(string, len + 1);
+	if (!string)
+		return -ENOMEM;
+	index_ch = string + index;
+	/* concatenating the new value */
+	strcpy(index_ch, value);
+	index_ch += value_len;
+	/* return values */
+	*(len_p) = len;
+	*(string_p) = string;
+	*(index_ch_p) = index_ch;
+	return 0;
+}
+
+static int snd_pcm_file_replace_fname(snd_pcm_file_t *file, char **new_fname_p)
+{
+	char value[VALUE_MAXLEN];
+	char *fname = file->fname;
+	char *new_fname = NULL;
+	char *old_last_ch, *old_index_ch, *new_index_ch;
+	int old_len, new_len, err;
+
+	snd_pcm_t *pcm = file->gen.slave;
+
+	/* we want to keep fname, const */
+	old_len = new_len = strlen(fname);
+	old_last_ch = fname + old_len - 1;
+	new_fname = malloc(new_len + 1);
+	if (!new_fname)
+		return -ENOMEM;
+
+	old_index_ch = fname;	/* first character of the old name */
+	new_index_ch = new_fname;	/* first char of the new name */
+
+	while (old_index_ch <= old_last_ch) {
+		if (*(old_index_ch) == LEADING_KEY &&
+				old_index_ch != old_last_ch) {
+			/* is %, not last char, skipping and checking
+			 next char */
+			switch (*(++old_index_ch)) {
+			case RATE_KEY:
+				snprintf(value, sizeof(value), "%d",
+						pcm->rate);
+				err = snd_pcm_file_append_value(&new_fname,
+					&new_index_ch, &new_len, value);
+				if (err < 0)
+					return err;
+				break;
+
+			case CHANNELS_KEY:
+				snprintf(value, sizeof(value), "%d",
+						pcm->channels);
+				err = snd_pcm_file_append_value(&new_fname,
+					&new_index_ch, &new_len, value);
+				if (err < 0)
+					return err;
+				break;
+
+			case BWIDTH_KEY:
+				snprintf(value, sizeof(value), "%d",
+					pcm->frame_bits/(8 * pcm->channels));
+				err = snd_pcm_file_append_value(&new_fname,
+						&new_index_ch, &new_len, value);
+				if (err < 0)
+					return err;
+				break;
+
+			case FORMAT_KEY:
+				err = snd_pcm_file_append_value(&new_fname,
+					&new_index_ch, &new_len,
+					snd_pcm_format_name(pcm->format));
+				if (err < 0)
+					return err;
+				break;
+
+			default:
+				/* non-key char, just copying */
+				*(new_index_ch++) = *(old_index_ch);
+			}
+			/* next old char */
+			old_index_ch++;
+		} else {
+			/* plain copying, shifting both strings to next chars */
+			*(new_index_ch++) = *(old_index_ch++);
+		}
+	}
+	/* closing the new string */
+	*(new_index_ch) = '\0';
+	*(new_fname_p) = new_fname;
+	return 0;
+
+}
+
+static int snd_pcm_file_open_output_file(snd_pcm_file_t *file)
+{
+	int err, fd;
+
+	/* fname can contain keys, generating final_fname */
+	err = snd_pcm_file_replace_fname(file, &(file->final_fname));
+	if (err < 0)
+		return err;
+	/*printf("DEBUG - original fname: %s, final fname: %s\n",
+	  file->fname, file->final_fname);*/
+
+	if (file->final_fname[0] == '|') {
+		/* pipe mode */
+		FILE *pipe;
+		/* clearing */
+		pipe = popen(file->final_fname + 1, "w");
+		if (!pipe) {
+			SYSERR("running %s for writing failed",
+					file->final_fname);
+			return -errno;
+		}
+		fd = fileno(pipe);
+	} else {
+		if (file->trunc)
+			fd = open(file->final_fname, O_WRONLY|O_CREAT|O_TRUNC,
+					file->perm);
+		else {
+			fd = open(file->final_fname, O_WRONLY|O_CREAT|O_EXCL,
+					file->perm);
+			if (fd < 0) {
+				char *tmpfname = NULL;
+				int idx, len;
+				len = strlen(file->final_fname) + 6;
+				tmpfname = malloc(len);
+				if (!tmpfname)
+					return -ENOMEM;
+				for (idx = 1; idx < 10000; idx++) {
+					snprintf(tmpfname, len,
+						"%s.%04d", file->final_fname,
+						idx);
+					fd = open(tmpfname,
+							O_WRONLY|O_CREAT|O_EXCL,
+							file->perm);
+					if (fd >= 0) {
+						free(file->final_fname);
+						file->final_fname = tmpfname;
+						break;
+					}
+				}
+				if (fd < 0) {
+					SYSERR("open %s for writing failed",
+							file->final_fname);
+					free(tmpfname);
+					return -errno;
+				}
+			}
+		}
+	}
+	file->fd = fd;
+	return 0;
+}
+
 static void setup_wav_header(snd_pcm_t *pcm, struct wav_fmt *fmt)
 {
 	fmt->fmt = TO_LE16(0x01);
@@ -152,6 +335,8 @@ static void fixup_wav_header(snd_pcm_t *pcm)
 }
 #endif /* DOC_HIDDEN */
 
+
+
 static void snd_pcm_file_write_bytes(snd_pcm_t *pcm, size_t bytes)
 {
 	snd_pcm_file_t *file = pcm->private_data;
@@ -442,6 +627,13 @@ static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 		a->first = slave->sample_bits * channel;
 		a->step = slave->frame_bits;
 	}
+	if (file->fd < 0) {
+		err = snd_pcm_file_open_output_file(file);
+		if (err < 0) {
+			SYSERR("failed opening output file %s", file->fname);
+			return err;
+		}
+	}
 	return 0;
 }
 
@@ -452,6 +644,10 @@ static void snd_pcm_file_dump(snd_pcm_t *pcm, snd_output_t *out)
 		snd_output_printf(out, "File PCM (file=%s)\n", file->fname);
 	else
 		snd_output_printf(out, "File PCM (fd=%d)\n", file->fd);
+	if (file->final_fname)
+		snd_output_printf(out, "Final file PCM (file=%s)\n",
+				file->final_fname);
+
 	if (pcm->setup) {
 		snd_output_printf(out, "Its setup is:\n");
 		snd_pcm_dump_setup(pcm, out);
@@ -533,7 +729,6 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 	snd_pcm_file_t *file;
 	snd_pcm_file_format_t format;
 	struct timespec timespec;
-	char *tmpname = NULL;
 	int err;
 
 	assert(pcmp);
@@ -546,58 +741,27 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 		SNDERR("file format %s is unknown", fmt);
 		return -EINVAL;
 	}
-	if (fname) {
-		if (trunc)
-			fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, perm);
-		else {
-			fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, perm);
-			if (fd < 0) {
-				int idx, len;
-				len = strlen(fname) + 6;
-				tmpname = malloc(len);
-				if (!tmpname)
-					return -ENOMEM;
-				for (idx = 1; idx < 10000; idx++) {
-					snprintf(tmpname, len,
-						 "%s.%04d", fname, idx);
-					fd = open(tmpname, O_WRONLY|O_CREAT|O_EXCL, perm);
-					if (fd >= 0) {
-						fname = tmpname;
-						break;
-					}
-				}
-			}
-		}
-		if (fd < 0) {
-			SYSERR("open %s for writing failed", fname);
-			free(tmpname);
-			return -errno;
-		}
-	}
 	file = calloc(1, sizeof(snd_pcm_file_t));
 	if (!file) {
-		if (fname)
-			close(fd);
-		free(tmpname);
 		return -ENOMEM;
 	}
 
+	/* opening output fname is delayed until writing,
+	 when PCM params are known */
+	if (fname)
+		file->fname = strdup(fname);
+	file->trunc = trunc;
+	file->perm = perm;
+
 	if (ifname) {
 		ifd = open(ifname, O_RDONLY);	/* TODO: mind blocking mode */
 		if (ifd < 0) {
 			SYSERR("open %s for reading failed", ifname);
-			if (fname)
-				close(fd);
 			free(file);
-			free(tmpname);
 			return -errno;
 		}
-	}
-
-	if (fname)
-		file->fname = strdup(fname);
-	if (ifname)
 		file->ifname = strdup(ifname);
+	}
 	file->fd = fd;
 	file->ifd = ifd;
 	file->format = format;
@@ -608,7 +772,6 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 	if (err < 0) {
 		free(file->fname);
 		free(file);
-		free(tmpname);
 		return err;
 	}
 	pcm->ops = &snd_pcm_file_ops;
@@ -625,8 +788,6 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 	snd_pcm_link_hw_ptr(pcm, slave);
 	snd_pcm_link_appl_ptr(pcm, slave);
 	*pcmp = pcm;
-
-	free(tmpname);
 	return 0;
 }
 
@@ -634,8 +795,9 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 
 \section pcm_plugins_file Plugin: File
 
-This plugin stores contents of a PCM stream to file, and optionally
-uses an existing file as an input data source (i.e., "virtual mic")
+This plugin stores contents of a PCM stream to file or pipes the stream
+to a command, and optionally uses an existing file as an input data source
+(i.e., "virtual mic")
 
 \code
 pcm.name {
@@ -647,7 +809,17 @@ pcm.name {
                 # or
                 pcm { }         # Slave PCM definition
         }
-	file STR		# Output filename
+	file STR		# Output filename (or shell command the stream
+				# will be piped to if STR starts with the pipe
+				# char).
+				# STR can contain format keys, replaced by
+				# real values corresponding to the stream:
+				# %r	rate (replaced with: 48000)
+				# %c	channels (replaced with: 2)
+				# %b	bytes per sample (replaced with: 2)
+				# %f	sample format string
+				#			(replaced with: S16_LE)
+				# %%	replaced with %
 	or
 	file INT		# Output file descriptor number
 	infile STR		# Input filename - only raw format
@@ -773,7 +945,7 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 	err = snd_pcm_slave_conf(root, slave, &sconf, 0);
 	if (err < 0)
 		return err;
-	if (!fname && fd < 0 && !ifname) {
+	if ((!fname || strlen(fname) == 0) && fd < 0 && !ifname) {
 		snd_config_delete(sconf);
 		SNDERR("file is not defined");
 		return -EINVAL;

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] PCM parameters in file plugin
  2009-01-29 10:54               ` Pavel Hofman
@ 2009-01-29 11:01                 ` Takashi Iwai
  0 siblings, 0 replies; 11+ messages in thread
From: Takashi Iwai @ 2009-01-29 11:01 UTC (permalink / raw)
  To: Pavel Hofman; +Cc: alsa-devel

At Thu, 29 Jan 2009 11:54:18 +0100,
Pavel Hofman wrote:
> 
> Takashi Iwai wrote:
> > 
> > Thanks, it gets better now.
> > 
> >> +static int snd_pcm_file_replace_key(char format, const void *value_p,
> >> +		char **string_p, char **index_ch_p, int *len_p)
> > 
> > I think it could be easier to make value_str in the caller side.
> > That is,
> > ........
> 
> Hi Takashi,
> 
> Thanks for your valuable comments. I am enclosing a fixed and tested 
> version.

Thanks for a quick fix!  Now I applied your patch to GIT tree.
For further improvements / optimizations, please submit a patch
against it.


Takashi

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2009-01-29 11:01 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-01-05 20:54 PCM parameters in file plugin Pavel Hofman
2009-01-06  9:51 ` Pavel Hofman
2009-01-06 10:31   ` Jaroslav Kysela
2009-01-06 11:33     ` Pavel Hofman
2009-01-19 22:20       ` [PATCH] " Pavel Hofman
2009-01-26 14:28         ` Pavel Hofman
2009-01-28 15:41         ` Takashi Iwai
2009-01-28 23:00           ` Pavel Hofman
2009-01-29  8:28             ` Takashi Iwai
2009-01-29 10:54               ` Pavel Hofman
2009-01-29 11:01                 ` Takashi Iwai

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.