1
/*
2
 * Copyright (C) 2008-2011 Various Authors
3
 * Copyright (C) 2009 Gregory Petrosyan
4
 *
5
 * This program is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation, either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18
19
#include <string.h>
20
21
#include <pulse/pulseaudio.h>
22
23
#include "op.h"
24
#include "mixer.h"
25
#include "debug.h"
26
#include "utils.h"
27
#include "xmalloc.h"
28
29
static pa_threaded_mainloop	*pa_ml;
30
static pa_context		*pa_ctx;
31
static pa_stream		*pa_s;
32
static pa_channel_map		 pa_cmap;
33
static pa_cvolume		 pa_vol;
34
static pa_sample_spec		 pa_ss;
35
36
/* configuration */
37
static int pa_restore_volume = 1;
38
39
#define ret_pa_error(err)						\
40
	do {								\
41
		d_print("PulseAudio error: %s\n", pa_strerror(err));	\
42
		return -OP_ERROR_INTERNAL;				\
43
	} while (0)
44
45
#define ret_pa_last_error() ret_pa_error(pa_context_errno(pa_ctx))
46
47
static pa_proplist *__create_app_proplist(void)
48
{
49
	pa_proplist	*pl;
50
	int		 rc;
51
52
	pl = pa_proplist_new();
53
	BUG_ON(!pl);
54
55
	rc = pa_proplist_sets(pl, PA_PROP_APPLICATION_NAME, "C* Music Player");
56
	BUG_ON(rc);
57
58
	rc = pa_proplist_sets(pl, PA_PROP_APPLICATION_VERSION, VERSION);
59
	BUG_ON(rc);
60
61
	return pl;
62
}
63
64
static pa_proplist *__create_stream_proplist(void)
65
{
66
	pa_proplist	*pl;
67
	int		 rc;
68
69
	pl = pa_proplist_new();
70
	BUG_ON(!pl);
71
72
	rc = pa_proplist_sets(pl, PA_PROP_MEDIA_ROLE, "music");
73
	BUG_ON(rc);
74
75
	rc = pa_proplist_sets(pl, PA_PROP_MEDIA_ICON_NAME, "audio-x-generic");
76
	BUG_ON(rc);
77
78
	return pl;
79
}
80
81
static const char *__pa_context_state_str(pa_context_state_t s)
82
{
83
	switch (s) {
84
	case PA_CONTEXT_AUTHORIZING:
85
		return "PA_CONTEXT_AUTHORIZING";
86
	case PA_CONTEXT_CONNECTING:
87
		return "PA_CONTEXT_CONNECTING";
88
	case PA_CONTEXT_FAILED:
89
		return "PA_CONTEXT_FAILED";
90
	case PA_CONTEXT_READY:
91
		return "PA_CONTEXT_READY";
92
	case PA_CONTEXT_SETTING_NAME:
93
		return "PA_CONTEXT_SETTING_NAME";
94
	case PA_CONTEXT_TERMINATED:
95
		return "PA_CONTEXT_TERMINATED";
96
	case PA_CONTEXT_UNCONNECTED:
97
		return "PA_CONTEXT_UNCONNECTED";
98
	}
99
100
	return "unknown";
101
}
102
103
static void __pa_context_running_cb(pa_context *c, void *data)
104
{
105
	const pa_context_state_t cs = pa_context_get_state(c);
106
107
	d_print("pulse: context state has changed to %s\n", __pa_context_state_str(cs));
108
109
	switch (cs) {
110
	case PA_CONTEXT_READY:
111
	case PA_CONTEXT_FAILED:
112
	case PA_CONTEXT_TERMINATED:
113
		pa_threaded_mainloop_signal(pa_ml, 0);
114
	default:
115
		return;
116
	}
117
}
118
119
static const char *__pa_stream_state_str(pa_stream_state_t s)
120
{
121
	switch (s) {
122
	case PA_STREAM_CREATING:
123
		return "PA_STREAM_CREATING";
124
	case PA_STREAM_FAILED:
125
		return "PA_STREAM_FAILED";
126
	case PA_STREAM_READY:
127
		return "PA_STREAM_READY";
128
	case PA_STREAM_TERMINATED:
129
		return "PA_STREAM_TERMINATED";
130
	case PA_STREAM_UNCONNECTED:
131
		return "PA_STREAM_UNCONNECTED";
132
	}
133
134
	return "unknown";
135
}
136
137
static void __pa_stream_running_cb(pa_stream *s, void *data)
138
{
139
	const pa_stream_state_t ss = pa_stream_get_state(s);
140
141
	d_print("pulse: stream state has changed to %s\n", __pa_stream_state_str(ss));
142
143
	switch (ss) {
144
	case PA_STREAM_READY:
145
	case PA_STREAM_FAILED:
146
	case PA_STREAM_TERMINATED:
147
		pa_threaded_mainloop_signal(pa_ml, 0);
148
	default:
149
		return;
150
	}
151
}
152
153
static void __pa_sink_input_info_cb(pa_context *c,
154
				    const pa_sink_input_info *i,
155
				    int eol,
156
				    void *data)
