Исходный код утилиты waverec
Приложение захватывает аудио данные и записывате их в .wav файл:
/** (c) 2014, SWD Embedded Systems Limited, http://www.kpda.ru*//** $QNXLicenseC:* Copyright 2007, QNX Software Systems. All Rights Reserved.** You must obtain a written license from and pay applicable license fees to QNX* Software Systems before you may reproduce, modify or distribute this software,* or any work that includes all or part of this software. Free development* licenses are available for evaluation and non-commercial purposes. For more* information visit http://licensing.qnx.com or email licensing@qnx.com.** This file may contain contributions from others. Please review this entire* file for other proprietary rights or license notices, as well as the QNX* Development Suite License Guide at http://licensing.qnx.com/license-guide/* for other information.* $*/#include <errno.h>#include <fcntl.h>#include <gulliver.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/ioctl.h>#include <sys/select.h>#include <sys/stat.h>#include <sys/termio.h>#include <sys/types.h>#include <unistd.h>#include <limits.h>#include <ctype.h>#include <sys/asoundlib.h>struct {char riff_id[4];char wave_len[4];struct {char fmt_id[8];char fmt_len[4];struct {char format_tag[2];char voices[2];char rate[4];char char_per_sec[4];char block_align[2];char bits_per_sample[2];} fmt;struct {char data_id[4];char data_len[4];} data;} wave;} riff_hdr = { { 'R', 'I', 'F', 'F' },{ sizeof( riff_hdr.wave ), 0, 0, 0 },{ {'W', 'A', 'V', 'E', 'f', 'm', 't', ' ' },{ sizeof( riff_hdr.wave.fmt ), 0, 0, 0 },{ { 1, 0 },{ 0, 0 },{ 0, 0, 0, 0 },{ 0, 0 },{ 0, 0 } },{ { 'd', 'a', 't', 'a' },{ 0, 0, 0, 0 } } } };int err( char *msg ){perror( msg );return (-1);}int dev_raw( int fd ){struct termios termios_p;if ( tcgetattr( fd, &termios_p ) )return (-1);termios_p.c_cc[VMIN] = 1;termios_p.c_cc[VTIME] = 0;termios_p.c_lflag &= ~(ECHO | ICANON | ISIG | ECHOE | ECHOK | ECHONL);termios_p.c_oflag &= ~(OPOST);return (tcsetattr( fd, TCSANOW, &termios_p ));}int dev_unraw( int fd ){struct termios termios_p;if ( tcgetattr( fd, &termios_p ) )return (-1);termios_p.c_lflag |= (ECHO | ICANON | ISIG | ECHOE | ECHOK | ECHONL);termios_p.c_oflag |= (OPOST);return (tcsetattr( fd, TCSAFLUSH, &termios_p ));}//*****************************************************************************#ifdef __USAGE%C[Options] *Options:-8 use 8 bit mode (16 bit default)-a[card#:]<dev#> the card & device number to record from-m record in mono (stereo default)-r <rate> record at rate (44100 default | 48000 44100 22050 11025)-t <sec> seconds to record (5 seconds default)-f <frag_size> requested fragment size-v verbosity-c <args>[,args ...] voice matrix configurationArgs:1=<hw_channel_bitmask> hardware channel bitmask for application voice 12=<hw_channel_bitmask> hardware channel bitmask for application voice 23=<hw_channel_bitmask> hardware channel bitmask for application voice 34=<hw_channel_bitmask> hardware channel bitmask for application voice 4#endif//*****************************************************************************int main( int argc, char **argv ){int card = -1;int dev = 0;snd_pcm_t *pcm_handle;FILE *file1;int mSamples;int mSampleRate;int mSampleChannels;int mSampleBits;int mSampleTime;char *mSampleBfr1;int fragsize = -1;int verbose = 0;int rtn;snd_pcm_channel_info_t pi;snd_mixer_t *mixer_handle;snd_mixer_group_t group;snd_pcm_channel_params_t pp;snd_pcm_channel_setup_t setup;int bsize,n,N = 0,c;uint32_t voice_mask[] = { 0, 0, 0, 0 };snd_pcm_voice_conversion_t voice_conversion;int voice_override = 0;char *sub_opts,*value;char *dev_opts[] = { "1",#define CHN1 0"2",#define CHN2 1"3",#define CHN3 2"4",#define CHN4 3NULL };char name[_POSIX_PATH_MAX] = { 0 };fd_set rfds;mSampleRate = 44100;mSampleChannels = 2;mSampleBits = 16;mSampleTime = 5;while ( (c = getopt( argc, argv, "8a:f:mr:t:vc:" )) != EOF ){switch ( c ){case '8':mSampleBits = 8;break;case 'a':if ( strchr( optarg, ':' ) ){card = atoi( optarg );dev = atoi( strchr( optarg, ':' ) + 1 );} elseif ( isalpha( optarg[0] ) )strcpy( name, optarg );elsedev = atoi( optarg );if ( name[0] != '\0' )printf( "Using device /dev/snd/%s\n", name );elseprintf( "Using card %d device %d \n", card, dev );break;case 'f':fragsize = atoi( optarg );break;case 'm':mSampleChannels = 1;break;case 'r':mSampleRate = atoi( optarg );break;case 't':mSampleTime = atoi( optarg );break;case 'v':verbose = 1;break;case 'c':sub_opts = strdup( optarg );while ( *sub_opts != '\0' ){switch ( getsubopt( &sub_opts, dev_opts, &value ) ){case CHN1:voice_mask[0] = strtoul( value, NULL, 0 );break;case CHN2:voice_mask[1] = strtoul( value, NULL, 0 );break;case CHN3:voice_mask[2] = strtoul( value, NULL, 0 );break;case CHN4:voice_mask[3] = strtoul( value, NULL, 0 );break;default:break;}}voice_override = 1;break;default:return (1);}}setvbuf( stdin, NULL, _IONBF, 0 );if ( name[0] != '\0' ){snd_pcm_info_t info;if ( (rtn = snd_pcm_open_name( &pcm_handle, name, SND_PCM_OPEN_CAPTURE )) < 0 )return err( "open_name" );rtn = snd_pcm_info( pcm_handle, &info );card = info.card;} else {if ( card == -1 ){if ( (rtn = snd_pcm_open_preferred( &pcm_handle, &card, &dev, SND_PCM_OPEN_CAPTURE )) < 0 )return err( "device open" );} else {if ( (rtn = snd_pcm_open( &pcm_handle, card, dev, SND_PCM_OPEN_CAPTURE )) < 0 )return err( "device open" );}}if ( argc < 2 )return err( "no file specified" );if ( (file1 = fopen( argv[optind], "w" )) == 0 )return err( "file open #1" );mSamples = mSampleRate * mSampleChannels * mSampleBits / 8 * mSampleTime;*(short *)riff_hdr.wave.fmt.voices = ENDIAN_LE16( mSampleChannels );*(long *)riff_hdr.wave.fmt.rate = ENDIAN_LE32( mSampleRate );*(long *)riff_hdr.wave.fmt.char_per_sec = ENDIAN_LE32( mSampleRate * mSampleChannels * mSampleBits / 8 );*(short *)riff_hdr.wave.fmt.block_align = ENDIAN_LE16( mSampleChannels * mSampleBits / 8 );*(short *)riff_hdr.wave.fmt.bits_per_sample = ENDIAN_LE16( mSampleBits );*(long *)riff_hdr.wave.data.data_len = ENDIAN_LE32( mSamples );*(long *)riff_hdr.wave_len = ENDIAN_LE32( mSamples + sizeof( riff_hdr ) - 8 );fwrite( &riff_hdr, 1, sizeof( riff_hdr ), file1 );printf( "SampleRate = %d, Channels = %d, SampleBits = %d\n", mSampleRate, mSampleChannels, mSampleBits );/* disabling mmap is not actually required in this example but it is included to* demonstrate how it is used when it is required. */if ( (rtn = snd_pcm_plugin_set_disable( pcm_handle, PLUGIN_DISABLE_MMAP )) < 0 ){fprintf( stderr, "snd_pcm_plugin_set_disable failed: %s\n", snd_strerror( rtn ) );return (-1);}memset( &pi, 0, sizeof( pi ) );pi.channel = SND_PCM_CHANNEL_CAPTURE;if ( (rtn = snd_pcm_plugin_info( pcm_handle, &pi )) < 0 ){fprintf( stderr, "snd_pcm_plugin_info failed: %s\n", snd_strerror( rtn ) );return (-1);}memset( &pp, 0, sizeof( pp ) );pp.mode = SND_PCM_MODE_BLOCK;pp.channel = SND_PCM_CHANNEL_CAPTURE;pp.start_mode = SND_PCM_START_DATA;pp.stop_mode = SND_PCM_STOP_STOP;pp.buf.block.frag_size = pi.max_fragment_size;if ( fragsize != -1 )pp.buf.block.frag_size = fragsize;pp.buf.block.frags_max = -1;pp.buf.block.frags_min = 1;pp.format.interleave = 1;pp.format.rate = mSampleRate;pp.format.voices = mSampleChannels;if ( mSampleBits == 8 )pp.format.format = SND_PCM_SFMT_U8;elsepp.format.format = SND_PCM_SFMT_S16_LE;if ( (rtn = snd_pcm_plugin_params( pcm_handle, &pp )) < 0 ){fprintf( stderr, "snd_pcm_plugin_params failed: %s\n", snd_strerror( rtn ) );return (-1);}if ( (rtn = snd_pcm_plugin_prepare( pcm_handle, SND_PCM_CHANNEL_CAPTURE )) < 0 )fprintf( stderr, "snd_pcm_plugin_prepare failed: %s\n", snd_strerror( rtn ) );if ( voice_override ){snd_pcm_plugin_get_voice_conversion( pcm_handle, SND_PCM_CHANNEL_CAPTURE, &voice_conversion );voice_conversion.matrix[0] = voice_mask[0];voice_conversion.matrix[1] = voice_mask[1];voice_conversion.matrix[2] = voice_mask[2];voice_conversion.matrix[3] = voice_mask[3];snd_pcm_plugin_set_voice_conversion( pcm_handle, SND_PCM_CHANNEL_CAPTURE, &voice_conversion );}memset( &setup, 0, sizeof( setup ) );memset( &group, 0, sizeof( group ) );setup.channel = SND_PCM_CHANNEL_CAPTURE;setup.mixer_gid = &group.gid;if ( (rtn = snd_pcm_plugin_setup( pcm_handle, &setup )) < 0 ){fprintf( stderr, "snd_pcm_plugin_setup failed: %s\n", snd_strerror( rtn ) );return (-1);}printf( "Format %s \n", snd_pcm_get_format_name( setup.format.format ) );printf( "Frag Size %d \n", setup.buf.block.frag_size );printf( "Rate %d \n", setup.format.rate );bsize = setup.buf.block.frag_size;if ( group.gid.name[0] == 0 ){printf( "Mixer Pcm Group [%s] Not Set \n", group.gid.name );printf( "***>>>> Input Gain Controls Disabled <<<<*** \n" );} elseprintf( "Mixer Pcm Group [%s]\n", group.gid.name );if ( (rtn = snd_mixer_open( &mixer_handle, card, setup.mixer_device )) < 0 ){fprintf( stderr, "snd_mixer_open failed: %s\n", snd_strerror( rtn ) );return (-1);}mSampleBfr1 = malloc( bsize );FD_ZERO( &rfds );n = 1;while ( N < mSamples && n > 0 ){FD_SET( STDIN_FILENO, &rfds );FD_SET( snd_mixer_file_descriptor( mixer_handle ), &rfds );FD_SET( snd_pcm_file_descriptor( pcm_handle, SND_PCM_CHANNEL_CAPTURE ), &rfds );rtn = max( snd_mixer_file_descriptor( mixer_handle ),snd_pcm_file_descriptor( pcm_handle, SND_PCM_CHANNEL_CAPTURE ) );if ( select( rtn + 1, &rfds, NULL, NULL, NULL ) == -1 )return err( "select" );if ( FD_ISSET( STDIN_FILENO, &rfds ) ){dev_raw( fileno( stdin ) );c = getc( stdin );dev_unraw( fileno( stdin ) );if ( c != EOF ){if ( group.gid.name[0] != 0 ){if ( (rtn = snd_mixer_group_read( mixer_handle, &group )) < 0 )fprintf( stderr, "snd_mixer_group_read failed: %s\n", snd_strerror( rtn ) );switch ( c ){case 'q':group.volume.names.front_left += 1;break;case 'a':group.volume.names.front_left -= 1;break;case 'w':group.volume.names.front_left += 1;group.volume.names.front_right += 1;break;case 's':group.volume.names.front_left -= 1;group.volume.names.front_right -= 1;break;case 'e':group.volume.names.front_right += 1;break;case 'd':group.volume.names.front_right -= 1;break;}if ( group.volume.names.front_left > group.max )group.volume.names.front_left = group.max;if ( group.volume.names.front_left < group.min )group.volume.names.front_left = group.min;if ( group.volume.names.front_right > group.max )group.volume.names.front_right = group.max;if ( group.volume.names.front_right < group.min )group.volume.names.front_right = group.min;if ( (rtn = snd_mixer_group_write( mixer_handle, &group )) < 0 )fprintf( stderr, "snd_mixer_group_write failed: %s\n", snd_strerror( rtn ) );printf ( "Volume Now at %d:%d \n",100 * (group.volume.names.front_left - group.min) / (group.max - group.min),100 * (group.volume.names.front_right - group.min) / (group.max - group.min));}} elseexit( 0 );}if ( FD_ISSET( snd_mixer_file_descriptor( mixer_handle ), &rfds ) ){snd_mixer_callbacks_t callbacks = { 0, 0, 0, 0 };snd_mixer_read( mixer_handle, &callbacks );}if ( FD_ISSET( snd_pcm_file_descriptor( pcm_handle, SND_PCM_CHANNEL_CAPTURE ), &rfds ) ){snd_pcm_channel_status_t status;int read = 0;read = snd_pcm_plugin_read( pcm_handle, mSampleBfr1, bsize );if ( verbose )printf( "bytes read = %d \n", read );if ( read < n ){memset( &status, 0, sizeof( status ) );status.channel = SND_PCM_CHANNEL_CAPTURE;if ( snd_pcm_plugin_status( pcm_handle, &status ) < 0 ){fprintf( stderr, "overrun: capture channel status error\n" );exit( 1 );}if ( status.status == SND_PCM_STATUS_READY || status.status == SND_PCM_STATUS_OVERRUN ){if ( snd_pcm_plugin_prepare( pcm_handle, SND_PCM_CHANNEL_CAPTURE ) < 0 ){fprintf( stderr, "overrun: capture channel prepare error\n" );exit( 1 );}}}fwrite( mSampleBfr1, 1, read, file1 );N += read;}}n = snd_pcm_plugin_flush( pcm_handle, SND_PCM_CHANNEL_CAPTURE );rtn = snd_mixer_close( mixer_handle );rtn = snd_pcm_close( pcm_handle );fclose( file1 );return (0);}
Предыдущий раздел: Библиотека libasound