Исходный код утилиты wave
Приложение проигрывает .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 <sys/slogcodes.h>#include <ctype.h>#include <limits.h>#include <sys/asoundlib.h>const char *kRiffId = "RIFF";const char *kWaveId = "WAVE";typedef struct {char tag[4];long length;} RiffTag;typedef struct {char Riff[4];long Size;char Wave[4];} RiffHdr;typedef struct {short FormatTag;short Channels;long SamplesPerSec;long AvgBytesPerSec;short BlockAlign;short BitsPerSample;} WaveHdr;int err( char *msg ){perror( msg );return (-1);}int FindTag( FILE *fp, const char *tag ){int retVal = 0;RiffTag tagBfr = { "", 0 };// Keep reading until we find the tag or hit the EOF.while ( fread( (unsigned char *)&tagBfr, sizeof( tagBfr ), 1, fp ) ){// If this is our tag, set the length and break.if ( strncmp( tag, tagBfr.tag, sizeof tagBfr.tag ) == 0 ){retVal = ENDIAN_LE32( tagBfr.length );break;}// Skip ahead the specified number of bytes in the streamfseek( fp, tagBfr.length, SEEK_CUR );}// Return the result of our operationreturn (retVal);}int CheckHdr( FILE *fp ){RiffHdr riffHdr = { "", 0 };// Read the header and, if successful, play the file file or WAVE file.if ( fread( (unsigned char *)&riffHdr, sizeof( RiffHdr ), 1, fp ) == 0 )return (0);if ( strncmp( riffHdr.Riff, kRiffId, strlen( kRiffId ) ) ||strncmp( riffHdr.Wave, kWaveId, strlen( kWaveId ) ) )return (-1);return (0);}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:-a[card#:]<dev#> the card & device number to play out on-f<frag_size> requested fragment size-v verbose-c<args>[,args ..] voice matrix configuration-n<num_frags> requested number of fragmentsArgs: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;WaveHdr wavHdr1;int mSamples;int mSampleRate;int mSampleChannels;int mSampleBits;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;fd_set rfds,wfds;uint32_t voice_mask[] = { 0, 0, 0, 0 };snd_pcm_voice_conversion_t voice_conversion;int voice_override = 0;int num_frags = -1;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 };while ( (c = getopt( argc, argv, "a:f:vc:n:" )) != EOF ){switch ( c ){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 '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;case 'n':num_frags = atoi( optarg ) - 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_PLAYBACK )) < 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_PLAYBACK )) < 0 )return err( "device open" );} else {if ( (rtn = snd_pcm_open( &pcm_handle, card, dev, SND_PCM_OPEN_PLAYBACK )) < 0 )return err( "device open" );}}if ( argc < 2 )return err( "no file specified" );if ( (file1 = fopen( argv[optind], "r" )) == 0 )return err( "file open #1" );if ( CheckHdr( file1 ) == -1 )return err( "CheckHdr #1" );mSamples = FindTag( file1, "fmt " );fread( &wavHdr1, sizeof( wavHdr1 ), 1, file1 );fseek( file1, (mSamples - sizeof( WaveHdr )), SEEK_CUR );mSampleRate = ENDIAN_LE32( wavHdr1.SamplesPerSec );mSampleChannels = ENDIAN_LE16( wavHdr1.Channels );mSampleBits = ENDIAN_LE16( wavHdr1.BitsPerSample );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_PLAYBACK;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_PLAYBACK;pp.start_mode = SND_PCM_START_FULL;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 = num_frags;pp.buf.block.frags_min = 1;pp.format.interleave = 1;pp.format.rate = mSampleRate;pp.format.voices = mSampleChannels;if ( ENDIAN_LE16( wavHdr1.FormatTag ) == 6 )pp.format.format = SND_PCM_SFMT_A_LAW;else if ( ENDIAN_LE16( wavHdr1.FormatTag ) == 7 )pp.format.format = SND_PCM_SFMT_MU_LAW;else if ( mSampleBits == 8 )pp.format.format = SND_PCM_SFMT_U8;else if ( mSampleBits == 24 )pp.format.format = SND_PCM_SFMT_S24;elsepp.format.format = SND_PCM_SFMT_S16_LE;strcpy ( pp.sw_mixer_subchn_name, "Wave playback channel" );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_PLAYBACK )) < 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_PLAYBACK, &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_PLAYBACK, &voice_conversion );}memset( &setup, 0, sizeof( setup ) );memset( &group, 0, sizeof( group ) );setup.channel = SND_PCM_CHANNEL_PLAYBACK;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( "Total Frags %d \n", setup.buf.block.frags );printf( "Rate %d \n", setup.format.rate );printf( "Voices %d \n", setup.format.voices );bsize = setup.buf.block.frag_size;if ( group.gid.name[0] == 0 ){printf( "Mixer Pcm Group [%s] Not Set \n", group.gid.name );exit( -1 );}printf( "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);}mSamples = FindTag( file1, "data" );mSampleBfr1 = malloc( bsize );FD_ZERO( &rfds );FD_ZERO( &wfds );n = 1;while ( N < mSamples && n > 0 ){if ( tcgetpgrp( 0 ) == getpid() )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_PLAYBACK ), &wfds );rtn = max( snd_mixer_file_descriptor( mixer_handle ),snd_pcm_file_descriptor( pcm_handle, SND_PCM_CHANNEL_PLAYBACK ) );if ( select( rtn + 1, &rfds, &wfds, NULL, NULL ) == -1 )return err( "select" );if ( FD_ISSET( STDIN_FILENO, &rfds ) ){if ( (rtn = snd_mixer_group_read( mixer_handle, &group )) < 0 )fprintf( stderr, "snd_mixer_group_read failed: %s\n", snd_strerror( rtn ) );dev_raw( fileno( stdin ) );c = getc( stdin );dev_unraw( fileno( stdin ) );if ( c != EOF ){switch ( c ){case 'q':if ( group.channels & SND_MIXER_CHN_MASK_FRONT_LEFT )group.volume.names.front_left += 10;if ( group.channels & SND_MIXER_CHN_MASK_REAR_LEFT )group.volume.names.rear_left += 10;if ( group.channels & SND_MIXER_CHN_MASK_WOOFER )group.volume.names.woofer += 10;break;case 'a':if ( group.channels & SND_MIXER_CHN_MASK_FRONT_LEFT )group.volume.names.front_left -= 10;if ( group.channels & SND_MIXER_CHN_MASK_REAR_LEFT )group.volume.names.rear_left -= 10;if ( group.channels & SND_MIXER_CHN_MASK_WOOFER )group.volume.names.woofer -= 10;break;case 'w':if ( group.channels & SND_MIXER_CHN_MASK_FRONT_LEFT )group.volume.names.front_left += 10;if ( group.channels & SND_MIXER_CHN_MASK_REAR_LEFT )group.volume.names.rear_left += 10;if ( group.channels & SND_MIXER_CHN_MASK_FRONT_CENTER )group.volume.names.front_center += 10;if ( group.channels & SND_MIXER_CHN_MASK_FRONT_RIGHT )group.volume.names.front_right += 10;if ( group.channels & SND_MIXER_CHN_MASK_REAR_RIGHT )group.volume.names.rear_right += 10;if ( group.channels & SND_MIXER_CHN_MASK_WOOFER )group.volume.names.woofer += 10;break;case 's':if ( group.channels & SND_MIXER_CHN_MASK_FRONT_LEFT )group.volume.names.front_left -= 10;if ( group.channels & SND_MIXER_CHN_MASK_REAR_LEFT )group.volume.names.rear_left -= 10;if ( group.channels & SND_MIXER_CHN_MASK_FRONT_CENTER )group.volume.names.front_center -= 10;if ( group.channels & SND_MIXER_CHN_MASK_FRONT_RIGHT )group.volume.names.front_right -= 10;if ( group.channels & SND_MIXER_CHN_MASK_REAR_RIGHT )group.volume.names.rear_right -= 10;if ( group.channels & SND_MIXER_CHN_MASK_WOOFER )group.volume.names.woofer -= 10;break;case 'e':if ( group.channels & SND_MIXER_CHN_MASK_FRONT_RIGHT )group.volume.names.front_right += 10;if ( group.channels & SND_MIXER_CHN_MASK_REAR_RIGHT )group.volume.names.rear_right += 10;if ( group.channels & SND_MIXER_CHN_MASK_FRONT_CENTER )group.volume.names.front_center += 10;break;case 'd':if ( group.channels & SND_MIXER_CHN_MASK_FRONT_RIGHT )group.volume.names.front_right -= 10;if ( group.channels & SND_MIXER_CHN_MASK_REAR_RIGHT )group.volume.names.rear_right -= 10;if ( group.channels & SND_MIXER_CHN_MASK_FRONT_CENTER )group.volume.names.front_center -= 10;break;}if ( group.channels & SND_MIXER_CHN_MASK_FRONT_LEFT ){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.channels & SND_MIXER_CHN_MASK_REAR_LEFT ){if ( group.volume.names.rear_left > group.max )group.volume.names.rear_left = group.max;if ( group.volume.names.rear_left < group.min )group.volume.names.rear_left = group.min;}if ( group.channels & SND_MIXER_CHN_MASK_FRONT_CENTER ){if ( group.volume.names.front_center > group.max )group.volume.names.front_center = group.max;if ( group.volume.names.front_center < group.min )group.volume.names.front_center = group.min;}if ( group.channels & SND_MIXER_CHN_MASK_FRONT_RIGHT ){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 ( group.channels & SND_MIXER_CHN_MASK_REAR_RIGHT ){if ( group.volume.names.rear_right > group.max )group.volume.names.rear_right = group.max;if ( group.volume.names.rear_right < group.min )group.volume.names.rear_right = group.min;}if ( group.channels & SND_MIXER_CHN_MASK_WOOFER ){if ( group.volume.names.woofer > group.max )group.volume.names.woofer = group.max;if ( group.volume.names.woofer < group.min )group.volume.names.woofer = group.min;}if ( (rtn = snd_mixer_group_write( mixer_handle, &group )) < 0 )fprintf( stderr, "snd_mixer_group_write failed: %s\n", snd_strerror( rtn ) );} elseexit( 0 );if ( group.channels & SND_MIXER_CHN_MASK_FRONT_LEFT ){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) );}else if ( group.channels & SND_MIXER_CHN_MASK_REAR_LEFT ){printf( "Volume Now at %d:%d \n",100 * (group.volume.names.rear_left - group.min) / (group.max - group.min),100 * (group.volume.names.rear_right - group.min) / (group.max - group.min) );}else if ( group.channels & SND_MIXER_CHN_MASK_WOOFER ){printf( "Volume Now at %d:%d \n",100 * (group.volume.names.woofer - group.min) / (group.max - group.min),100 * (group.volume.names.front_center - group.min) / (group.max - group.min));} else {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));}}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_PLAYBACK ), &wfds ) ){snd_pcm_channel_status_t status;int written = 0;if ( (n = fread( mSampleBfr1, 1, min( mSamples - N, bsize ), file1 )) <= 0 )continue;written = snd_pcm_plugin_write( pcm_handle, mSampleBfr1, n );if ( verbose )printf( "bytes written = %d \n", written );if ( written < n ){memset( &status, 0, sizeof( status ) );status.channel = SND_PCM_CHANNEL_PLAYBACK;if ( snd_pcm_plugin_status( pcm_handle, &status ) < 0 ){fprintf( stderr, "underrun: playback channel status error\n" );exit( 1 );}if ( status.status == SND_PCM_STATUS_READY || status.status == SND_PCM_STATUS_UNDERRUN ){if ( snd_pcm_plugin_prepare( pcm_handle, SND_PCM_CHANNEL_PLAYBACK ) < 0 ){fprintf( stderr, "underrun: playback channel prepare error\n" );exit( 1 );}}if ( written < 0 )written = 0;written += snd_pcm_plugin_write( pcm_handle, mSampleBfr1 + written, n - written );}N += written;}}n = snd_pcm_plugin_flush( pcm_handle, SND_PCM_CHANNEL_PLAYBACK );rtn = snd_mixer_close( mixer_handle );rtn = snd_pcm_close( pcm_handle );fclose( file1 );return (0);}
Предыдущий раздел: Библиотека libasound