changeset 0:4d04dc4239b4

Simple demo programs for libao and libvorbisfile.
author Eris Caffee <discordia@eldalin.com>
date Tue, 22 Jul 2014 14:42:26 -0500
parents
children 03892700ff0d
files .hgignore Makefile list_drivers.c playogg.c playogg.h
diffstat 5 files changed, 511 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Tue Jul 22 14:42:26 2014 -0500
     1.3 @@ -0,0 +1,3 @@
     1.4 +^list_drivers$
     1.5 +^playogg$
     1.6 +^.*~$
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/Makefile	Tue Jul 22 14:42:26 2014 -0500
     2.3 @@ -0,0 +1,12 @@
     2.4 +SHELL = /bin/sh
     2.5 +
     2.6 +all: playogg list_drivers
     2.7 +
     2.8 +playogg: playogg.c playogg.h
     2.9 +	gcc -o playogg playogg.c --std=gnu99 -lao -lvorbisfile
    2.10 +
    2.11 +list_drivers: list_drivers.c
    2.12 +	gcc -o list_drivers list_drivers.c --std=gnu99 -lao
    2.13 +
    2.14 +clean:
    2.15 +	rm -f list_drivers playogg
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/list_drivers.c	Tue Jul 22 14:42:26 2014 -0500
     3.3 @@ -0,0 +1,77 @@
     3.4 +#include <stdio.h>
     3.5 +#include <stdlib.h>
     3.6 +
     3.7 +#include <ao/ao.h>
     3.8 +
     3.9 +/******************************************************************************/
    3.10 +
    3.11 +void err_exit( char * msg )
    3.12 +    {
    3.13 +    fprintf(stderr, "FATAL ERROR: %s\n", msg ? msg : "Unknown error" );
    3.14 +    exit( EXIT_FAILURE );
    3.15 +    }
    3.16 +
    3.17 +
    3.18 +/******************************************************************************/
    3.19 +
    3.20 +int main ( int argc, char** argv ) 
    3.21 +    {
    3.22 +    ao_initialize();
    3.23 +
    3.24 +    ao_info ** driver_list = NULL;
    3.25 +    int driver_count = -1;
    3.26 +
    3.27 +    driver_list = ao_driver_info_list( &driver_count );
    3.28 +    if ( driver_list == NULL )
    3.29 +        {
    3.30 +        err_exit("Unable to get list of drivers");
    3.31 +        }
    3.32 +
    3.33 +    printf( "Endianness: %s\n", ao_is_big_endian() ? "big" : "little" );
    3.34 +
    3.35 +    int default_driver_id = ao_default_driver_id();
    3.36 +    if ( -1 == default_driver_id )
    3.37 +        {
    3.38 +        printf( "No default driver available\n" );
    3.39 +        }
    3.40 +
    3.41 +    for ( int i = 0; i < driver_count; ++i )
    3.42 +        {
    3.43 +        printf( "%s\n", driver_list[i]->name );
    3.44 +        int driver_id = ao_driver_id( driver_list[i]->short_name );
    3.45 +        if ( default_driver_id == driver_id )
    3.46 +            {
    3.47 +            printf( "\tDEFAULT DRIVER\n" );
    3.48 +            }
    3.49 +        printf( "\tshort name           :\t%s\n", driver_list[i]->short_name );
    3.50 +        printf( "\ttype                 :\t%s\n",
    3.51 +            driver_list[i]->type == AO_TYPE_LIVE ? "live" :
    3.52 +            (driver_list[i]->type == AO_TYPE_FILE ? "file" :
    3.53 +            "unknown")
    3.54 +            );
    3.55 +        printf( "\tpriority             :\t%d\n", driver_list[i]->priority );
    3.56 +        printf( "\tpreferred byte format:\t%s\n",
    3.57 +            driver_list[i]->preferred_byte_format == AO_FMT_LITTLE ? "little" : 
    3.58 +            (driver_list[i]->preferred_byte_format == AO_FMT_BIG ? "big" : "unknown" )
    3.59 +            );
    3.60 +
    3.61 +#if 0
    3.62 +        // Appears that ao-file_extension is not in my version of libao
    3.63 +        char * ext = NULL;
    3.64 +        ext = ao_file_extension( driver_id );
    3.65 +        printf( "\tnormal file extension:\t%s\n", ext == NULL ? "[none]" : ext );
    3.66 +#endif
    3.67 +
    3.68 +        printf( "\toptions              :\t", driver_list[i]->comment);
    3.69 +        for ( int j = 0; j < driver_list[i]->option_count ; ++j )
    3.70 +            {
    3.71 +            printf( "%s ", driver_list[i]->options[j]);
    3.72 +            }
    3.73 +        printf("\n");
    3.74 +
    3.75 +        printf( "\tcomment              :\t%s\n", driver_list[i]->comment);
    3.76 +        }
    3.77 +
    3.78 +    ao_shutdown();
    3.79 +    }
    3.80 +
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/playogg.c	Tue Jul 22 14:42:26 2014 -0500
     4.3 @@ -0,0 +1,399 @@
     4.4 +#include <stdio.h>
     4.5 +#include <stdlib.h>
     4.6 +#include <string.h>
     4.7 +
     4.8 +#include <getopt.h>
     4.9 +#include <signal.h>
    4.10 +
    4.11 +#include <ao/ao.h>
    4.12 +#include <vorbis/vorbisfile.h>
    4.13 +
    4.14 +#include "playogg.h"
    4.15 +
    4.16 +/******************************************************************************/
    4.17 +static struct opts {
    4.18 +    int debug;
    4.19 +    int verbose;
    4.20 +    int list_devices;
    4.21 +    char* device;
    4.22 +    char **files;
    4.23 +    int skip_next;
    4.24 +    int ao_endian;
    4.25 +    int ao_device_id;
    4.26 +    ao_device *ao_device;
    4.27 +    ao_info *ao_driver_info;
    4.28 +    ao_sample_format ao_format;
    4.29 +    } options;
    4.30 +
    4.31 +int
    4.32 +main (int argc, char **argv ) {
    4.33 +    
    4.34 +    init();
    4.35 +    parse_command_line( argc, argv );
    4.36 +
    4.37 +    if ( ! sound_init() ) {
    4.38 +        exit( EXIT_FAILURE );
    4.39 +        }
    4.40 +    
    4.41 +    if ( options.list_devices ) {
    4.42 +        exit( sound_list_devices() );
    4.43 +        }
    4.44 +
    4.45 +    char **file =  options.files;
    4.46 +    int ok = 1;
    4.47 +    while (ok && file && *file) {
    4.48 +        if ( options.verbose ) {
    4.49 +            printf( "Next file: %s\n", *file );
    4.50 +            }
    4.51 +        ok = sound_play_file( *file );
    4.52 +        file++;
    4.53 +        }
    4.54 +
    4.55 +    exit( EXIT_SUCCESS );
    4.56 +    }
    4.57 +
    4.58 +/******************************************************************************/
    4.59 +void
    4.60 +sig_handler ( int sig ) {
    4.61 +    if ( SIGINT == sig ) {
    4.62 +        options.skip_next = 1;
    4.63 +        }
    4.64 +    }
    4.65 +
    4.66 +/******************************************************************************/
    4.67 +void
    4.68 +err_exit ( char * msg ) {
    4.69 +    fprintf(stderr, "FATAL ERROR: %s\n", msg ? msg : "Unknown error" );
    4.70 +    exit( EXIT_FAILURE );
    4.71 +    }
    4.72 +
    4.73 +/******************************************************************************/
    4.74 +void
    4.75 +init ( void ) {
    4.76 +    atexit( shutdown );
    4.77 +
    4.78 +    options.debug = 0;
    4.79 +    options.verbose = 0;
    4.80 +    options.device = NULL;
    4.81 +    options.list_devices = 0;
    4.82 +    options.files = NULL;
    4.83 +    options.skip_next = 0;
    4.84 +    options.ao_endian = 1;
    4.85 +    options.ao_device_id = -1;
    4.86 +    options.ao_device = NULL;
    4.87 +    options.ao_driver_info = NULL;
    4.88 +    memset( &options.ao_format, 0, sizeof(ao_sample_format) );
    4.89 +
    4.90 +    struct sigaction sigact;
    4.91 +    memset( &sigact, 0, sizeof(sigact) );
    4.92 +    sigact.sa_handler = sig_handler;
    4.93 +    sigaction( SIGINT, &sigact, NULL );
    4.94 +
    4.95 +    }
    4.96 +
    4.97 +/******************************************************************************/
    4.98 +int
    4.99 +min ( int a, int b ) {
   4.100 +    if (a <= b) {
   4.101 +        return a;
   4.102 +        }
   4.103 +    else {
   4.104 +        return b;
   4.105 +        }
   4.106 +    }
   4.107 +
   4.108 +
   4.109 +/******************************************************************************/
   4.110 +void
   4.111 +parse_command_line (int argc, char **argv ) {
   4.112 +
   4.113 +    static const char *short_options = "hd:l";
   4.114 +    static const struct option long_options[] = {
   4.115 +        { "help",         0,    0,      'h'    },
   4.116 +        { "verbose",      0,    0,      0      },
   4.117 +        { "debug",        0,    0,      0      },
   4.118 +        { "device",       1,    0,      'd'    },
   4.119 +        { "list-devices", 0,    0,      'l'    },
   4.120 +        { NULL, 0, NULL, 0}
   4.121 +        };
   4.122 +
   4.123 +    int c;
   4.124 +    int option_index = 0;
   4.125 +    while (1) {
   4.126 +        c = getopt_long( argc, argv, short_options, long_options, &option_index );
   4.127 +
   4.128 +        if ( -1 == c ) {
   4.129 +            break;
   4.130 +            }
   4.131 +
   4.132 +        switch (c) {
   4.133 +
   4.134 +        case 0:
   4.135 +            1; 
   4.136 +            int len = strlen( long_options[option_index].name );
   4.137 +            if ( 0 == strncmp( long_options[option_index].name, "verbose", min(len, 7) ) ) {
   4.138 +                options.verbose = 1;
   4.139 +                }
   4.140 +            else if ( 0 == strncmp( long_options[option_index].name, "debug", min(len, 5) ) ) {
   4.141 +                options.debug = 1;
   4.142 +                }
   4.143 +            else {
   4.144 +                fprintf( stderr, "Unrecognized option on command line: --%s\n", optarg );
   4.145 +                show_help();
   4.146 +                exit( EXIT_FAILURE );
   4.147 +                }
   4.148 +
   4.149 +            break;
   4.150 +
   4.151 +        case 'h':
   4.152 +            show_help();
   4.153 +            exit( EXIT_SUCCESS );
   4.154 +            break;
   4.155 +
   4.156 +        case 'd':
   4.157 +            options.device = strdup(optarg);
   4.158 +            break;
   4.159 +
   4.160 +        case 'l':
   4.161 +            options.list_devices = 1;
   4.162 +            break;
   4.163 +
   4.164 +        case 'v':
   4.165 +            options.verbose = 1;
   4.166 +            break;
   4.167 +
   4.168 +        default:
   4.169 +            fprintf( stderr, "Unrecognized option on command line: -%c\n", c );
   4.170 +            show_help();
   4.171 +            exit( EXIT_FAILURE );
   4.172 +            break;
   4.173 +            }
   4.174 +        }
   4.175 +
   4.176 +    if (optind < argc) {
   4.177 +        options.files = calloc( argc - optind + 1, sizeof(char *) );
   4.178 +        int i = 0;
   4.179 +        while ( optind < argc) {
   4.180 +            options.files[i++] = argv[optind++];
   4.181 +            }
   4.182 +        }
   4.183 +
   4.184 +    if (options.debug) {
   4.185 +        fprintf( stderr, "verbose: %d\n", options.verbose );
   4.186 +        fprintf( stderr, "debug  : %d\n", options.debug );
   4.187 +        fprintf( stderr, "device : %s\n", options.device );
   4.188 +        fprintf( stderr, "list_devices : %d\n", options.list_devices );
   4.189 +        fprintf( stderr, "files  : ");
   4.190 +        char **ptr = options.files;
   4.191 +        while (ptr && *ptr) {
   4.192 +            fprintf( stderr, "%s ", *ptr );
   4.193 +            ptr++;
   4.194 +            }
   4.195 +        fprintf( stderr, "\n" );
   4.196 +        }
   4.197 +    
   4.198 +    }
   4.199 +
   4.200 +/******************************************************************************/
   4.201 +void
   4.202 +shutdown ( void ) {
   4.203 +    if ( options.device ) {
   4.204 +        free( options.device );
   4.205 +        }
   4.206 +    }
   4.207 +
   4.208 +/******************************************************************************/
   4.209 +void
   4.210 +show_help ( void ) {
   4.211 +    printf(
   4.212 +        "Usage: myplayogg [-hlv] filename\n"
   4.213 +        "\n"
   4.214 +        "Play the Ogg Vorbis encoded file.\n"
   4.215 +        "\n"
   4.216 +        "Options:\n"
   4.217 +        "\n"
   4.218 +        "-h --help               Show these instructions.\n"
   4.219 +        "   --verbose            Print extra information.\n"
   4.220 +        "   --debug              Print debugging information.\n"
   4.221 +        "-d --device             Specify the output device to use.\n"
   4.222 +        "-l --list-devices       Print a list fo available output devices.\n"
   4.223 +        "\n"
   4.224 +        );
   4.225 +    }
   4.226 +
   4.227 +/******************************************************************************/
   4.228 +int
   4.229 +sound_list_devices ( void ) {
   4.230 +    ao_info ** driver_list = NULL;
   4.231 +    int driver_count = -1;
   4.232 +
   4.233 +    driver_list = ao_driver_info_list( &driver_count );
   4.234 +    if ( driver_list == NULL ) {
   4.235 +        fprintf( stderr, "Unable to get list of drivers" );
   4.236 +        return EXIT_FAILURE;
   4.237 +        }
   4.238 +
   4.239 +    int default_driver_id = ao_default_driver_id();
   4.240 +
   4.241 +    for ( int i = 0; i < driver_count; ++i )
   4.242 +        {
   4.243 +        printf( "%s\n", driver_list[i]->name );
   4.244 +        int driver_id = ao_driver_id( driver_list[i]->short_name );
   4.245 +        if ( default_driver_id == driver_id ) {
   4.246 +            printf( "\tDEFAULT DRIVER\n" );
   4.247 +            }
   4.248 +        printf( "\tshort name           :\t%s\n", driver_list[i]->short_name );
   4.249 +        printf( "\ttype                 :\t%s\n",
   4.250 +            driver_list[i]->type == AO_TYPE_LIVE ? "live" :
   4.251 +                (driver_list[i]->type == AO_TYPE_FILE ? "file" :
   4.252 +                "unknown")
   4.253 +            );
   4.254 +        printf( "\tcomment              :\t%s\n", driver_list[i]->comment);
   4.255 +        }
   4.256 +
   4.257 +    return EXIT_SUCCESS;
   4.258 +    }
   4.259 +
   4.260 +/******************************************************************************/
   4.261 +int
   4.262 +sound_init ( void ) {
   4.263 +
   4.264 +    ao_initialize();
   4.265 +    atexit( sound_shutdown );
   4.266 +
   4.267 +    options.ao_endian = ao_is_big_endian();
   4.268 +    options.ao_device_id = ao_default_driver_id();
   4.269 +    if ( options.device ) {
   4.270 +        options.ao_device_id = ao_driver_id( options.device );
   4.271 +        }
   4.272 +    if ( -1 == options.ao_device_id ) {
   4.273 +        fprintf( stderr, "Unable to open output device.\n" );
   4.274 +        return 0;
   4.275 +        }
   4.276 +
   4.277 +    options.ao_driver_info = ao_driver_info( options.ao_device_id );
   4.278 +    
   4.279 +    options.ao_format.bits = 16;
   4.280 +    options.ao_format.channels = 2;
   4.281 +    options.ao_format.rate = 44100;
   4.282 +    options.ao_format.byte_format = options.ao_driver_info->preferred_byte_format;
   4.283 +
   4.284 +    if ( AO_TYPE_LIVE == options.ao_driver_info->type ) {
   4.285 +        options.ao_device = ao_open_live( options.ao_device_id, &options.ao_format, NULL );
   4.286 +        }
   4.287 +    else {
   4.288 +        fprintf( stderr, "error: Only live output devices are supported.\n" );
   4.289 +        return 0;
   4.290 +        }
   4.291 +
   4.292 +    return 1;
   4.293 +    }
   4.294 +
   4.295 +/******************************************************************************/
   4.296 +int
   4.297 +sound_play_file ( char *file ) {
   4.298 +    OggVorbis_File vf;
   4.299 +    int ok = 1;
   4.300 +
   4.301 +    int err = ov_fopen( file, &vf );
   4.302 +    if ( err ) {
   4.303 +        fprintf( stderr, "Unable to open file: %d\n", err );
   4.304 +        ok = 0;
   4.305 +        return ok;
   4.306 +        }
   4.307 +
   4.308 +    sound_print_comments( &vf );
   4.309 +
   4.310 +    if ( options.debug ) {
   4.311 +        vorbis_info *vi = ov_info( &vf, -1 );
   4.312 +        printf( "Encoded by: %s\n\n", ov_comment( &vf, -1 )->vendor );
   4.313 +        printf( "Bitstream is %d channel, %ldHz\n", vi->channels, vi->rate);
   4.314 +        printf( "Decoded length: %ld samples\n", (long) ov_pcm_total( &vf, -1 ) );
   4.315 +        }
   4.316 +
   4.317 +    char pcm[PCM_BUFFER_SIZE];
   4.318 +    int current_section;
   4.319 +    int done = 0;
   4.320 +
   4.321 +    while ( ! done && ! options.skip_next ) {
   4.322 +        long bytes_read = ov_read( &vf, pcm, sizeof(pcm), options.ao_endian, 2, 1, &current_section );
   4.323 +
   4.324 +        if ( 0 == bytes_read ) {
   4.325 +            done = 1;
   4.326 +            }
   4.327 +        else if ( OV_HOLE == bytes_read ) {
   4.328 +            if (options.verbose ) {
   4.329 +                fprintf( stderr, "error: hole in data\n" );
   4.330 +                }
   4.331 +            }
   4.332 +        else if ( OV_EBADLINK == bytes_read ) {
   4.333 +            if (options.verbose ) {
   4.334 +                fprintf( stderr, "error: invalid stream section in data\n" );
   4.335 +                }
   4.336 +            }
   4.337 +        else if ( OV_EINVAL == bytes_read ) {
   4.338 +            fprintf( stderr, "error: Unable to read file headers.\n" );
   4.339 +            done = 1;
   4.340 +            }
   4.341 +        else {
   4.342 +            // Play it!
   4.343 +            if ( ! ao_play( options.ao_device, pcm, bytes_read ) ) {
   4.344 +                done = 1;
   4.345 +                ok = 0;
   4.346 +                }
   4.347 +            }
   4.348 +        
   4.349 +        }
   4.350 +
   4.351 +    ov_clear( &vf );
   4.352 +
   4.353 +    if ( options.skip_next ) {
   4.354 +        options.skip_next = 0;
   4.355 +        }
   4.356 +
   4.357 +    return ok;
   4.358 +    }
   4.359 +
   4.360 +/******************************************************************************/
   4.361 +void
   4.362 +sound_print_comments ( OggVorbis_File *vf) {
   4.363 +
   4.364 +    char **comments = ov_comment( vf, -1 )->user_comments;
   4.365 +
   4.366 +    char *track_title = NULL;
   4.367 +    char **ptr = comments;
   4.368 +    while ( ptr && *ptr ) {
   4.369 +        char * pos = strstr( *ptr, "title" );
   4.370 +        if ( NULL != pos ) {
   4.371 +            pos = strchr( *ptr, '=' );
   4.372 +            if ( pos ) {
   4.373 +                track_title = pos + 1;
   4.374 +                }
   4.375 +            }
   4.376 +        ++ptr;
   4.377 +        }
   4.378 +
   4.379 +    printf( "Now playing: %s\n", track_title ? track_title : "[unknown]" );
   4.380 +
   4.381 +    if ( options.verbose ) {
   4.382 +        ptr = comments;
   4.383 +        while ( ptr && *ptr ) {
   4.384 +            char * pos = strstr( *ptr, "title" );
   4.385 +            if ( NULL == pos ) {
   4.386 +                char *temp = strdup(*ptr);
   4.387 +                pos = strchr( temp, '=' );
   4.388 +                *pos = '\0';
   4.389 +                printf( "\t%s: %s\n", temp, pos+1);
   4.390 +                free(temp);
   4.391 +                }
   4.392 +            ++ptr;
   4.393 +            }
   4.394 +        }
   4.395 +    }
   4.396 +
   4.397 +/******************************************************************************/
   4.398 +void
   4.399 +sound_shutdown ( void ) {
   4.400 +    ao_shutdown();
   4.401 +    }
   4.402 +
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/playogg.h	Tue Jul 22 14:42:26 2014 -0500
     5.3 @@ -0,0 +1,20 @@
     5.4 +#ifndef PLAYOGG_H_
     5.5 +#define PLAYOGG_H_
     5.6 +
     5.7 +#define PCM_BUFFER_SIZE 4096
     5.8 +
     5.9 +void err_exit ( char *msg );
    5.10 +void init ( void );
    5.11 +int min ( int a, int b );
    5.12 +void parse_command_line (int argc, char **argv );
    5.13 +void show_help ( void );
    5.14 +void shutdown ( void );
    5.15 +void sig_handler( int sig );
    5.16 +int sound_list_devices ( void );
    5.17 +int sound_init ( void );
    5.18 +int sound_play_file ( char *file );
    5.19 +void sound_print_comments ( OggVorbis_File *vf);
    5.20 +void sound_shutdown ( void );
    5.21 +
    5.22 +
    5.23 +#endif