157
{
158
	if (i) {
159
		memcpy(&pa_vol, &i->volume, sizeof(pa_vol));
160
		pa_threaded_mainloop_signal(pa_ml, 0);
161
	}
162
}
163
164
static void __pa_stream_success_cb(pa_stream *s, int success, void *data)
165
{
166
	pa_threaded_mainloop_signal(pa_ml, 0);
167
}
168
169
static pa_sample_format_t __pa_sample_format(sample_format_t sf)
170
{
171
	const int signed_	= sf_get_signed(sf);
172
	const int big_endian	= sf_get_bigendian(sf);
173
	const int sample_size	= sf_get_sample_size(sf) * 8;
174
175
	if (!signed_ && sample_size == 8)
176
		return PA_SAMPLE_U8;
177
178
	if (signed_) {
179
		switch (sample_size) {
180
		case 16:
181
			return big_endian ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
182
		case 24:
183
			return big_endian ? PA_SAMPLE_S24BE : PA_SAMPLE_S24LE;
184
		case 32:
185
			return big_endian ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
186
		}
187
	}
188
189
	return PA_SAMPLE_INVALID;
190
}
191
192
static int __pa_wait_unlock(pa_operation *o)
193
{
194
	pa_operation_state_t state;
195
196
	if (!o) {
197
		pa_threaded_mainloop_unlock(pa_ml);
198
		ret_pa_last_error();
199
	}
200
201
	while ((state = pa_operation_get_state(o)) == PA_OPERATION_RUNNING)
202
		pa_threaded_mainloop_wait(pa_ml);
203
204
	pa_operation_unref(o);
205
	pa_threaded_mainloop_unlock(pa_ml);
206
207
	if (state == PA_OPERATION_DONE)
208
		return OP_ERROR_SUCCESS;
209
	else
210
		ret_pa_last_error();
211
}
212
213
static int __pa_nowait_unlock(pa_operation *o)
214
{
215
	if (!o) {
216
		pa_threaded_mainloop_unlock(pa_ml);
217
		ret_pa_last_error();
218
	}
219
220
	pa_operation_unref(o);
221
	pa_threaded_mainloop_unlock(pa_ml);
222
223
	return OP_ERROR_SUCCESS;
224
}
225
226
static int __pa_stream_cork(int pause_)
227
{
228
	pa_threaded_mainloop_lock(pa_ml);
229
230
	return __pa_wait_unlock(pa_stream_cork(pa_s, pause_, __pa_stream_success_cb, NULL));
231
}
232
233
static int __pa_stream_drain(void)
234
{
235
	pa_threaded_mainloop_lock(pa_ml);
236
237
	return __pa_wait_unlock(pa_stream_drain(pa_s, __pa_stream_success_cb, NULL));
238
}
239
240
static int __pa_create_context(void)
241
{
242
	pa_mainloop_api	*api;
243
	pa_proplist	*pl;
244
	int		 rc;
245
246
	pl = __create_app_proplist();
247
248
	api = pa_threaded_mainloop_get_api(pa_ml);
249
	BUG_ON(!api);
250
251
	pa_threaded_mainloop_lock(pa_ml);
252
253
	pa_ctx = pa_context_new_with_proplist(api, "C* Music Player", pl);
254
	BUG_ON(!pa_ctx);
255
	pa_proplist_free(pl);
256
257
	pa_context_set_state_callback(pa_ctx, __pa_context_running_cb, NULL);
258
259
	rc = pa_context_connect(pa_ctx, NULL, PA_CONTEXT_NOFAIL, NULL);
260
	if (rc)
261
		goto out_fail;
262
263
	for (;;) {
264
		pa_context_state_t state;
265
		state = pa_context_get_state(pa_ctx);
266
		if (state == PA_CONTEXT_READY)
267
			break;
268
		if (!PA_CONTEXT_IS_GOOD(state))
269
			goto out_fail_connected;
270
		pa_threaded_mainloop_wait(pa_ml);
271
	}
272
273
	pa_threaded_mainloop_unlock(pa_ml);
274
275
	return OP_ERROR_SUCCESS;
276
277
out_fail_connected:
278
	pa_context_disconnect(pa_ctx);
279
280
out_fail:
281
	pa_context_unref(pa_ctx);
282
	pa_ctx = NULL;
283
284
	pa_threaded_mainloop_unlock(pa_ml);
285
286
	ret_pa_last_error();
287
}
288
289
static int op_pulse_init(void)
290
{
291
	int rc;
292
293
	pa_ml = pa_threaded_mainloop_new();
294
	BUG_ON(!pa_ml);
295
296
	rc = pa_threaded_mainloop_start(pa_ml);
297
	if (rc) {
298
		pa_threaded_mainloop_free(pa_ml);
299
		ret_pa_error(rc);
300
	}
301
302
	return OP_ERROR_SUCCESS;
303
}
304
305
static int op_pulse_exit(void)
306
{
307
	if (pa_ml) {
308
		pa_threaded_mainloop_stop(pa_ml);
309
		pa_threaded_mainloop_free(pa_ml);
310
		pa_ml = NULL;
311
	}
312
313
	return OP_ERROR_SUCCESS;
314
}
315
316
#define RET_IF(x) case CHANNEL_POSITION_ ## x: return PA_CHANNEL_POSITION_ ## x
317
318
static pa_channel_position_t pulse_channel_position(channel_position_t p)
319
{
320
	switch (p) {
321
	RET_IF(MONO);
322
	RET_IF(FRONT_LEFT); RET_IF(FRONT_RIGHT); RET_IF(FRONT_CENTER);
323
	RET_IF(REAR_CENTER); RET_IF(REAR_LEFT); RET_IF(REAR_RIGHT);
324
	RET_IF(LFE);
325
	RET_IF(FRONT_LEFT_OF_CENTER); RET_IF(FRONT_RIGHT_OF_CENTER);
326
	RET_IF(SIDE_LEFT); RET_IF(SIDE_RIGHT);
327
	RET_IF(TOP_CENTER);
328
	RET_IF(TOP_FRONT_LEFT); RET_IF(TOP_FRONT_RIGHT); RET_IF(TOP_FRONT_CENTER);
329
	RET_IF(TOP_REAR_LEFT); RET_IF(TOP_REAR_RIGHT); RET_IF(TOP_REAR_CENTER);
330
	default:
331
		return PA_CHANNEL_POSITION_INVALID;
332
	}
333
}
334
335
static int op_pulse_open(sample_format_t sf, const channel_position_t *channel_map)
336
{
337
	pa_proplist	*pl;
338
	int		 rc, i;
339
340
	const pa_sample_spec ss = {
341
		.format		= __pa_sample_format(sf),
342
		.rate		= sf_get_rate(sf),
343
		.channels	= sf_get_channels(sf)
344
	};
345
346
	if (!pa_sample_spec_valid(&ss))
347
		return -OP_ERROR_SAMPLE_FORMAT;
348
349
	pa_ss = ss;
350
	if (channel_map && channel_map_valid(channel_map)) {
351
		pa_channel_map_init(&pa_cmap);
352
		pa_cmap.channels = ss.channels;
353
		for (i = 0; i < pa_cmap.channels; i++)
354
			pa_cmap.map[i] = pulse_channel_position(channel_map[i]);
355
	} else
356
		pa_channel_map_init_auto(&pa_cmap, ss.channels, PA_CHANNEL_MAP_ALSA);
357
358
	rc = __pa_create_context();
359
	if (rc)
360
		return rc;
361
362
	pl = __create_stream_proplist();
363
364
	pa_threaded_mainloop_lock(pa_ml);
365
366
	pa_s = pa_stream_new_with_proplist(pa_ctx, "playback", &ss, &pa_cmap, pl);
367
	pa_proplist_free(pl);
368
	if (!pa_s) {
369
		pa_threaded_mainloop_unlock(pa_ml);
370
		ret_pa_last_error();
371
	}
372
373
	pa_stream_set_state_callback(pa_s, __pa_stream_running_cb, NULL);
374
375
	rc = pa_stream_connect_playback(pa_s,
376
					NULL,
377
					NULL,
378
					PA_STREAM_NOFLAGS,
379
					pa_restore_volume ? NULL : &pa_vol,
380
					NULL);
381
	if (rc)
382
		goto out_fail;
383
384
	pa_threaded_mainloop_wait(pa_ml);
385
386
	if (pa_stream_get_state(pa_s) != PA_STREAM_READY)
387
		goto out_fail;
388
389
	pa_threaded_mainloop_unlock(pa_ml);
390
391
	return OP_ERROR_SUCCESS;
392
393
out_fail:
394
	pa_stream_unref(pa_s);
395
396
	pa_threaded_mainloop_unlock(pa_ml);
397
398
	ret_pa_last_error();
399
}
400
401
static int op_pulse_close(void)
402
{
403
	/*
404
	 * If this __pa_stream_drain() will be moved below following
405
	 * pa_threaded_mainloop_lock(), PulseAudio 0.9.19 will hang.
406
	 */
407
	if (pa_s)
408
		__pa_stream_drain();
409
410
	pa_threaded_mainloop_lock(pa_ml);
411
412
	if (pa_s) {
413
		pa_stream_disconnect(pa_s);
414
		pa_stream_unref(pa_s);
415
		pa_s = NULL;
416
	}
417
418
	if (pa_ctx) {
419
		pa_context_disconnect(pa_ctx);
420
		pa_context_unref(pa_ctx);
421
		pa_ctx = NULL;
422
	}
423
424
	pa_threaded_mainloop_unlock(pa_ml);
425
426
	return OP_ERROR_SUCCESS;
427
}
428
429
static int op_pulse_drop(void)
430
{
431
	pa_threaded_mainloop_lock(pa_ml);
432
433
	return __pa_wait_unlock(pa_stream_flush(pa_s, __pa_stream_success_cb, NULL));
434
}
435
436
static int op_pulse_write(const char *buf, int count)
437
{
438
	int rc;
439
440
	pa_threaded_mainloop_lock(pa_ml);
441
	rc = pa_stream_write(pa_s, buf, count, NULL, 0, PA_SEEK_RELATIVE);
442
	pa_threaded_mainloop_unlock(pa_ml);
443
444
	if (rc)
445
		ret_pa_error(rc);
446
	else
447
		return count;
448
}
449
450
static int op_pulse_buffer_space(void)
451
{
452
	int s;
453
454
	pa_threaded_mainloop_lock(pa_ml);
455
	s = (int)pa_stream_writable_size(pa_s);
456
	pa_threaded_mainloop_unlock(pa_ml);
457
458
	return s;
459
}
460
461
static int op_pulse_pause(void)
462
{
463
	return __pa_stream_cork(1);
464
}
465
466
static int op_pulse_unpause(void)
467
{
468
	return __pa_stream_cork(0);
469
}
470
471
static int op_pulse_set_option(int key, const char *val)
472
{
473
	return -OP_ERROR_NOT_OPTION;
474
}
475
476
static int op_pulse_get_option(int key, char **val)
477
{
478
	return -OP_ERROR_NOT_OPTION;
479
}
480
481
static int op_pulse_mixer_init(void)
482
{
483
	if (!pa_channel_map_init_stereo(&pa_cmap))
484
		ret_pa_last_error();
485
486
	pa_cvolume_reset(&pa_vol, 2);
487
488
	return OP_ERROR_SUCCESS;
489
}
490
491
static int op_pulse_mixer_exit(void)
492
{
493
	return OP_ERROR_SUCCESS;
494
}
495
496
static int op_pulse_mixer_open(int *volume_max)
497
{
498
	*volume_max = PA_VOLUME_NORM;
499
500
	return OP_ERROR_SUCCESS;
501
}
502
503
static int op_pulse_mixer_close(void)
504
{
505
	return OP_ERROR_SUCCESS;
506
}
507
508
static int op_pulse_mixer_get_fds(int *fds)
509
{
510
	return -OP_ERROR_NOT_SUPPORTED;
511
}
512
513
static int op_pulse_mixer_set_volume(int l, int r)
514
{
515
	if (!pa_s && pa_restore_volume)
516
		return -OP_ERROR_NOT_OPEN;
517
518
	pa_cvolume_set(&pa_vol, pa_ss.channels, (pa_volume_t) ((l + r) / 2));
519
	pa_cvolume_set_position(&pa_vol,
520
				&pa_cmap,
521
				PA_CHANNEL_POSITION_FRONT_LEFT,
522
				(pa_volume_t)l);
523
524
	pa_cvolume_set_position(&pa_vol,
525
				&pa_cmap,
526
				PA_CHANNEL_POSITION_FRONT_RIGHT,
527
				(pa_volume_t)r);
528
529
	if (!pa_s) {
530
		return OP_ERROR_SUCCESS;
531
	} else {
532
		pa_threaded_mainloop_lock(pa_ml);
533
534
		return __pa_nowait_unlock(pa_context_set_sink_input_volume(pa_ctx,
535
								           pa_stream_get_index(pa_s),
536
								           &pa_vol,
537
								           NULL,
538
								           NULL));
539
	}
540
}
541
542
static int op_pulse_mixer_get_volume(int *l, int *r)
543
{
544
	int rc = OP_ERROR_SUCCESS;
545
546
	if (!pa_s && pa_restore_volume)
547
		return -OP_ERROR_NOT_OPEN;
548
549
	if (pa_s) {
550
		pa_threaded_mainloop_lock(pa_ml);
551
552
		rc = __pa_wait_unlock(pa_context_get_sink_input_info(pa_ctx,
553
								     pa_stream_get_index(pa_s),
554
								     __pa_sink_input_info_cb,
555
								     NULL));
556
	}
557
558
	*l = pa_cvolume_get_position(&pa_vol, &pa_cmap, PA_CHANNEL_POSITION_FRONT_LEFT);
559
	*r = pa_cvolume_get_position(&pa_vol, &pa_cmap, PA_CHANNEL_POSITION_FRONT_RIGHT);
560
561
	return rc;
562
}
563
564
static int op_pulse_mixer_set_option(int key, const char *val)
565
{
566
	switch (key) {
567
	case 0:
568
		pa_restore_volume = is_freeform_true(val);
569
		break;
570
	default:
571
		return -OP_ERROR_NOT_OPTION;
572
	}
573
	return 0;
574
}
575
576
static int op_pulse_mixer_get_option(int key, char **val)
577
{
578
	switch (key) {
579
	case 0:
580
		*val = xstrdup(pa_restore_volume ? "1" : "0");
581
		break;
582
	default:
583
		return -OP_ERROR_NOT_OPTION;
584
	}
585
	return 0;
586
}
587
588
const struct output_plugin_ops op_pcm_ops = {
589
	.init		= op_pulse_init,
590
	.exit		= op_pulse_exit,
591
	.open		= op_pulse_open,
592
	.close		= op_pulse_close,
593
	.drop		= op_pulse_drop,
594
	.write		= op_pulse_write,
595
	.buffer_space	= op_pulse_buffer_space,
596
	.pause		= op_pulse_pause,
597
	.unpause	= op_pulse_unpause,
598
	.set_option	= op_pulse_set_option,
599
	.get_option	= op_pulse_get_option
600
};
601
602
const struct mixer_plugin_ops op_mixer_ops = {
603
	.init		= op_pulse_mixer_init,
604
	.exit		= op_pulse_mixer_exit,
605
	.open		= op_pulse_mixer_open,
606
	.close		= op_pulse_mixer_close,
607
	.get_fds	= op_pulse_mixer_get_fds,
608
	.set_volume	= op_pulse_mixer_set_volume,
609
	.get_volume	= op_pulse_mixer_get_volume,
610
	.set_option	= op_pulse_mixer_set_option,
611
	.get_option	= op_pulse_mixer_get_option
612
};
613
614
const char * const op_pcm_options[] = {
615
	NULL
616
};
617
618
const char * const op_mixer_options[] = {
619
	"restore_volume",
620
	NULL
621
};
622
623
const int op_priority = -2;