crec: Initial version of a compressed capture utility
PATCH 1/2 crec: Initial version of a compressed capture utility
This version only supports capture of PCM streams over a compressed device and saves these as WAV files.
--- Android.mk | 10 ++ crec.c | 425 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ makefile.linux | 20 ++- 3 files changed, 448 insertions(+), 7 deletions(-) create mode 100644 crec.c
Android.mk +10 -0
@@ -20,3 +20,13 @@ LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) +include $(CLEAR_VARS) + +LOCAL_C_INCLUDES:= $(LOCAL_PATH)/include +LOCAL_SRC_FILES:= crec.c +LOCAL_MODULE := crec +LOCAL_SHARED_LIBRARIES:= libcutils libutils libtinycompress +LOCAL_MODULE_TAGS := optional + +include $(BUILD_EXECUTABLE) +
crec.c new file +425 -0
425 lines not on this page · raw message
makefile.linux +13 -7
@@ -1,10 +1,13 @@ LIB = libtinycompress -BIN = cplay VER = 0.1 LIBSRC = compress.c -SRC = cplay.c utils.c +PLAYBIN = cplay +RECBIN = crec +PLAYSRC = cplay.c utils.c +RECSRC = crec.c utils.c LIBOBJ = ${LIBSRC:.c=.o} -OBJ = ${SRC:.c=.o} +PLAYOBJ = ${PLAYSRC:.c=.o} +RECOBJ = ${RECSRC:.c=.o} CC = gcc CROSS_COMPILE =
@@ -13,23 +16,26 @@ CFLAGS += -std=c99 -Wall -Wextra -Wunused -DVERSION=\"${VER}\" -I./include LDFLAGS += -L. -ltinycompress LIBLDFLAGS = -lasound -all: libtinycompress cplay +all: libtinycompress cplay crec $(LIB): ${LIBOBJ} @echo " LD "$@ @${CROSS_COMPILE}${CC} ${CFLAGS} -shared -Wl,-soname,[email protected] -o [email protected] ${LIBOBJ} ${LIBLDFLAGS} -$(BIN): ${OBJ} ${LIB} +$(PLAYBIN): ${PLAYOBJ} ${LIB} @echo " LD "$@ - @${CROSS_COMPILE}${CC} ${CFLAGS} -o $@ ${OBJ} ${LDFLAGS} + @${CROSS_COMPILE}${CC} ${CFLAGS} -o $@ ${PLAYOBJ} ${LDFLAGS} +$(RECBIN): ${RECOBJ} ${LIB} + @echo " LD "$@ + @${CROSS_COMPILE}${CC} ${CFLAGS} -o $@ ${RECOBJ} ${LDFLAGS} %.o: %.c @echo " CC "$< @${CROSS_COMPILE}${CC} ${CFLAGS} -c -fPIC -o $@ $< clean: - @rm -rf ${BIN} ${OBJ} ${LIB}.so ${LIBOBJ} + @rm -rf ${BIN} ${PLAYOBJ} ${RECOBJ} ${LIB}.so ${LIBOBJ} .PHONY: all clean
Signature · 1 line
1.7.2.5
PATCH 2/2 crec: Add primitive exception handling
Add very primitive signal handling, we will not attempt to drain any remaining data etc. simply save out what we have to a file.
--- crec.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 77 insertions(+), 13 deletions(-)
crec.c +77 -13
@@ -74,6 +74,7 @@#include "tinycompress/tinycompress.h" static int verbose; +static FILE *file;static const unsigned int DEFAULT_CHANNELS =1 ;static const unsigned int DEFAULT_RATE =44100 ;
@@ -183,6 +184,62 @@ static int print_time(struct compress *compress)return 0 ; } +static int finish_record () +{ +struct wave_header header; +int ret; +size_t read, written; + +if (!file) +return -ENOENT ; + +/* Get amount of data written to file */ + ret =fseek (file,0 ,SEEK_END ); +if (ret <0 ) + goto seek_error; + ret =ftell (file); +if (ret <0 ) { +fprintf (stderr,"Error reading file position: %s\n" , +strerror (errno)); +return errno; + } + written = ret; +if (written <sizeof (header)) { +fprintf (stderr,"No data recorded!\n" ); +return -ENOENT ; + } + written -=sizeof (header); + +/* Sync file header from file */ + ret =fseek (file,0 ,SEEK_SET ); +if (ret <0 ) + goto seek_error; + read =fread (&header,sizeof (header),1 , file); +if (read !=1 ) { + ret =ferror (file); +fprintf (stderr,"Error reading output file header: %d\n" , ret); +return ret; + } + +/* Update file header */ + ret =fseek (file,0 ,SEEK_SET ); +if (ret <0 ) + goto seek_error; +size_wave_header (&header, written); + written =fwrite (&header,sizeof (header),1 , file); +if (written !=1 ) { + ret =ferror (file); +fprintf (stderr,"Error updating output file header: %d\n" , ret); +return ret; + } + +return 0 ; + +seek_error: +fprintf (stderr,"Error seeking: %s\n" ,strerror (errno)); +return errno; +} + void capture_samples(char *name, unsigned int card, unsigned int device, unsigned long buffer_size, unsigned int frag, unsigned int length, unsigned int rate,
@@ -192,7 +249,6 @@ void capture_samples(char *name, unsigned int card, unsigned int device,struct snd_codec codec;struct compress *compress;struct wave_header header; -FILE *file;char *buffer;size_t written;int read, ret;
@@ -318,25 +374,16 @@ void capture_samples(char *name, unsigned int card, unsigned int device,fprintf (stderr,"ERR: %s\n" ,compress_get_error (compress)); } -/* Update file header now we know file size */ -size_wave_header (&header, total_read); - ret =fseek (file,0 ,SEEK_SET ); -if (ret <0 ) { -fprintf (stderr,"Error seeking: %s\n" ,stderror (errno)); + ret =finish_record (); +if (ret <0 ) goto buf_exit; - } - written =fwrite (&header,sizeof (header),1 , file); -if (written !=1 ) { -fprintf (stderr,"Error updating output file header: %d\n" , -ferror (file)); - goto buf_exit; - }if (verbose)printf ("%s: exit success\n" , __func__);free (buffer);fclose (file); + file =NULL ;compress_close (compress);
@@ -354,6 +401,18 @@ file_exit:exit (EXIT_FAILURE ); } +static void sig_handler (int signum __attribute__ ((unused))) +{ +printf ("Interrupted, saving what we have!\n" ); + +finish_record (); + +if (file) +fclose (file); + +_exit (EXIT_FAILURE ); +} +int main (int argc,char **argv) {char *file;
@@ -363,6 +422,11 @@ int main(int argc, char **argv)unsigned int rate =DEFAULT_RATE , channels =DEFAULT_CHANNELS ;unsigned int format =DEFAULT_FORMAT ; +if (signal (SIGINT , sig_handler) ==SIG_ERR ) { +fprintf (stderr,"Error registering signal handler\n" ); +exit (EXIT_FAILURE ); + } +if (argc <2 )usage ();
Signature · 1 line
1.7.2.5
Quoted 2 lines · Charles Keepax
This version only supports capture of PCM streams over a compressed device and saves these as WAV files.
Thanks for posting this :) I was about to ping you ad get these done if you were busy...
crec.c line 157
Quoted 9 lines
crec.c new file +9
-0+static void usage (void ) +{ +fprintf (stderr,"usage: crec [OPTIONS] filename\n" +"-c\tcard number\n" +"-d\tdevice node\n" +"-b\tbuffer size\n" +"-f\tfragments\n" +"-v\tverbose mode\n" + "-l\tlength of record in seconds\n"
perhaps it would be more intutive for time. We cant use d here :(
crec.c line 160
Quoted 3 lines
crec.c new file +3
-0+"-h\tPrints this help list\n\n" +"-C\tSpecify the number of channels (default %u)\n" +"-R\tSpecify the sample rate (default %u)\n"
can these be lower case?
Quoted 47 lines
crec.c new file +47
-0+"-F\tSpecify the format: S16_LE, S32_LE (default S16_LE)\n\n" +"Example:\n" +"\tcrec -c 1 -d 2 test.wav\n" +"\tcrec -f 5 test.wav\n" , + DEFAULT_CHANNELS, DEFAULT_RATE); + +exit (EXIT_FAILURE ); +} + +static int print_time (struct compress *compress) +{ +unsigned int avail; +struct timespec tstamp; + +if (compress_get_hpointer (compress, &avail, &tstamp) !=0 ) { +fprintf (stderr,"Error querying timestamp\n" ); +fprintf (stderr,"ERR: %s\n" ,compress_get_error (compress)); +return -1 ; + }else { +printf ("DSP recorded %jd.%jd\n" , + (intmax_t )tstamp.tv_sec, (intmax_t )tstamp.tv_nsec*1000 ); + } +return 0 ; +} + +void capture_samples (char *name,unsigned int card,unsigned int device, +unsigned long buffer_size,unsigned int frag, +unsigned int length,unsigned int rate, +unsigned int channels,unsigned int format) +{ +struct compr_config config; +struct snd_codec codec; +struct compress *compress; +struct wave_header header; +FILE *file; +char *buffer; +size_t written; +int read, ret; +unsigned int size, total_read =0 ; +unsigned int samplebits; + +switch (format) { +case SNDRV_PCM_FORMAT_S32_LE : + samplebits =32 ; +break ; +default : + samplebits =16 ;
crec.c line 217
Quoted 10 lines
crec.c new file +10
-0+break ; + } + +/* Convert length from seconds to bytes */ + length = length * rate * (samplebits /8 ) * channels; + +if (verbose) +printf ("%s: entry, reading %u bytes\n" , __func__, length); + + file =fopen (name,"w+b" );
why w+?
Quoted 18 lines
crec.c new file +18
-0+if (!file) { +fprintf (stderr,"Unable to open file '%s'\n" , name); +exit (EXIT_FAILURE ); + } + +/* Write a header, will update with size once record is complete */ +init_wave_header (&header, channels, rate, samplebits); + written =fwrite (&header,sizeof (header),1 , file); +if (written !=1 ) { +fprintf (stderr,"Error writing output file header: %d\n" , +ferror (file)); + goto file_exit; + } + + codec.id =SND_AUDIOCODEC_PCM ; + codec.ch_in = channels; + codec.ch_out = channels; + codec.sample_rate =compress_get_alsa_rate (rate);
crec.c line 245
Quoted 10 lines
crec.c new file +10
-0+if (!codec.sample_rate) { +fprintf (stderr,"invalid sample rate %d\n" , rate); + goto file_exit; + } + codec.bit_rate =0 ; + codec.rate_control =0 ; + codec.profile =0 ; + codec.level =0 ; + codec.ch_mode =0 ; + codec.format = format;
why not do memset of the codec and configure only what we need...
rest looks okay to me
--
~Vinod
Quoted 5 lines · Vinod Koul
Quoted 2 lines · Charles Keepax
This version only supports capture of PCM streams over a compressed device and saves these as WAV files.
Thanks for posting this :) I was about to ping you ad get these done if you were busy...
Sorry about the delay on looking at this again, I keep getting pulled off in other directions :-)
Quoted 10 lines
crec.c line 157
Quoted 9 lines
crec.c new file +9
-0+static void usage (void ) +{ +fprintf (stderr,"usage: crec [OPTIONS] filename\n" +"-c\tcard number\n" +"-d\tdevice node\n" +"-b\tbuffer size\n" +"-f\tfragments\n" +"-v\tverbose mode\n" + "-l\tlength of record in seconds\n"perhaps it would be more intutive for time. We cant use d here :(
Yeah can't use 'd', I guess I could use 't' if preferred?
Quoted 5 lines
crec.c line 160
Quoted 4 lines
crec.c new file +3
-0+"-h\tPrints this help list\n\n" +"-C\tSpecify the number of channels (default %u)\n" +"-R\tSpecify the sample rate (default %u)\n" can these be lower case?
Unfortunately, 'c', card and 'f', fragments are both used so I opted to use capitals for the stream parameters (channels, rate, format). I am open to changing these to something else but you end up using weird letters for things and caps felt most clear.
Quoted 9 lines
Quoted 9 lines
crec.c new file +8
-0+"-F\tSpecify the format: S16_LE, S32_LE (default S16_LE)\n\n" +"Example:\n" +"\tcrec -c 1 -d 2 test.wav\n" +"\tcrec -f 5 test.wav\n" , + DEFAULT_CHANNELS, DEFAULT_RATE); + +exit (EXIT_FAILURE ); +}
<snip>
Quoted 5 lines
crec.c line 217
Quoted 4 lines
crec.c new file +4
-0+if (verbose) +printf ("%s: entry, reading %u bytes\n" , __func__, length); + + file =fopen (name,"w+b" );why w+?
Oops, yeah that should be changed.
Quoted 21 lines
Quoted 21 lines
crec.c new file +21
-0+if (!file) { +fprintf (stderr,"Unable to open file '%s'\n" , name); +exit (EXIT_FAILURE ); + } + +/* Write a header, will update with size once record is complete */ +init_wave_header (&header, channels, rate, samplebits); + written =fwrite (&header,sizeof (header),1 , file); +if (written !=1 ) { +fprintf (stderr,"Error writing output file header: %d\n" , +ferror (file)); + goto file_exit; + } + + codec.id =SND_AUDIOCODEC_PCM ; + codec.ch_in = channels; + codec.ch_out = channels; + codec.sample_rate =compress_get_alsa_rate (rate); +if (!codec.sample_rate) { +fprintf (stderr,"invalid sample rate %d\n" , rate); + goto file_exit;
Quoted 8 lines
crec.c line 245
Quoted 7 lines
crec.c new file +7
-0+ } + codec.bit_rate =0 ; + codec.rate_control =0 ; + codec.profile =0 ; + codec.level =0 ; + codec.ch_mode =0 ; + codec.format = format;why not do memset of the codec and configure only what we need...
Yeah, that is a good point I will update this as well.
Thanks,
Charles