]>
Commit | Line | Data |
---|---|---|
cf8401db JL |
1 | /* |
2 | * libao output driver. This file is part of Shairport. | |
3 | * Copyright (c) James Laird 2013 | |
cb03d5c6 | 4 | * Copyright (c) Mike Brady 2014 -- 2022 |
cf8401db JL |
5 | * All rights reserved. |
6 | * | |
7 | * Permission is hereby granted, free of charge, to any person | |
8 | * obtaining a copy of this software and associated documentation | |
9 | * files (the "Software"), to deal in the Software without | |
10 | * restriction, including without limitation the rights to use, | |
11 | * copy, modify, merge, publish, distribute, sublicense, and/or | |
12 | * sell copies of the Software, and to permit persons to whom the | |
13 | * Software is furnished to do so, subject to the following conditions: | |
14 | * | |
15 | * The above copyright notice and this permission notice shall be | |
16 | * included in all copies or substantial portions of the Software. | |
17 | * | |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
19 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
20 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
21 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
22 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
23 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
25 | * OTHER DEALINGS IN THE SOFTWARE. | |
26 | */ | |
27 | ||
064bd293 MB |
28 | #include "audio.h" |
29 | #include "common.h" | |
30 | #include <ao/ao.h> | |
31 | #include <memory.h> | |
a2fb5d21 JL |
32 | #include <stdio.h> |
33 | #include <unistd.h> | |
a2fb5d21 JL |
34 | |
35 | ao_device *dev = NULL; | |
cb03d5c6 MB |
36 | ao_option *ao_opts = NULL; |
37 | ao_sample_format fmt; | |
38 | int driver = 0; | |
a2fb5d21 | 39 | |
9b33878c | 40 | static void help(void) { |
87a0475c MB |
41 | printf(" -d driver set the output driver\n" |
42 | " -o name=value set an arbitrary ao option\n" | |
43 | " -i id shorthand for -o id=<id>\n" | |
44 | " -n name shorthand for -o dev=<name> -o dsp=<name>\n"); | |
cb03d5c6 MB |
45 | // get a list of drivers available |
46 | ao_initialize(); | |
47 | int defaultDriver = ao_default_driver_id(); | |
48 | if (defaultDriver == -1) { | |
49 | printf(" No usable drivers available.\n"); | |
50 | } else { | |
51 | ao_info *defaultDriverInfo = ao_driver_info(defaultDriver); | |
52 | int driver_count; | |
53 | ao_info **driver_list = ao_driver_info_list(&driver_count); | |
54 | int i = 0; | |
55 | if (driver_count == 0) { | |
56 | printf(" Driver list unavailable.\n"); | |
57 | } else { | |
58 | printf(" Drivers:\n"); | |
59 | for (i = 0; i < driver_count; i++) { | |
60 | ao_info *the_driver = driver_list[i]; | |
61 | if (strcmp(the_driver->short_name, defaultDriverInfo->short_name) == 0) | |
62 | printf(" \"%s\" (default)\n", the_driver->short_name); | |
63 | else | |
64 | printf(" \"%s\"\n", the_driver->short_name); | |
65 | } | |
66 | } | |
67 | } | |
68 | ao_shutdown(); | |
9b33878c JL |
69 | } |
70 | ||
54250f75 | 71 | static int init(int argc, char **argv) { |
87a0475c | 72 | ao_initialize(); |
cb03d5c6 MB |
73 | driver = ao_default_driver_id(); |
74 | if (driver == -1) { | |
75 | warn("libao can not find a usable driver!"); | |
76 | } else { | |
77 | ||
78 | // set up default values first | |
79 | ||
80 | config.audio_backend_buffer_desired_length = 1.0; | |
81 | config.audio_backend_latency_offset = 0; | |
82 | ||
83 | // get settings from settings file first, allow them to be overridden by | |
84 | // command line options | |
85 | ||
86 | // do the "general" audio options. Note, these options are in the "general" stanza! | |
87 | parse_general_audio_options(); | |
88 | ||
89 | optind = 1; // optind=0 is equivalent to optind=1 plus special behaviour | |
90 | argv--; // so we shift the arguments to satisfy getopt() | |
91 | argc++; | |
92 | ||
93 | // some platforms apparently require optreset = 1; - which? | |
94 | int opt; | |
95 | char *mid; | |
96 | while ((opt = getopt(argc, argv, "d:i:n:o:")) > 0) { | |
97 | switch (opt) { | |
98 | case 'd': | |
99 | driver = ao_driver_id(optarg); | |
100 | if (driver < 0) | |
101 | die("could not find ao driver %s", optarg); | |
102 | break; | |
103 | case 'i': | |
104 | ao_append_option(&ao_opts, "id", optarg); | |
105 | break; | |
106 | case 'n': | |
107 | ao_append_option(&ao_opts, "dev", optarg); | |
108 | // Old libao versions (for example, 0.8.8) only support | |
109 | // "dsp" instead of "dev". | |
110 | ao_append_option(&ao_opts, "dsp", optarg); | |
111 | break; | |
112 | case 'o': | |
113 | mid = strchr(optarg, '='); | |
114 | if (!mid) | |
115 | die("Expected an = in audio option %s", optarg); | |
116 | *mid = 0; | |
117 | ao_append_option(&ao_opts, optarg, mid + 1); | |
118 | break; | |
119 | default: | |
120 | help(); | |
121 | die("Invalid audio option -%c specified", opt); | |
122 | } | |
efe7d2c6 | 123 | } |
a2fb5d21 | 124 | |
cb03d5c6 MB |
125 | if (optind < argc) |
126 | die("Invalid audio argument: %s", argv[optind]); | |
a2fb5d21 | 127 | |
cb03d5c6 | 128 | memset(&fmt, 0, sizeof(fmt)); |
a2fb5d21 | 129 | |
cb03d5c6 MB |
130 | fmt.bits = 16; |
131 | fmt.rate = 44100; | |
132 | fmt.channels = 2; | |
133 | fmt.byte_format = AO_FMT_NATIVE; | |
1ff669d4 | 134 | fmt.matrix = strdup("L,R"); |
cb03d5c6 MB |
135 | } |
136 | return 0; | |
a2fb5d21 JL |
137 | } |
138 | ||
139 | static void deinit(void) { | |
cb03d5c6 | 140 | if (dev != NULL) |
87a0475c MB |
141 | ao_close(dev); |
142 | dev = NULL; | |
143 | ao_shutdown(); | |
a2fb5d21 JL |
144 | } |
145 | ||
0cd8a2ce | 146 | static void start(__attribute__((unused)) int sample_rate, |
cb03d5c6 MB |
147 | __attribute__((unused)) int sample_format) { |
148 | // debug(1,"libao start"); | |
149 | } | |
a2fb5d21 | 150 | |
fd880056 MB |
151 | static int play(void *buf, int samples, __attribute__((unused)) int sample_type, |
152 | __attribute__((unused)) uint32_t timestamp, | |
153 | __attribute__((unused)) uint64_t playtime) { | |
cb03d5c6 MB |
154 | int response = 0; |
155 | int oldState; | |
156 | pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState); // make this un-cancellable | |
157 | if (driver != -1) { | |
158 | if (dev == NULL) | |
159 | dev = ao_open_live(driver, &fmt, ao_opts); | |
160 | if (dev != NULL) | |
161 | response = ao_play(dev, buf, samples * 4); | |
162 | } | |
163 | pthread_setcancelstate(oldState, NULL); | |
164 | return response; | |
165 | } | |
87a0475c | 166 | |
cb03d5c6 MB |
167 | static void stop(void) { |
168 | // debug(1,"libao stop"); | |
169 | if (dev != NULL) { | |
170 | ao_close(dev); | |
171 | dev = NULL; | |
172 | } | |
173 | } | |
87a0475c MB |
174 | |
175 | audio_output audio_ao = {.name = "ao", | |
176 | .help = &help, | |
177 | .init = &init, | |
178 | .deinit = &deinit, | |
83c0405d | 179 | .prepare = NULL, |
87a0475c MB |
180 | .start = &start, |
181 | .stop = &stop, | |
8cabb16f | 182 | .is_running = NULL, |
87a0475c MB |
183 | .flush = NULL, |
184 | .delay = NULL, | |
cd9da86f | 185 | .stats = NULL, |
87a0475c MB |
186 | .play = &play, |
187 | .volume = NULL, | |
4c70223f MB |
188 | .parameters = NULL, |
189 | .mute = NULL}; |