10l: comparison of char* ptrs with string literals
[mplayer.git] / libao2 / ao_polyp.c
blob22239762a25607cf695fd0f627b98add2c99c9df
1 #include <assert.h>
2 #include <string.h>
4 #include <polyp/polyplib.h>
5 #include <polyp/polyplib-error.h>
6 #include <polyp/mainloop.h>
8 #include "config.h"
9 #include "audio_out.h"
10 #include "audio_out_internal.h"
11 #include "libaf/af_format.h"
12 #include "mp_msg.h"
14 #define POLYP_CLIENT_NAME "MPlayer"
16 /** General driver info */
17 static ao_info_t info = {
18 "Polypaudio audio output",
19 "polyp",
20 "Lennart Poettering",
24 /** The sink to connect to */
25 static char *sink = NULL;
27 /** Polypaudio playback stream object */
28 static struct pa_stream *stream = NULL;
30 /** Polypaudio connection context */
31 static struct pa_context *context = NULL;
33 /** Main event loop object */
34 static struct pa_mainloop *mainloop = NULL;
36 /** Some special libao macro magic */
37 LIBAO_EXTERN(polyp)
39 /** Wait until no further actions are pending on the connection context */
40 static void wait_for_completion(void) {
41 assert(context && mainloop);
43 while (pa_context_is_pending(context))
44 pa_mainloop_iterate(mainloop, 1, NULL);
47 /** Make sure that the connection context doesn't starve to death */
48 static void keep_alive(void) {
49 assert(context && mainloop);
51 while (pa_mainloop_iterate(mainloop, 0, NULL) > 0);
54 /** Wait until the specified operation completes */
55 static void wait_for_operation(struct pa_operation *o) {
56 assert(o && context && mainloop);
58 while (pa_operation_get_state(o) == PA_OPERATION_RUNNING)
59 pa_mainloop_iterate(mainloop, 1, NULL);
61 pa_operation_unref(o);
64 /** libao initialization function, arguments are sampling frequency,
65 * number of channels, sample type and some flags */
66 static int init(int rate_hz, int channels, int format, int flags) {
67 struct pa_sample_spec ss;
68 struct pa_buffer_attr a;
69 char hn[128];
70 char *host = NULL;
72 assert(!context && !stream && !mainloop);
74 if (ao_subdevice) {
75 int i = strcspn(ao_subdevice, ":");
76 if (i >= sizeof(hn))
77 i = sizeof(hn)-1;
79 if (i > 0) {
80 strncpy(host = hn, ao_subdevice, i);
81 hn[i] = 0;
84 if (ao_subdevice[i] == ':')
85 sink = ao_subdevice+i+1;
88 mp_msg(MSGT_AO, MSGL_ERR, "AO: [polyp] -%s-%s-\n", host, sink);
91 ss.channels = channels;
92 ss.rate = rate_hz;
94 switch (format) {
95 case AF_FORMAT_U8:
96 ss.format = PA_SAMPLE_U8;
97 break;
98 case AF_FORMAT_S16_LE:
99 ss.format = PA_SAMPLE_S16LE;
100 break;
101 case AF_FORMAT_S16_BE:
102 ss.format = PA_SAMPLE_S16BE;
103 break;
104 case AF_FORMAT_FLOAT_NE:
105 ss.format = PA_SAMPLE_FLOAT32;
106 break;
107 default:
108 mp_msg(MSGT_AO, MSGL_ERR, "AO: [polyp] Unsupported sample spec\n");
109 goto fail;
113 if (!pa_sample_spec_valid(&ss)) {
114 mp_msg(MSGT_AO, MSGL_ERR, "AO: [polyp] Invalid sample spec\n");
115 goto fail;
119 mainloop = pa_mainloop_new();
120 assert(mainloop);
122 context = pa_context_new(pa_mainloop_get_api(mainloop), POLYP_CLIENT_NAME);
123 assert(context);
125 pa_context_connect(context, host, 1, NULL);
127 wait_for_completion();
129 if (pa_context_get_state(context) != PA_CONTEXT_READY) {
130 mp_msg(MSGT_AO, MSGL_ERR, "AO: [polyp] Failed to connect to server: %s\n", pa_strerror(pa_context_errno(context)));
131 goto fail;
134 stream = pa_stream_new(context, "audio stream", &ss);
135 assert(stream);
137 a.maxlength = pa_bytes_per_second(&ss)*1;
138 a.tlength = a.maxlength*9/10;
139 a.prebuf = a.tlength/2;
140 a.minreq = a.tlength/10;
142 pa_stream_connect_playback(stream, sink, &a, PA_STREAM_INTERPOLATE_LATENCY, PA_VOLUME_NORM);
144 wait_for_completion();
146 if (pa_stream_get_state(stream) != PA_STREAM_READY) {
147 mp_msg(MSGT_AO, MSGL_ERR, "AO: [polyp] Failed to connect to server: %s\n", pa_strerror(pa_context_errno(context)));
148 goto fail;
151 return 1;
153 fail:
154 uninit(1);
155 return 0;
158 /** Destroy libao driver */
159 static void uninit(int immed) {
160 if (stream) {
161 if (!immed && pa_stream_get_state(stream) == PA_STREAM_READY)
162 wait_for_operation(pa_stream_drain(stream, NULL, NULL));
164 pa_stream_unref(stream);
165 stream = NULL;
168 if (context) {
169 pa_context_unref(context);
170 context = NULL;
173 if (mainloop) {
174 pa_mainloop_free(mainloop);
175 mainloop = NULL;
179 /** Play the specified data to the polypaudio server */
180 static int play(void* data, int len, int flags) {
181 assert(stream && context);
183 if (pa_stream_get_state(stream) != PA_STREAM_READY)
184 return -1;
186 if (!len)
187 wait_for_operation(pa_stream_trigger(stream, NULL, NULL));
188 else
189 pa_stream_write(stream, data, len, NULL, 0);
191 wait_for_completion();
193 if (pa_stream_get_state(stream) != PA_STREAM_READY)
194 return -1;
196 return len;
199 /** Pause the audio stream by corking it on the server */
200 static void audio_pause(void) {
201 assert(stream && context && pa_stream_get_state(stream) == PA_STREAM_READY);
202 wait_for_operation(pa_stream_cork(stream, 1, NULL, NULL));
205 /** Resume the audio stream by uncorking it on the server */
206 static void audio_resume(void) {
207 assert(stream && context && pa_stream_get_state(stream) == PA_STREAM_READY);
208 wait_for_operation(pa_stream_cork(stream, 0, NULL, NULL));
211 /** Reset the audio stream, i.e. flush the playback buffer on the server side */
212 static void reset(void) {
213 assert(stream && context && pa_stream_get_state(stream) == PA_STREAM_READY);
214 wait_for_operation(pa_stream_flush(stream, NULL, NULL));
217 /** Return number of bytes that may be written to the server without blocking */
218 static int get_space(void) {
219 uint32_t l;
220 assert(stream && context && pa_stream_get_state(stream) == PA_STREAM_READY);
222 keep_alive();
224 l = pa_stream_writable_size(stream);
226 return l;
229 /* A temporary latency variable */
230 /* static pa_usec_t latency = 0; */
232 /* static void latency_func(struct pa_stream *s, const struct pa_latency_info *l, void *userdata) { */
233 /* int negative = 0; */
235 /* if (!l) { */
236 /* mp_msg(MSGT_AO, MSGL_ERR, "AO: [polyp] Invalid sample spec: %s\n", pa_strerror(pa_context_errno(context))); */
237 /* return; */
238 /* } */
240 /* latency = pa_stream_get_latency(s, l, &negative); */
242 /* /\* Nor really required *\/ */
243 /* if (negative) */
244 /* latency = 0; */
245 /* } */
247 /** Return the current latency in seconds */
248 static float get_delay(void) {
249 pa_usec_t latency;
250 assert(stream && context && pa_stream_get_state(stream) == PA_STREAM_READY);
252 /* latency = 0; */
253 /* wait_for_operation(pa_stream_get_latency(stream, latency_func, NULL)); */
254 /* pa_operation_unref(pa_stream_get_latency(stream, latency_func, NULL)); */
256 latency = pa_stream_get_interpolated_latency(stream, NULL);
258 return (float) latency/1000000;
261 /** A temporary variable to store the current volume */
262 static pa_volume_t volume = PA_VOLUME_NORM;
264 /** A callback function that is called when the
265 * pa_context_get_sink_input_info() operation completes. Saves the
266 * volume field of the specified structure to the global variable volume. */
267 static void info_func(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) {
268 if (is_last < 0) {
269 mp_msg(MSGT_AO, MSGL_ERR, "AO: [polyp] Failed to get sink input info: %s\n", pa_strerror(pa_context_errno(context)));
270 return;
273 if (!i)
274 return;
276 volume = i->volume;
279 /** Issue special libao controls on the device */
280 static int control(int cmd, void *arg) {
282 if (!context || !stream)
283 return CONTROL_ERROR;
285 switch (cmd) {
287 case AOCONTROL_SET_DEVICE:
288 /* Change the playback device */
289 sink = (char*)arg;
290 return CONTROL_OK;
292 case AOCONTROL_GET_DEVICE:
293 /* Return the playback device */
294 *(char**)arg = sink;
295 return CONTROL_OK;
297 case AOCONTROL_GET_VOLUME: {
298 /* Return the current volume of the playback stream */
299 ao_control_vol_t *vol = (ao_control_vol_t*) arg;
301 volume = PA_VOLUME_NORM;
302 wait_for_operation(pa_context_get_sink_input_info(context, pa_stream_get_index(stream), info_func, NULL));
303 vol->left = vol->right = (int) (pa_volume_to_user(volume)*100);
304 return CONTROL_OK;
307 case AOCONTROL_SET_VOLUME: {
308 /* Set the playback volume of the stream */
309 const ao_control_vol_t *vol = (ao_control_vol_t*) arg;
310 int v = vol->left;
311 if (vol->right > v)
312 v = vol->left;
314 wait_for_operation(pa_context_set_sink_input_volume(context, pa_stream_get_index(stream), pa_volume_from_user((double)v/100), NULL, NULL));
316 return CONTROL_OK;
319 default:
320 /* Unknown CONTROL command */
321 return CONTROL_UNKNOWN;