From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Tue, 9 Aug 2022 19:52:08 +0000 (+0100) Subject: Close the driver when play stops; reopen it when it restarts. Seems a lot more stable... X-Git-Tag: 4.1-rc1~24^2~40 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cb03d5c68b9dc0a8e4c81f488d11aedb90635a66;p=thirdparty%2Fshairport-sync.git Close the driver when play stops; reopen it when it restarts. Seems a lot more stable. Add a list of drivers to the help text. --- diff --git a/audio_ao.c b/audio_ao.c index 40a94fdc..6e203709 100644 --- a/audio_ao.c +++ b/audio_ao.c @@ -1,6 +1,7 @@ /* * libao output driver. This file is part of Shairport. * Copyright (c) James Laird 2013 + * Copyright (c) Mike Brady 2014 -- 2022 * All rights reserved. * * Permission is hereby granted, free of charge, to any person @@ -32,98 +33,141 @@ #include ao_device *dev = NULL; +ao_option *ao_opts = NULL; +ao_sample_format fmt; +int driver = 0; static void help(void) { printf(" -d driver set the output driver\n" " -o name=value set an arbitrary ao option\n" " -i id shorthand for -o id=\n" " -n name shorthand for -o dev= -o dsp=\n"); + // get a list of drivers available + ao_initialize(); + int defaultDriver = ao_default_driver_id(); + if (defaultDriver == -1) { + printf(" No usable drivers available.\n"); + } else { + ao_info *defaultDriverInfo = ao_driver_info(defaultDriver); + int driver_count; + ao_info **driver_list = ao_driver_info_list(&driver_count); + int i = 0; + if (driver_count == 0) { + printf(" Driver list unavailable.\n"); + } else { + printf(" Drivers:\n"); + for (i = 0; i < driver_count; i++) { + ao_info *the_driver = driver_list[i]; + if (strcmp(the_driver->short_name, defaultDriverInfo->short_name) == 0) + printf(" \"%s\" (default)\n", the_driver->short_name); + else + printf(" \"%s\"\n", the_driver->short_name); + } + } + } + ao_shutdown(); } static int init(int argc, char **argv) { - // const char *str; - // int value; - // double dvalue; ao_initialize(); - int driver = ao_default_driver_id(); - ao_option *ao_opts = NULL; - - // set up default values first - - config.audio_backend_buffer_desired_length = 1.0; - config.audio_backend_latency_offset = 0; - - // get settings from settings file first, allow them to be overridden by - // command line options - - // do the "general" audio options. Note, these options are in the "general" stanza! - parse_general_audio_options(); - - optind = 1; // optind=0 is equivalent to optind=1 plus special behaviour - argv--; // so we shift the arguments to satisfy getopt() - argc++; - - // some platforms apparently require optreset = 1; - which? - int opt; - char *mid; - while ((opt = getopt(argc, argv, "d:i:n:o:")) > 0) { - switch (opt) { - case 'd': - driver = ao_driver_id(optarg); - if (driver < 0) - die("could not find ao driver %s", optarg); - break; - case 'i': - ao_append_option(&ao_opts, "id", optarg); - break; - case 'n': - ao_append_option(&ao_opts, "dev", optarg); - // Old libao versions (for example, 0.8.8) only support - // "dsp" instead of "dev". - ao_append_option(&ao_opts, "dsp", optarg); - break; - case 'o': - mid = strchr(optarg, '='); - if (!mid) - die("Expected an = in audio option %s", optarg); - *mid = 0; - ao_append_option(&ao_opts, optarg, mid + 1); - break; - default: - help(); - die("Invalid audio option -%c specified", opt); + driver = ao_default_driver_id(); + if (driver == -1) { + warn("libao can not find a usable driver!"); + } else { + + // set up default values first + + config.audio_backend_buffer_desired_length = 1.0; + config.audio_backend_latency_offset = 0; + + // get settings from settings file first, allow them to be overridden by + // command line options + + // do the "general" audio options. Note, these options are in the "general" stanza! + parse_general_audio_options(); + + optind = 1; // optind=0 is equivalent to optind=1 plus special behaviour + argv--; // so we shift the arguments to satisfy getopt() + argc++; + + // some platforms apparently require optreset = 1; - which? + int opt; + char *mid; + while ((opt = getopt(argc, argv, "d:i:n:o:")) > 0) { + switch (opt) { + case 'd': + driver = ao_driver_id(optarg); + if (driver < 0) + die("could not find ao driver %s", optarg); + break; + case 'i': + ao_append_option(&ao_opts, "id", optarg); + break; + case 'n': + ao_append_option(&ao_opts, "dev", optarg); + // Old libao versions (for example, 0.8.8) only support + // "dsp" instead of "dev". + ao_append_option(&ao_opts, "dsp", optarg); + break; + case 'o': + mid = strchr(optarg, '='); + if (!mid) + die("Expected an = in audio option %s", optarg); + *mid = 0; + ao_append_option(&ao_opts, optarg, mid + 1); + break; + default: + help(); + die("Invalid audio option -%c specified", opt); + } } - } - - if (optind < argc) - die("Invalid audio argument: %s", argv[optind]); - - ao_sample_format fmt; - memset(&fmt, 0, sizeof(fmt)); - fmt.bits = 16; - fmt.rate = 44100; - fmt.channels = 2; - fmt.byte_format = AO_FMT_NATIVE; + if (optind < argc) + die("Invalid audio argument: %s", argv[optind]); - dev = ao_open_live(driver, &fmt, ao_opts); + memset(&fmt, 0, sizeof(fmt)); - return dev ? 0 : 1; + fmt.bits = 16; + fmt.rate = 44100; + fmt.channels = 2; + fmt.byte_format = AO_FMT_NATIVE; + } + return 0; } static void deinit(void) { - if (dev) + if (dev != NULL) ao_close(dev); dev = NULL; ao_shutdown(); } static void start(__attribute__((unused)) int sample_rate, - __attribute__((unused)) int sample_format) {} + __attribute__((unused)) int sample_format) { + // debug(1,"libao start"); +} -static int play(void *buf, int samples) { return ao_play(dev, buf, samples * 4); } +static int play(void *buf, int samples) { + int response = 0; + int oldState; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState); // make this un-cancellable + if (driver != -1) { + if (dev == NULL) + dev = ao_open_live(driver, &fmt, ao_opts); + if (dev != NULL) + response = ao_play(dev, buf, samples * 4); + } + pthread_setcancelstate(oldState, NULL); + return response; +} -static void stop(void) {} +static void stop(void) { + // debug(1,"libao stop"); + if (dev != NULL) { + ao_close(dev); + dev = NULL; + } +} audio_output audio_ao = {.name = "ao", .help = &help,