]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Close the driver when play stops; reopen it when it restarts. Seems a lot more stable...
authorMike Brady <4265913+mikebrady@users.noreply.github.com>
Tue, 9 Aug 2022 19:52:08 +0000 (20:52 +0100)
committerMike Brady <4265913+mikebrady@users.noreply.github.com>
Tue, 9 Aug 2022 19:52:08 +0000 (20:52 +0100)
audio_ao.c

index 40a94fdccdc5ce09d8c601dd73b8e864fdd75c85..6e2037091d08e787dd896c8bb4d724c4ebc0e82f 100644 (file)
@@ -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
 #include <unistd.h>
 
 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=<id>\n"
          "    -n name             shorthand for -o dev=<name> -o dsp=<name>\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,