annotate libao2/ao_pulse.c @ 25661:293aeec83153

Replace the persistent CODECS_FLAG_SELECTED by a local "stringset" with an almost-trivial implementation. This allows making the builtin codec structs const, and it also makes clearer that this "selected" status is not used outside the init functions.
author reimar
date Sat, 12 Jan 2008 14:05:46 +0000
parents bd46b759fd35
children d48e2d7191df
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
24782
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
1 /*
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
2 * PulseAudio audio output driver.
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
3 * Copyright (C) 2006 Lennart Poettering
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
4 * Copyright (C) 2007 Reimar Doeffinger
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
5 *
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
6 * This file is part of MPlayer.
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
7 *
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
8 * MPlayer is free software; you can redistribute it and/or modify
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
9 * it under the terms of the GNU General Public License as published by
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
10 * the Free Software Foundation; either version 2 of the License, or
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
11 * (at your option) any later version.
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
12 *
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
13 * MPlayer is distributed in the hope that it will be useful,
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
16 * GNU General Public License for more details.
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
17 *
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
18 * You should have received a copy of the GNU General Public License
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
19 * along with MPlayer; if not, write to the Free Software
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
21 */
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
22 #include <string.h>
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
23
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
24 #include <pulse/pulseaudio.h>
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
25
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
26 #include "config.h"
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
27 #include "libaf/af_format.h"
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
28 #include "mp_msg.h"
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
29 #include "audio_out.h"
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
30 #include "audio_out_internal.h"
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
31
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
32 #define PULSE_CLIENT_NAME "MPlayer"
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
33
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
34 /** General driver info */
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
35 static ao_info_t info = {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
36 "PulseAudio audio output",
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
37 "pulse",
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
38 "Lennart Poettering",
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
39 ""
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
40 };
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
41
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
42 /** PulseAudio playback stream object */
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
43 static struct pa_stream *stream;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
44
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
45 /** PulseAudio connection context */
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
46 static struct pa_context *context;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
47
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
48 /** Main event loop object */
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
49 static struct pa_threaded_mainloop *mainloop;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
50
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
51 /** A temporary variable to store the current volume */
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
52 static pa_cvolume volume;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
53
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
54 LIBAO_EXTERN(pulse)
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
55
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
56 #define GENERIC_ERR_MSG(ctx, str) \
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
57 mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] "str": %s\n", \
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
58 pa_strerror(pa_context_errno(ctx)))
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
59
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
60 static void context_state_cb(pa_context *c, void *userdata) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
61 switch (pa_context_get_state(c)) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
62 case PA_CONTEXT_READY:
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
63 case PA_CONTEXT_TERMINATED:
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
64 case PA_CONTEXT_FAILED:
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
65 pa_threaded_mainloop_signal(mainloop, 0);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
66 break;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
67 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
68 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
69
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
70 static void stream_state_cb(pa_stream *s, void *userdata) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
71 switch (pa_stream_get_state(s)) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
72 case PA_STREAM_READY:
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
73 case PA_STREAM_FAILED:
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
74 case PA_STREAM_TERMINATED:
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
75 pa_threaded_mainloop_signal(mainloop, 0);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
76 break;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
77 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
78 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
79
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
80 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
81 pa_threaded_mainloop_signal(mainloop, 0);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
82 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
83
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
84 static void stream_latency_update_cb(pa_stream *s, void *userdata) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
85 pa_threaded_mainloop_signal(mainloop, 0);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
86 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
87
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
88 static void success_cb(pa_stream *s, int success, void *userdata) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
89 if (userdata)
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
90 *(int *)userdata = success;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
91 pa_threaded_mainloop_signal(mainloop, 0);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
92 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
93
25383
9ca05492f9f3 Documentation for waitop function
reimar
parents: 24923
diff changeset
94 /**
9ca05492f9f3 Documentation for waitop function
reimar
parents: 24923
diff changeset
95 * \brief waits for a pulseaudio operation to finish, frees it and
9ca05492f9f3 Documentation for waitop function
reimar
parents: 24923
diff changeset
96 * unlocks the mainloop
9ca05492f9f3 Documentation for waitop function
reimar
parents: 24923
diff changeset
97 * \param op operation to wait for
9ca05492f9f3 Documentation for waitop function
reimar
parents: 24923
diff changeset
98 * \return 1 if operation has finished normally (DONE state), 0 otherwise
9ca05492f9f3 Documentation for waitop function
reimar
parents: 24923
diff changeset
99 */
24782
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
100 static int waitop(pa_operation *op) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
101 pa_operation_state_t state;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
102 if (!op) return 0;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
103 state = pa_operation_get_state(op);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
104 while (state == PA_OPERATION_RUNNING) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
105 pa_threaded_mainloop_wait(mainloop);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
106 state = pa_operation_get_state(op);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
107 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
108 pa_operation_unref(op);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
109 pa_threaded_mainloop_unlock(mainloop);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
110 return state == PA_OPERATION_DONE;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
111 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
112
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
113 static const struct format_map_s {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
114 int mp_format;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
115 pa_sample_format_t pa_format;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
116 } format_maps[] = {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
117 {AF_FORMAT_U8, PA_SAMPLE_U8},
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
118 {AF_FORMAT_S16_LE, PA_SAMPLE_S16LE},
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
119 {AF_FORMAT_S16_BE, PA_SAMPLE_S16BE},
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
120 {AF_FORMAT_FLOAT_LE, PA_SAMPLE_FLOAT32LE},
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
121 {AF_FORMAT_FLOAT_BE, PA_SAMPLE_FLOAT32BE},
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
122 {AF_FORMAT_MU_LAW, PA_SAMPLE_ULAW},
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
123 {AF_FORMAT_A_LAW, PA_SAMPLE_ALAW},
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
124 {AF_FORMAT_UNKNOWN, 0}
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
125 };
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
126
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
127 static int init(int rate_hz, int channels, int format, int flags) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
128 struct pa_sample_spec ss;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
129 struct pa_channel_map map;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
130 const struct format_map_s *fmt_map;
24921
148ca265fcb6 Change parsing to allow host == NULL and sink != NULL
reimar
parents: 24920
diff changeset
131 char *devarg = NULL;
24782
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
132 char *host = NULL;
24919
51372a34bc7d Make sink variable local, it is only used in one place
reimar
parents: 24782
diff changeset
133 char *sink = NULL;
24782
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
134
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
135 if (ao_subdevice) {
24921
148ca265fcb6 Change parsing to allow host == NULL and sink != NULL
reimar
parents: 24920
diff changeset
136 devarg = strdup(ao_subdevice);
148ca265fcb6 Change parsing to allow host == NULL and sink != NULL
reimar
parents: 24920
diff changeset
137 sink = strchr(devarg, ':');
24920
12dc34b2e41c Simplify argument "parsing"
reimar
parents: 24919
diff changeset
138 if (sink) *sink++ = 0;
24921
148ca265fcb6 Change parsing to allow host == NULL and sink != NULL
reimar
parents: 24920
diff changeset
139 if (devarg[0]) host = devarg;
24782
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
140 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
141
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
142 ss.channels = channels;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
143 ss.rate = rate_hz;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
144
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
145 ao_data.samplerate = rate_hz;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
146 ao_data.format = format;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
147 ao_data.channels = channels;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
148
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
149 fmt_map = format_maps;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
150 while (fmt_map->mp_format != format) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
151 if (fmt_map->mp_format == AF_FORMAT_UNKNOWN) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
152 mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Unsupported sample spec\n");
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
153 goto fail;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
154 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
155 fmt_map++;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
156 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
157 ss.format = fmt_map->pa_format;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
158
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
159 if (!pa_sample_spec_valid(&ss)) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
160 mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Invalid sample spec\n");
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
161 goto fail;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
162 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
163
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
164 pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
165 ao_data.bps = pa_bytes_per_second(&ss);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
166
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
167 pa_cvolume_reset(&volume, ss.channels);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
168
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
169 if (!(mainloop = pa_threaded_mainloop_new())) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
170 mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate main loop\n");
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
171 goto fail;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
172 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
173
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
174 if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), PULSE_CLIENT_NAME))) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
175 mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate context\n");
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
176 goto fail;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
177 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
178
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
179 pa_context_set_state_callback(context, context_state_cb, NULL);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
180
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
181 if (pa_context_connect(context, host, 0, NULL) < 0)
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
182 goto fail;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
183
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
184 pa_threaded_mainloop_lock(mainloop);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
185
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
186 if (pa_threaded_mainloop_start(mainloop) < 0)
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
187 goto unlock_and_fail;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
188
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
189 /* Wait until the context is ready */
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
190 pa_threaded_mainloop_wait(mainloop);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
191
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
192 if (pa_context_get_state(context) != PA_CONTEXT_READY)
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
193 goto unlock_and_fail;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
194
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
195 if (!(stream = pa_stream_new(context, "audio stream", &ss, &map)))
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
196 goto unlock_and_fail;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
197
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
198 pa_stream_set_state_callback(stream, stream_state_cb, NULL);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
199 pa_stream_set_write_callback(stream, stream_request_cb, NULL);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
200 pa_stream_set_latency_update_callback(stream, stream_latency_update_cb, NULL);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
201
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
202 if (pa_stream_connect_playback(stream, sink, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, &volume, NULL) < 0)
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
203 goto unlock_and_fail;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
204
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
205 /* Wait until the stream is ready */
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
206 pa_threaded_mainloop_wait(mainloop);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
207
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
208 if (pa_stream_get_state(stream) != PA_STREAM_READY)
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
209 goto unlock_and_fail;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
210
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
211 pa_threaded_mainloop_unlock(mainloop);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
212
24921
148ca265fcb6 Change parsing to allow host == NULL and sink != NULL
reimar
parents: 24920
diff changeset
213 free(devarg);
24782
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
214 return 1;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
215
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
216 unlock_and_fail:
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
217
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
218 if (mainloop)
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
219 pa_threaded_mainloop_unlock(mainloop);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
220
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
221 fail:
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
222 if (context)
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
223 GENERIC_ERR_MSG(context, "Init failed");
24921
148ca265fcb6 Change parsing to allow host == NULL and sink != NULL
reimar
parents: 24920
diff changeset
224 free(devarg);
24782
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
225 uninit(1);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
226 return 0;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
227 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
228
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
229 /** Destroy libao driver */
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
230 static void uninit(int immed) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
231 if (stream && !immed) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
232 pa_threaded_mainloop_lock(mainloop);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
233 waitop(pa_stream_drain(stream, success_cb, NULL));
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
234 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
235
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
236 if (mainloop)
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
237 pa_threaded_mainloop_stop(mainloop);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
238
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
239 if (stream) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
240 pa_stream_disconnect(stream);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
241 pa_stream_unref(stream);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
242 stream = NULL;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
243 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
244
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
245 if (context) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
246 pa_context_disconnect(context);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
247 pa_context_unref(context);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
248 context = NULL;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
249 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
250
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
251 if (mainloop) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
252 pa_threaded_mainloop_free(mainloop);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
253 mainloop = NULL;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
254 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
255 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
256
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
257 /** Play the specified data to the pulseaudio server */
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
258 static int play(void* data, int len, int flags) {
25386
bd46b759fd35 pa_stream_write reportedly needs locking of the main loop
reimar
parents: 25385
diff changeset
259 pa_threaded_mainloop_lock(mainloop);
25385
52f6c42c43bb Fix indentation
reimar
parents: 25384
diff changeset
260 if (pa_stream_write(stream, data, len, NULL, 0, PA_SEEK_RELATIVE) < 0) {
52f6c42c43bb Fix indentation
reimar
parents: 25384
diff changeset
261 GENERIC_ERR_MSG(context, "pa_stream_write() failed");
25386
bd46b759fd35 pa_stream_write reportedly needs locking of the main loop
reimar
parents: 25385
diff changeset
262 len = -1;
25385
52f6c42c43bb Fix indentation
reimar
parents: 25384
diff changeset
263 }
25386
bd46b759fd35 pa_stream_write reportedly needs locking of the main loop
reimar
parents: 25385
diff changeset
264 pa_threaded_mainloop_unlock(mainloop);
24782
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
265 return len;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
266 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
267
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
268 static void cork(int b) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
269 int success = 0;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
270 pa_threaded_mainloop_lock(mainloop);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
271 if (!waitop(pa_stream_cork(stream, b, success_cb, &success)) ||
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
272 !success)
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
273 GENERIC_ERR_MSG(context, "pa_stream_cork() failed");
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
274 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
275
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
276 /** Pause the audio stream by corking it on the server */
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
277 static void audio_pause(void) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
278 cork(1);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
279 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
280
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
281 /** Resume the audio stream by uncorking it on the server */
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
282 static void audio_resume(void) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
283 cork(0);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
284 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
285
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
286 /** Reset the audio stream, i.e. flush the playback buffer on the server side */
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
287 static void reset(void) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
288 int success = 0;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
289 pa_threaded_mainloop_lock(mainloop);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
290 if (!waitop(pa_stream_flush(stream, success_cb, &success)) ||
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
291 !success)
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
292 GENERIC_ERR_MSG(context, "pa_stream_flush() failed");
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
293 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
294
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
295 /** Return number of bytes that may be written to the server without blocking */
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
296 static int get_space(void) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
297 size_t l;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
298 pa_threaded_mainloop_lock(mainloop);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
299 l = pa_stream_writable_size(stream);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
300 pa_threaded_mainloop_unlock(mainloop);
24923
d0d04fe92bce Remove idiotic check that would always be false
reimar
parents: 24921
diff changeset
301 return l;
24782
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
302 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
303
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
304 /** Return the current latency in seconds */
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
305 static float get_delay(void) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
306 pa_usec_t latency = (pa_usec_t) -1;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
307 pa_threaded_mainloop_lock(mainloop);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
308 while (pa_stream_get_latency(stream, &latency, NULL) < 0) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
309 if (pa_context_errno(context) != PA_ERR_NODATA) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
310 GENERIC_ERR_MSG(context, "pa_stream_get_latency() failed");
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
311 break;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
312 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
313 /* Wait until latency data is available again */
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
314 pa_threaded_mainloop_wait(mainloop);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
315 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
316 pa_threaded_mainloop_unlock(mainloop);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
317 return latency == (pa_usec_t) -1 ? 0 : latency / 1000000.0;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
318 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
319
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
320 /** A callback function that is called when the
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
321 * pa_context_get_sink_input_info() operation completes. Saves the
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
322 * volume field of the specified structure to the global variable volume. */
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
323 static void info_func(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
324 if (is_last < 0) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
325 GENERIC_ERR_MSG(context, "Failed to get sink input info");
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
326 return;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
327 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
328 if (!i)
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
329 return;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
330 volume = i->volume;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
331 pa_threaded_mainloop_signal(mainloop, 0);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
332 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
333
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
334 static int control(int cmd, void *arg) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
335 switch (cmd) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
336 case AOCONTROL_GET_VOLUME: {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
337 ao_control_vol_t *vol = arg;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
338 uint32_t devidx = pa_stream_get_index(stream);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
339 pa_threaded_mainloop_lock(mainloop);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
340 if (!waitop(pa_context_get_sink_input_info(context, devidx, info_func, NULL))) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
341 GENERIC_ERR_MSG(context, "pa_stream_get_sink_input_info() failed");
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
342 return CONTROL_ERROR;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
343 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
344
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
345 if (volume.channels != 2)
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
346 vol->left = vol->right = pa_cvolume_avg(&volume)*100/PA_VOLUME_NORM;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
347 else {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
348 vol->left = volume.values[0]*100/PA_VOLUME_NORM;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
349 vol->right = volume.values[1]*100/PA_VOLUME_NORM;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
350 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
351
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
352 return CONTROL_OK;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
353 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
354
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
355 case AOCONTROL_SET_VOLUME: {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
356 const ao_control_vol_t *vol = arg;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
357 pa_operation *o;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
358
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
359 if (volume.channels != 2)
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
360 pa_cvolume_set(&volume, volume.channels, (pa_volume_t)vol->left*PA_VOLUME_NORM/100);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
361 else {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
362 volume.values[0] = (pa_volume_t)vol->left*PA_VOLUME_NORM/100;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
363 volume.values[1] = (pa_volume_t)vol->right*PA_VOLUME_NORM/100;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
364 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
365
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
366 if (!(o = pa_context_set_sink_input_volume(context, pa_stream_get_index(stream), &volume, NULL, NULL))) {
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
367 GENERIC_ERR_MSG(context, "pa_context_set_sink_input_volume() failed");
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
368 return CONTROL_ERROR;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
369 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
370 /* We don't wait for completion here */
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
371 pa_operation_unref(o);
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
372 return CONTROL_OK;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
373 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
374
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
375 default:
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
376 return CONTROL_UNKNOWN;
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
377 }
6479c850fcfd Add missing ao_pulse.c
reimar
parents:
diff changeset
378 }