# HG changeset patch # User Eris Caffee # Date 1406058146 18000 # Node ID 4d04dc4239b4b922719e380ab9151ae460fdaaa2 Simple demo programs for libao and libvorbisfile. diff -r 000000000000 -r 4d04dc4239b4 .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Tue Jul 22 14:42:26 2014 -0500 @@ -0,0 +1,3 @@ +^list_drivers$ +^playogg$ +^.*~$ diff -r 000000000000 -r 4d04dc4239b4 Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Tue Jul 22 14:42:26 2014 -0500 @@ -0,0 +1,12 @@ +SHELL = /bin/sh + +all: playogg list_drivers + +playogg: playogg.c playogg.h + gcc -o playogg playogg.c --std=gnu99 -lao -lvorbisfile + +list_drivers: list_drivers.c + gcc -o list_drivers list_drivers.c --std=gnu99 -lao + +clean: + rm -f list_drivers playogg diff -r 000000000000 -r 4d04dc4239b4 list_drivers.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/list_drivers.c Tue Jul 22 14:42:26 2014 -0500 @@ -0,0 +1,77 @@ +#include +#include + +#include + +/******************************************************************************/ + +void err_exit( char * msg ) + { + fprintf(stderr, "FATAL ERROR: %s\n", msg ? msg : "Unknown error" ); + exit( EXIT_FAILURE ); + } + + +/******************************************************************************/ + +int main ( int argc, char** argv ) + { + ao_initialize(); + + ao_info ** driver_list = NULL; + int driver_count = -1; + + driver_list = ao_driver_info_list( &driver_count ); + if ( driver_list == NULL ) + { + err_exit("Unable to get list of drivers"); + } + + printf( "Endianness: %s\n", ao_is_big_endian() ? "big" : "little" ); + + int default_driver_id = ao_default_driver_id(); + if ( -1 == default_driver_id ) + { + printf( "No default driver available\n" ); + } + + for ( int i = 0; i < driver_count; ++i ) + { + printf( "%s\n", driver_list[i]->name ); + int driver_id = ao_driver_id( driver_list[i]->short_name ); + if ( default_driver_id == driver_id ) + { + printf( "\tDEFAULT DRIVER\n" ); + } + printf( "\tshort name :\t%s\n", driver_list[i]->short_name ); + printf( "\ttype :\t%s\n", + driver_list[i]->type == AO_TYPE_LIVE ? "live" : + (driver_list[i]->type == AO_TYPE_FILE ? "file" : + "unknown") + ); + printf( "\tpriority :\t%d\n", driver_list[i]->priority ); + printf( "\tpreferred byte format:\t%s\n", + driver_list[i]->preferred_byte_format == AO_FMT_LITTLE ? "little" : + (driver_list[i]->preferred_byte_format == AO_FMT_BIG ? "big" : "unknown" ) + ); + +#if 0 + // Appears that ao-file_extension is not in my version of libao + char * ext = NULL; + ext = ao_file_extension( driver_id ); + printf( "\tnormal file extension:\t%s\n", ext == NULL ? "[none]" : ext ); +#endif + + printf( "\toptions :\t", driver_list[i]->comment); + for ( int j = 0; j < driver_list[i]->option_count ; ++j ) + { + printf( "%s ", driver_list[i]->options[j]); + } + printf("\n"); + + printf( "\tcomment :\t%s\n", driver_list[i]->comment); + } + + ao_shutdown(); + } + diff -r 000000000000 -r 4d04dc4239b4 playogg.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/playogg.c Tue Jul 22 14:42:26 2014 -0500 @@ -0,0 +1,399 @@ +#include +#include +#include + +#include +#include + +#include +#include + +#include "playogg.h" + +/******************************************************************************/ +static struct opts { + int debug; + int verbose; + int list_devices; + char* device; + char **files; + int skip_next; + int ao_endian; + int ao_device_id; + ao_device *ao_device; + ao_info *ao_driver_info; + ao_sample_format ao_format; + } options; + +int +main (int argc, char **argv ) { + + init(); + parse_command_line( argc, argv ); + + if ( ! sound_init() ) { + exit( EXIT_FAILURE ); + } + + if ( options.list_devices ) { + exit( sound_list_devices() ); + } + + char **file = options.files; + int ok = 1; + while (ok && file && *file) { + if ( options.verbose ) { + printf( "Next file: %s\n", *file ); + } + ok = sound_play_file( *file ); + file++; + } + + exit( EXIT_SUCCESS ); + } + +/******************************************************************************/ +void +sig_handler ( int sig ) { + if ( SIGINT == sig ) { + options.skip_next = 1; + } + } + +/******************************************************************************/ +void +err_exit ( char * msg ) { + fprintf(stderr, "FATAL ERROR: %s\n", msg ? msg : "Unknown error" ); + exit( EXIT_FAILURE ); + } + +/******************************************************************************/ +void +init ( void ) { + atexit( shutdown ); + + options.debug = 0; + options.verbose = 0; + options.device = NULL; + options.list_devices = 0; + options.files = NULL; + options.skip_next = 0; + options.ao_endian = 1; + options.ao_device_id = -1; + options.ao_device = NULL; + options.ao_driver_info = NULL; + memset( &options.ao_format, 0, sizeof(ao_sample_format) ); + + struct sigaction sigact; + memset( &sigact, 0, sizeof(sigact) ); + sigact.sa_handler = sig_handler; + sigaction( SIGINT, &sigact, NULL ); + + } + +/******************************************************************************/ +int +min ( int a, int b ) { + if (a <= b) { + return a; + } + else { + return b; + } + } + + +/******************************************************************************/ +void +parse_command_line (int argc, char **argv ) { + + static const char *short_options = "hd:l"; + static const struct option long_options[] = { + { "help", 0, 0, 'h' }, + { "verbose", 0, 0, 0 }, + { "debug", 0, 0, 0 }, + { "device", 1, 0, 'd' }, + { "list-devices", 0, 0, 'l' }, + { NULL, 0, NULL, 0} + }; + + int c; + int option_index = 0; + while (1) { + c = getopt_long( argc, argv, short_options, long_options, &option_index ); + + if ( -1 == c ) { + break; + } + + switch (c) { + + case 0: + 1; + int len = strlen( long_options[option_index].name ); + if ( 0 == strncmp( long_options[option_index].name, "verbose", min(len, 7) ) ) { + options.verbose = 1; + } + else if ( 0 == strncmp( long_options[option_index].name, "debug", min(len, 5) ) ) { + options.debug = 1; + } + else { + fprintf( stderr, "Unrecognized option on command line: --%s\n", optarg ); + show_help(); + exit( EXIT_FAILURE ); + } + + break; + + case 'h': + show_help(); + exit( EXIT_SUCCESS ); + break; + + case 'd': + options.device = strdup(optarg); + break; + + case 'l': + options.list_devices = 1; + break; + + case 'v': + options.verbose = 1; + break; + + default: + fprintf( stderr, "Unrecognized option on command line: -%c\n", c ); + show_help(); + exit( EXIT_FAILURE ); + break; + } + } + + if (optind < argc) { + options.files = calloc( argc - optind + 1, sizeof(char *) ); + int i = 0; + while ( optind < argc) { + options.files[i++] = argv[optind++]; + } + } + + if (options.debug) { + fprintf( stderr, "verbose: %d\n", options.verbose ); + fprintf( stderr, "debug : %d\n", options.debug ); + fprintf( stderr, "device : %s\n", options.device ); + fprintf( stderr, "list_devices : %d\n", options.list_devices ); + fprintf( stderr, "files : "); + char **ptr = options.files; + while (ptr && *ptr) { + fprintf( stderr, "%s ", *ptr ); + ptr++; + } + fprintf( stderr, "\n" ); + } + + } + +/******************************************************************************/ +void +shutdown ( void ) { + if ( options.device ) { + free( options.device ); + } + } + +/******************************************************************************/ +void +show_help ( void ) { + printf( + "Usage: myplayogg [-hlv] filename\n" + "\n" + "Play the Ogg Vorbis encoded file.\n" + "\n" + "Options:\n" + "\n" + "-h --help Show these instructions.\n" + " --verbose Print extra information.\n" + " --debug Print debugging information.\n" + "-d --device Specify the output device to use.\n" + "-l --list-devices Print a list fo available output devices.\n" + "\n" + ); + } + +/******************************************************************************/ +int +sound_list_devices ( void ) { + ao_info ** driver_list = NULL; + int driver_count = -1; + + driver_list = ao_driver_info_list( &driver_count ); + if ( driver_list == NULL ) { + fprintf( stderr, "Unable to get list of drivers" ); + return EXIT_FAILURE; + } + + int default_driver_id = ao_default_driver_id(); + + for ( int i = 0; i < driver_count; ++i ) + { + printf( "%s\n", driver_list[i]->name ); + int driver_id = ao_driver_id( driver_list[i]->short_name ); + if ( default_driver_id == driver_id ) { + printf( "\tDEFAULT DRIVER\n" ); + } + printf( "\tshort name :\t%s\n", driver_list[i]->short_name ); + printf( "\ttype :\t%s\n", + driver_list[i]->type == AO_TYPE_LIVE ? "live" : + (driver_list[i]->type == AO_TYPE_FILE ? "file" : + "unknown") + ); + printf( "\tcomment :\t%s\n", driver_list[i]->comment); + } + + return EXIT_SUCCESS; + } + +/******************************************************************************/ +int +sound_init ( void ) { + + ao_initialize(); + atexit( sound_shutdown ); + + options.ao_endian = ao_is_big_endian(); + options.ao_device_id = ao_default_driver_id(); + if ( options.device ) { + options.ao_device_id = ao_driver_id( options.device ); + } + if ( -1 == options.ao_device_id ) { + fprintf( stderr, "Unable to open output device.\n" ); + return 0; + } + + options.ao_driver_info = ao_driver_info( options.ao_device_id ); + + options.ao_format.bits = 16; + options.ao_format.channels = 2; + options.ao_format.rate = 44100; + options.ao_format.byte_format = options.ao_driver_info->preferred_byte_format; + + if ( AO_TYPE_LIVE == options.ao_driver_info->type ) { + options.ao_device = ao_open_live( options.ao_device_id, &options.ao_format, NULL ); + } + else { + fprintf( stderr, "error: Only live output devices are supported.\n" ); + return 0; + } + + return 1; + } + +/******************************************************************************/ +int +sound_play_file ( char *file ) { + OggVorbis_File vf; + int ok = 1; + + int err = ov_fopen( file, &vf ); + if ( err ) { + fprintf( stderr, "Unable to open file: %d\n", err ); + ok = 0; + return ok; + } + + sound_print_comments( &vf ); + + if ( options.debug ) { + vorbis_info *vi = ov_info( &vf, -1 ); + printf( "Encoded by: %s\n\n", ov_comment( &vf, -1 )->vendor ); + printf( "Bitstream is %d channel, %ldHz\n", vi->channels, vi->rate); + printf( "Decoded length: %ld samples\n", (long) ov_pcm_total( &vf, -1 ) ); + } + + char pcm[PCM_BUFFER_SIZE]; + int current_section; + int done = 0; + + while ( ! done && ! options.skip_next ) { + long bytes_read = ov_read( &vf, pcm, sizeof(pcm), options.ao_endian, 2, 1, ¤t_section ); + + if ( 0 == bytes_read ) { + done = 1; + } + else if ( OV_HOLE == bytes_read ) { + if (options.verbose ) { + fprintf( stderr, "error: hole in data\n" ); + } + } + else if ( OV_EBADLINK == bytes_read ) { + if (options.verbose ) { + fprintf( stderr, "error: invalid stream section in data\n" ); + } + } + else if ( OV_EINVAL == bytes_read ) { + fprintf( stderr, "error: Unable to read file headers.\n" ); + done = 1; + } + else { + // Play it! + if ( ! ao_play( options.ao_device, pcm, bytes_read ) ) { + done = 1; + ok = 0; + } + } + + } + + ov_clear( &vf ); + + if ( options.skip_next ) { + options.skip_next = 0; + } + + return ok; + } + +/******************************************************************************/ +void +sound_print_comments ( OggVorbis_File *vf) { + + char **comments = ov_comment( vf, -1 )->user_comments; + + char *track_title = NULL; + char **ptr = comments; + while ( ptr && *ptr ) { + char * pos = strstr( *ptr, "title" ); + if ( NULL != pos ) { + pos = strchr( *ptr, '=' ); + if ( pos ) { + track_title = pos + 1; + } + } + ++ptr; + } + + printf( "Now playing: %s\n", track_title ? track_title : "[unknown]" ); + + if ( options.verbose ) { + ptr = comments; + while ( ptr && *ptr ) { + char * pos = strstr( *ptr, "title" ); + if ( NULL == pos ) { + char *temp = strdup(*ptr); + pos = strchr( temp, '=' ); + *pos = '\0'; + printf( "\t%s: %s\n", temp, pos+1); + free(temp); + } + ++ptr; + } + } + } + +/******************************************************************************/ +void +sound_shutdown ( void ) { + ao_shutdown(); + } + diff -r 000000000000 -r 4d04dc4239b4 playogg.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/playogg.h Tue Jul 22 14:42:26 2014 -0500 @@ -0,0 +1,20 @@ +#ifndef PLAYOGG_H_ +#define PLAYOGG_H_ + +#define PCM_BUFFER_SIZE 4096 + +void err_exit ( char *msg ); +void init ( void ); +int min ( int a, int b ); +void parse_command_line (int argc, char **argv ); +void show_help ( void ); +void shutdown ( void ); +void sig_handler( int sig ); +int sound_list_devices ( void ); +int sound_init ( void ); +int sound_play_file ( char *file ); +void sound_print_comments ( OggVorbis_File *vf); +void sound_shutdown ( void ); + + +#endif