1 /* sound-pulse.c - play a sound over the Pulse Audio Server
3 Copyright (C) 2006, 2007, 2008 Sebastian Freundt
5 Author: Sebastian Freundt <hroptatyr@sxemacs.org>
7 * This file is part of SXEmacs.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the author nor the names of any contributors
21 * may be used to endorse or promote products derived from this
22 * software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
31 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
33 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
34 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 /* Synched up with: Not in FSF. */
53 #include "sound-pulse.h"
57 #define MYSELF ADRIVER_PULSE
59 #define __PULSE_DEBUG__(args...) fprintf(stderr, "PULSE " args)
60 #ifndef PULSE_DEBUG_FLAG
61 #define PULSE_DEBUG(args...)
63 #define PULSE_DEBUG(args...) __PULSE_DEBUG__(args)
65 #define PULSE_DEBUG_CTX(args...) PULSE_DEBUG("[connection]: " args)
66 #define PULSE_DEBUG_ML(args...) PULSE_DEBUG("[mainloop]: " args)
67 #define PULSE_DEBUG_MX(args...) PULSE_DEBUG("[semaphore]: " args)
68 #define PULSE_DEBUG_S(args...) PULSE_DEBUG("[stream]: " args)
69 #define PULSE_DEBUG_PT(args...) PULSE_DEBUG("[pthread]: " args)
70 #define PULSE_DEBUG_COE(args...) PULSE_DEBUG("[coerce]: " args)
71 #define PULSE_DEBUG_AJ(args...) PULSE_DEBUG("[audio-job]: " args)
72 #define PULSE_DEBUG_CACHE(args...) PULSE_DEBUG("[cache]: " args)
73 #define PULSE_CRITICAL(args...) __PULSE_DEBUG__("CRITICAL: " args)
76 static int sound_pulse_init_mainloop(ad_device_data*);
78 time_ev_cb(pa_mainloop_api*, pa_time_event*, const struct timeval*, void*);
80 struct sound_pulse_data_s {
81 Lisp_Object stream; /* media has to deal with this actually */
89 pa_threaded_mainloop *tml;
91 pa_mainloop_api *mlapi;
93 const pa_sink_info *sink_info;
94 struct sxe_semaphore_s ctxsem;
97 struct sound_pulse_aj_data_s {
100 struct pa_sample_spec sampspec;
101 struct pa_channel_map chanmap;
102 pa_buffer_attr buffattr;
107 pa_time_event *time_ev;
110 media_sample_format_t *msf;
112 audio_coerce_chain_t coe_chain[4];
113 sxe_mse_rerate_args *rrargs;
117 DECLARE_AUDIO_DEVICE_SIMPLE_METHS(sound_pulse);
118 DEFINE_AUDIO_DEVICE_SIMPLE(sound_pulse);
122 sound_pulse_mark(ad_device_data *devdata)
124 sound_pulse_data_t spd = (sound_pulse_data_t)devdata;
128 mark_object(spd->stream);
129 mark_object(spd->client);
130 mark_object(spd->sink);
131 mark_object(spd->source);
132 mark_object(spd->server);
137 sound_pulse_print(Lisp_Object device, Lisp_Object pcfun, int ef)
139 sound_pulse_data_t spd = NULL;
140 pa_context_state_t st;
142 spd = get_audio_device_data(device);
143 /* cannot use incomplete or corrupt audio devices */
144 if (XAUDIO_DEVICE_DRIVER(device) != MYSELF || spd == NULL) {
145 write_c_string(" VOID", pcfun);
146 /* now that we are here, mark AO device as dead */
147 XAUDIO_DEVICE_STATE(device) = ASTATE_DEAD;
151 /* info about the connected output plugin */
152 write_c_string(" :server ", pcfun);
153 if (NILP(spd->server))
154 write_c_string("#default", pcfun);
156 print_internal(spd->server, pcfun, ef);
158 write_c_string(" :sink ", pcfun);
159 if (NILP(spd->sink)) {
160 write_c_string("#default", pcfun);
162 print_internal(spd->sink, pcfun, ef);
166 if (spd->sink_info) {
167 write_c_string(" (", pcfun);
168 write_c_string(spd->sink_info->description, pcfun);
169 write_c_string(")", pcfun);
171 write_c_string(" (sink does not exist)", pcfun);
175 write_c_string(" :source ", pcfun);
176 if (NILP(spd->source))
177 write_c_string("#default", pcfun);
179 print_internal(spd->source, pcfun, ef);
181 write_c_string(" :server-state ", pcfun);
184 write_c_string("#b0rked", pcfun);
188 st = pa_context_get_state(spd->ctx);
189 switch ((unsigned int)st) {
190 case PA_CONTEXT_CONNECTING:
191 case PA_CONTEXT_AUTHORIZING:
192 case PA_CONTEXT_SETTING_NAME:
193 write_c_string("#busy", pcfun);
196 case PA_CONTEXT_READY:
197 write_c_string("#connected", pcfun);
200 case PA_CONTEXT_TERMINATED:
201 write_c_string("#terminated", pcfun);
204 case PA_CONTEXT_FAILED:
206 write_c_string("#failed", pcfun);
210 write_c_string(" :api ", pcfun);
211 if (spd->ml_threaded_p) {
212 write_fmt_str(pcfun, "#threaded :mainloop 0x%lx",
213 (long unsigned int)spd->tml);
215 write_fmt_str(pcfun, "#non-threaded :mainloop 0x%lx",
216 (long unsigned int)spd->ml);
222 static ad_device_data *
223 sound_pulse_create(Lisp_Object pulse_options)
226 sound_pulse_data_t spd = NULL;
227 /* option keywords */
228 Lisp_Object opt_server = Qnil;
229 Lisp_Object opt_sink = Qnil;
230 Lisp_Object opt_source = Qnil;
231 Lisp_Object opt_client = Qnil;
232 Lisp_Object opt_role = Qnil;
233 Lisp_Object opt_stream = Qnil;
234 Lisp_Object opt_immediate = Qnil;
235 Lisp_Object opt_threaded = Qnil;
236 Lisp_Object opt_force = Qnil;
239 opt_server = Fplist_get(pulse_options, intern(":server"), Qnil);
240 if (!NILP(opt_server) && !STRINGP(opt_server)) {
241 wrong_type_argument(Qstringp, opt_server);
245 opt_sink = Fplist_get(pulse_options, intern(":sink"), Qnil);
246 if (!NILP(opt_sink) && !STRINGP(opt_sink)) {
247 wrong_type_argument(Qstringp, opt_sink);
251 opt_client = Fplist_get(pulse_options, intern(":client"), Qnil);
252 if (!NILP(opt_client) && !STRINGP(opt_client)) {
253 wrong_type_argument(Qstringp, opt_client);
257 opt_role = Fplist_get(pulse_options, intern(":role"), Qnil);
258 if (!NILP(opt_role) && !STRINGP(opt_role)) {
259 wrong_type_argument(Qstringp, opt_role);
263 opt_stream = Fplist_get(pulse_options, intern(":stream"), Qnil);
264 if (!NILP(opt_stream) && !STRINGP(opt_stream)) {
265 wrong_type_argument(Qstringp, opt_stream);
269 opt_immediate = Fplist_get(pulse_options, intern(":immediate"), Qt);
270 opt_threaded = Fplist_get(pulse_options, intern(":threaded"), Qt);
271 opt_force = Fplist_get(pulse_options, intern(":force"), Qnil);
273 /* initialise and fill */
274 spd = xnew_and_zero(struct sound_pulse_data_s);
275 spd->server = opt_server;
276 spd->client = opt_client;
277 spd->role = opt_role;
278 spd->sink = opt_sink;
279 spd->source = opt_source;
280 spd->stream = opt_stream;
282 spd->ml_threaded_p = !NILP(opt_threaded);
284 if (NILP(opt_immediate))
285 return (ad_device_data*)spd;
287 sound_pulse_init_mainloop(spd);
289 if (spd->ml_running_p == 0) /* yeah, finish immediately */
290 sound_pulse_finish(spd);
292 if (NILP(opt_force) && spd->ml_running_p == 0) {
295 error(GETTEXT("Error: audio-pulse: "
296 "Initialising connection to PulseAudio failed."));
300 return (ad_device_data*)spd;
304 sound_pulse_finish(ad_device_data *data)
306 sound_pulse_data_t spd = data;
310 if (spd != NULL && 0) {
319 spd->ml_running_p = 0;
321 /* setting this to 0 is not enough? :\ */
323 PULSE_DEBUG_CTX("DRAIN.\n");
324 pa_context_drain(spd->ctx, NULL, NULL);
325 PULSE_DEBUG_CTX("STOP.\n");
326 pa_context_disconnect(spd->ctx);
327 pa_context_unref(spd->ctx);
328 SXE_SEMAPH_FINI(&(spd->ctxsem));
332 PULSE_DEBUG_ML("Is there a mainloop awake?\n");
333 if (spd->ml_threaded_p) {
335 PULSE_DEBUG_ML("STOP.\n");
336 pa_threaded_mainloop_stop(spd->tml);
337 PULSE_DEBUG_ML("FREE. bye bye\n");
338 pa_threaded_mainloop_free(spd->tml);
344 PULSE_DEBUG_ML("FREE. bye bye (non-threaded)\n");
345 pa_mainloop_free(spd->ml);
350 PULSE_DEBUG_CTX("finish.\n");
358 /** Wait until the specified operation completes */
359 #define wait_for_operation(_m, _o) \
361 struct pa_operation *__o = (_o); \
362 while (pa_operation_get_state(__o) == \
363 PA_OPERATION_RUNNING) \
364 pa_mainloop_iterate((_m), 1, NULL); \
365 pa_operation_unref(__o); \
368 /** Wait until no further actions are pending on the connection context */
369 #define wait_for_completion(_c, _m) \
371 while (pa_context_is_pending(_c)) \
372 pa_mainloop_iterate((_m), 1, NULL); \
377 my_pa_free_cb(void *data)
379 /* dummy callback which ought to free DATA,
380 * however, we want to recycle the memory as much as possible,
381 * we free it ourselves */
382 PULSE_DEBUG_S("my_pa_free_cb called 0x%lx\n",
383 (long unsigned int)data);
388 static inline pa_volume_t
389 _sound_pulse_change_volume(
390 pa_cvolume *cvolp, pa_context *ctx,
391 pa_stream *stream, pa_volume_t volume)
392 __attribute__((always_inline));
393 static inline pa_volume_t
394 _sound_pulse_change_volume(
395 pa_cvolume *cvolp, pa_context *ctx,
396 pa_stream *stream, pa_volume_t volume)
400 pa_cvolume_set(cvolp, cvolp->channels,
401 (volume*PA_VOLUME_NORM)/MEDIA_SAMPLE_VOLUME_NORM);
403 if (!(o = pa_context_set_sink_input_volume(
404 ctx, pa_stream_get_index(stream), cvolp, NULL, NULL))) {
405 PULSE_CRITICAL("Cannot set volume.\n");
407 pa_operation_unref(o);
412 /* handling of events from the audio job's private queue */
415 sound_pulse_stop(audio_job_t aj)
416 __attribute__((always_inline));
418 sound_pulse_stop(audio_job_t aj)
420 sound_pulse_aj_data_t spsd;
423 SXE_MUTEX_LOCK(&aj->mtx);
424 spsd = audio_job_device_data(aj);
425 stream = spsd->stream;
426 PULSE_DEBUG_S("FLUSH. (0x%lx)\n", (long unsigned int)aj);
427 pa_operation_unref(pa_stream_flush(stream, NULL, NULL));
428 pa_stream_disconnect(stream);
429 aj->play_state = MTPSTATE_STOP;
430 SXE_MUTEX_UNLOCK(&aj->mtx);
435 sound_pulse_pause(audio_job_t aj)
436 __attribute__((always_inline));
438 sound_pulse_pause(audio_job_t aj)
440 sound_pulse_aj_data_t spsd;
441 sound_pulse_data_t spd;
445 SXE_MUTEX_LOCK(&aj->mtx);
446 spd = get_audio_device_data(aj->device);
447 spsd = audio_job_device_data(aj);
448 stream = spsd->stream;
449 PULSE_DEBUG_S("CORK. (0x%lx)\n", (long unsigned int)aj);
450 pa_operation_unref(pa_stream_cork(stream, 1, NULL, NULL));
451 aj->play_state = MTPSTATE_PAUSE;
453 if (audio_job_queue(aj)) {
454 spsd->time_ev = spd->mlapi->
455 time_new(spd->mlapi, &tv, time_ev_cb, aj);
458 SXE_MUTEX_UNLOCK(&aj->mtx);
463 sound_pulse_resume(audio_job_t aj)
464 __attribute__((always_inline));
466 sound_pulse_resume(audio_job_t aj)
468 sound_pulse_aj_data_t spsd;
469 sound_pulse_data_t spd;
472 SXE_MUTEX_LOCK(&aj->mtx);
473 spd = get_audio_device_data(aj->device);
474 spsd = audio_job_device_data(aj);
475 stream = spsd->stream;
476 PULSE_DEBUG_S("UNCORK. (0x%lx)\n", (long unsigned int)aj);
479 spd->mlapi->time_free(spsd->time_ev);
480 spsd->time_ev = NULL;
483 pa_operation_unref(pa_stream_cork(stream, 0, NULL, NULL));
484 aj->play_state = MTPSTATE_RUN;
485 SXE_MUTEX_UNLOCK(&aj->mtx);
490 sound_pulse_change_volume(audio_job_t aj, audio_job_event_args_t args)
492 sound_pulse_aj_data_t spsd;
493 pa_volume_t new_vol = args->volume_args;
495 PULSE_DEBUG_AJ("->%d\n", (int)new_vol);
497 SXE_MUTEX_LOCK(&aj->mtx);
498 spsd = audio_job_device_data(aj);
499 spsd->volume = _sound_pulse_change_volume(
500 &spsd->chanvol, spsd->ctx, spsd->stream, new_vol);
501 aj->volume = (int)(spsd->volume);
502 SXE_MUTEX_UNLOCK(&aj->mtx);
506 sound_pulse_change_rate(audio_job_t aj, audio_job_event_args_t args)
508 SXE_MUTEX_LOCK(&aj->mtx);
509 aj->ratetrafo = args->rate_args;
510 SXE_MUTEX_UNLOCK(&aj->mtx);
514 sound_pulse_change_state(audio_job_t aj, audio_job_event_args_t args)
516 switch (args->state_args) {
518 PULSE_DEBUG_AJ("->pause state\n");
519 sound_pulse_pause(aj);
522 PULSE_DEBUG_AJ("->resume state\n");
523 sound_pulse_resume(aj);
526 PULSE_DEBUG_AJ("->start state\n");
529 PULSE_DEBUG_AJ("->stop state\n");
530 sound_pulse_stop(aj);
533 case no_audio_job_change_states:
535 PULSE_DEBUG_AJ("->unknown state\n");
541 sound_pulse_handle_aj_events(audio_job_t aj)
542 __attribute__((always_inline));
544 sound_pulse_handle_aj_events(audio_job_t aj)
546 sound_pulse_aj_data_t spsd;
548 audio_job_event_t ev = NULL;
551 #if defined EF_USE_ASYNEQ
552 if (audio_job_queue(aj)) {
553 assert((long unsigned int)audio_job_queue(aj) != 0xB16B00B5);
557 PULSE_DEBUG_AJ("handle aj events called on 0x%lx\n",
558 (long unsigned int)aj);
560 SXE_MUTEX_LOCK(&aj->mtx);
561 spsd = audio_job_device_data(aj);
562 eq = audio_job_queue(aj);
563 SXE_MUTEX_UNLOCK(&aj->mtx);
564 stream = spsd->stream;
565 if ((ev = eq_noseeum_dequeue(eq)) == NULL) {
568 if (stream == NULL || pa_stream_get_state(stream) != PA_STREAM_READY) {
572 PULSE_DEBUG_AJ("Event 0x%lx\n", (long unsigned int)ev);
573 switch (audio_job_event_kind(ev)) {
574 case aj_change_state:
575 PULSE_DEBUG_AJ("change state event\n");
576 sound_pulse_change_state(aj, &audio_job_event_args(ev));
578 case aj_change_volume:
579 PULSE_DEBUG_AJ("change volume event\n");
580 sound_pulse_change_volume(aj, &audio_job_event_args(ev));
583 PULSE_DEBUG_AJ("change rate event\n");
584 sound_pulse_change_rate(aj, &audio_job_event_args(ev));
587 case no_audio_job_event_kinds:
589 PULSE_CRITICAL("unknown event\n");
592 free_audio_job_event(ev);
596 time_ev_cb(pa_mainloop_api *m, pa_time_event *e,
597 const struct timeval *tv, void *userdata)
599 /* check an audio-job's queue for incoming events */
600 struct timeval next; /* for rescheduling this construction */
601 audio_job_t aj = userdata;
602 sound_pulse_aj_data_t spsd = audio_job_device_data(aj);;
604 sound_pulse_handle_aj_events(userdata);
606 if (spsd->time_ev != NULL) {
607 /* reschedule the thing */
608 pa_gettimeofday(&next);
609 pa_timeval_add(&next, 25000);
610 m->time_restart(e, &next);
613 #endif /* EF_USE_ASYNEQ */
615 /* This is called whenever stream draining has completed */
617 stream_drain_complete(pa_stream *stream, int success, void *userdata)
619 audio_job_t aj = userdata;
621 PULSE_DEBUG_S("drain_complete cb called (0x%lx)\n",
622 (long unsigned int)aj);
624 if (UNLIKELY(!success)) {
625 PULSE_CRITICAL("Failed to drain stream 0x%lx\n",
626 (long unsigned int)aj);
629 pa_stream_disconnect(stream);
630 PULSE_DEBUG_S("leaving stream_drain cb (0x%lx)\n",
631 (long unsigned int)aj);
635 /* This is called whenever new data may be written to the stream */
637 stream_write_callback(pa_stream *stream, size_t length, void *userdata)
639 audio_job_t aj = NULL;
640 media_substream *mss = NULL;
641 int resolution __attribute__((unused));
643 media_thread_play_state mtp;
645 size_t real_frm_sz __attribute__((unused));
647 /* pulse and subthread stuff */
648 sound_pulse_aj_data_t spsd;
649 pa_context *ctx __attribute__((unused)) = NULL;
650 sxe_media_sample_t *tmpbuf;
652 assert(stream && length);
654 if (((aj = userdata) == NULL) ||
655 ((mss = aj->substream) == NULL)) {
656 PULSE_CRITICAL("This idiot of mainloop gave us wrong data: "
657 "aj:0x%lx mss:0x%lx\n",
658 (long unsigned int)aj,
659 (long unsigned int)mss);
661 PULSE_DEBUG_S("FLUSH.\n");
664 stream, stream_drain_complete, aj));
665 pa_stream_disconnect(stream);
669 PULSE_DEBUG_S("stream_write cb called on 0x%lx\n",
670 (long unsigned int)aj);
671 if (audio_job_queue(aj)) {
672 PULSE_DEBUG_S("checking queue\n");
673 sound_pulse_handle_aj_events(userdata);
675 SXE_MUTEX_LOCK(&aj->mtx);
676 spsd = audio_job_device_data(aj);
677 resolution = aj->resolution;
678 real_frm_sz = SOUND_MAX_SAMPLE_WIDTH * (channels = aj->channels);
681 #ifndef EF_USE_ASYNEQ
682 /* Set the playback volume of the stream */
683 if (aj->volume != spsd->volume) {
684 spsd->volume = _sound_pulse_change_volume(
685 &spsd->chanvol, ctx, stream, (pa_volume_t)aj->volume);
687 #endif /* !EF_USE_ASYNEQ */
689 mtp = aj->play_state;
692 /* set up length, rerate args and tmpbuf */
693 tmplen = length * (spsd->rrargs->tweak = aj->ratetrafo);
694 /* It's unlikely but I hit these constraints personally once so
695 let's handle them here.
696 Problem is that a request of 10000 samples from ffmpeg might
697 yield 11560 samples because the decode is not that
698 fine-tunable because a muxed'n'encoded packet likely (if not
699 always) contains a bunch of raw samples (==
701 Thence we add an extra 25% threshold here to be maximum
702 sure not to ask for our own suicide. Of course the media
703 driver itself ought to make sure not to flood the buffer
704 accidentally. This however is not possible at the moment,
705 look at the signature of the media_stream_meth to get the
708 if (UNLIKELY(tmplen > 4 * aj->buffer_alloc_size / 5)) {
709 tmplen = 4 * aj->buffer_alloc_size / 5;
711 tmplen /= aj->framesize;
712 tmpbuf = (sxe_media_sample_t*)aj->buffer;
713 PULSE_DEBUG_S("asking for %u frames, fetching %u instead "
715 length/aj->framesize, tmplen,
716 (long unsigned int)aj);
717 len = media_stream_meth(mss->up, read)(mss, aj->buffer, tmplen);
718 PULSE_DEBUG_S("reader sent %u frames down the pipe\n", len);
719 /* result `len' has number of frames */
725 /* coerce the stuff, tmplen is in samples */
726 tmplen = channels*len;
727 for (i = 0; i < spsd->coe_ch_cnt; i++) {
728 PULSE_DEBUG_COE("calling coerce "
729 "%lu on b:0x%lx l:%lu\n",
730 (long unsigned int)i,
731 (long unsigned int)tmpbuf,
732 (long unsigned int)tmplen);
733 tmplen = CALL_MEDIA_SAMPLE_EFFECT(
734 spsd->coe_chain, i, tmpbuf, tmpbuf, tmplen);
737 MEDIA_SAMPLE_FORMAT_DOWNSAMPLE(spsd->msf)(
738 aj->buffer, aj->buffer, tmplen);
740 tmplen = tmplen * sizeof(int16_t);
744 #if !defined EF_USE_ASYNEQ
745 /* fill buffer with zeros */
746 tmplen = (len = length) * channels * sizeof(int16_t);
747 memset(aj->buffer, 0, tmplen);
751 case MTPSTATE_UNKNOWN:
752 case NUMBER_OF_MEDIA_THREAD_PLAY_STATES:
755 PULSE_DEBUG_S("MTPSTATE == STOP, "
756 "hence leaving stream_write cb\n");
757 SXE_MUTEX_UNLOCK(&aj->mtx);
761 if (LIKELY(len > 0)) {
762 PULSE_DEBUG_S("writing %u frames == %u samples == %u bytes "
764 tmplen/aj->framesize,
765 tmplen*aj->channels / aj->framesize,
767 (long unsigned int)aj);
768 pa_stream_write(stream, aj->buffer, tmplen,
769 my_pa_free_cb, 0, PA_SEEK_RELATIVE);
772 if (tmplen < length) {
773 PULSE_DEBUG_S("DRAIN. (0x%lx)\n", (long unsigned int)aj);
774 aj->play_state = MTPSTATE_STOP;
777 stream, stream_drain_complete, aj));
780 SXE_MUTEX_UNLOCK(&aj->mtx);
781 PULSE_DEBUG_S("leaving stream_write cb\n");
785 /* This routine is called whenever the stream state changes */
787 stream_state_callback(pa_stream *s, void *userdata)
789 sxe_semaphore_t sem = userdata;
790 pa_context_state_t st;
794 st = pa_stream_get_state(s);
795 switch ((unsigned int)st) {
796 case PA_STREAM_CREATING:
797 PULSE_DEBUG_S("CREATING.\n");
799 case PA_STREAM_TERMINATED:
800 PULSE_DEBUG_S("TERMINATED.\n");
801 PULSE_DEBUG_PT("trigger local semaphore\n");
802 SXE_SEMAPH_TRIGGER(sem);
805 case PA_STREAM_READY:
806 PULSE_DEBUG_S("READY.\n");
809 case PA_STREAM_FAILED:
811 PULSE_DEBUG_S("FAILED.\n");
812 PULSE_DEBUG_PT("trigger local semaphore\n");
813 SXE_SEMAPH_TRIGGER(sem);
821 sound_pulse_play(audio_job_t aj)
824 mtype_audio_properties *mtap;
825 Lisp_Media_Stream *ms;
826 media_substream *mss;
829 sound_pulse_data_t spd = NULL;
830 Lisp_Audio_Device *lad = NULL;
832 struct sound_pulse_aj_data_s _spsd, *spsd = &_spsd;
833 struct pa_sample_spec *ssp = &spsd->sampspec;
834 struct pa_channel_map *cmapp = &spsd->chanmap;
835 pa_buffer_attr *bap = &spsd->buffattr;
836 pa_stream *stream = NULL;
838 char *stream_name = NULL;
839 char *sink_name = NULL;
840 sxe_mse_rerate_args _rrargs, *rrargs = &_rrargs;
841 /* semaphore stuff */
842 struct sxe_semaphore_s _sem, *sem = &_sem;
844 int alloced_myself = 0;
846 /* unpack the media thread */
847 SOUND_UNPACK_MT(aj, device, ms, mss, lad, spd, mtap);
849 /* Set up a new main loop - if it's not already running */
850 if (!(r = spd->ml_running_p)) {
851 PULSE_DEBUG_ML("trying to restart main loop...\n");
852 r = sound_pulse_init_mainloop(spd);
853 PULSE_DEBUG_ML("result was: %d\n", r);
856 if (r == 0 || spd->ml_running_p == 0) {
857 warn_when_safe(Qpulse, Qerror,
858 GETTEXT("Failed to (re)connect to server."));
859 XAUDIO_DEVICE_STATE(device) = ASTATE_DEAD;
863 /* prepare pulse sample specs */
864 ssp->rate = mtap->samplerate;
865 ssp->channels = mtap->channels;
867 /* prepare pulse channel map and output format */
868 pa_channel_map_init_auto(cmapp, ssp->channels, PA_CHANNEL_MAP_ALSA);
869 ssp->format = PA_SAMPLE_S16NE;
871 if (spd->ml_running_p && spd->ml_threaded_p) {
872 PULSE_DEBUG_ML("lock.\n");
873 pa_threaded_mainloop_lock(spd->tml);
876 stream_name = (NILP(spd->stream) ? "SXEmacs stream" :
877 (char*)XSTRING_DATA(spd->stream));
878 sink_name = (NILP(spd->sink) ? NULL :
879 (char*)XSTRING_DATA(spd->sink));
881 /* create the stream */
882 PULSE_DEBUG_S("Creating stream...\n");
883 if (!spd->ml_running_p ||
884 !(stream = pa_stream_new(spd->ctx, stream_name, ssp, cmapp))) {
885 PULSE_CRITICAL("SXEmacs critical: [pulse] stream is NULL. "
886 "Mainloop not running?!\n");
889 PULSE_DEBUG_S("Created stream 0x%lx\n", (long unsigned int)stream);
891 /* obviously our device is alive
892 * This does NOT mean that you can hear the sounds */
893 XAUDIO_DEVICE_STATE(device) = ASTATE_ALIVE;
895 /* rewind the media substream */
896 media_stream_meth(ms, rewind)(mss);
897 SXE_MUTEX_LOCK(&aj->mtx);
898 if (aj->buffer_alloc_size == 0) {
899 PULSE_DEBUG_CACHE("worker buffer (sz:%ld) too small, "
900 "reallocate (sz:%ld)\n",
901 (long int)aj->buffer_alloc_size,
902 (long int)SOUND_MAX_AUDIO_FRAME_SIZE);
904 aj->buffer = xmalloc_atomic(SOUND_MAX_AUDIO_FRAME_SIZE);
905 aj->buffer_alloc_size = SOUND_MAX_AUDIO_FRAME_SIZE;
907 aj->resolution = mtap->samplerate * mtap->channels;
908 aj->framesize = mtap->channels * sizeof(int16_t);
909 aj->channels = mtap->channels;
910 SXE_MUTEX_UNLOCK(&aj->mtx);
912 /* initialise buffer attributes */
913 bap->maxlength = mtap->samplerate * aj->framesize;
914 bap->tlength = 9 * bap->maxlength / 10;
915 bap->minreq = bap->tlength / 10;
916 bap->prebuf = bap->tlength / SOUND_MAX_SAMPLE_WIDTH;
917 bap->fragsize = bap->minreq;
919 pa_cvolume_set(&spsd->chanvol, ssp->channels,
920 ((pa_volume_t)aj->volume*PA_VOLUME_NORM)/
921 MEDIA_SAMPLE_VOLUME_NORM);
922 spsd->ctx = spd->ctx;
923 spsd->stream = stream;
924 spsd->time_ev = NULL;
925 audio_job_device_data(aj) = spsd;
927 /* initialise our thread semaphore */
928 PULSE_DEBUG_PT("init pulse local semaphore\n");
929 SXE_SEMAPH_INIT(sem);
932 spsd->msf = MEDIA_SAMPLE_FORMAT(sxe_msf_S16);
933 spsd->coe_ch_cnt = 0;
934 /* the rerate effect */
935 ADD_MEDIA_SAMPLE_EFFECT(
936 spsd->coe_chain, spsd->coe_ch_cnt,
937 MEDIA_SAMPLE_EFFECT(sxe_mse_rerate), rrargs);
938 rrargs->num_channels = mtap->channels;
939 rrargs->srcrate = rrargs->tgtrate = 1;
940 spsd->rrargs = rrargs;
942 PULSE_DEBUG_S("setting up stream.\n");
943 pa_stream_set_state_callback(stream, stream_state_callback, sem);
944 pa_stream_set_write_callback(stream, stream_write_callback, aj);
946 /* we better check if ml is still running */
947 if (!spd->ml_running_p)
949 pa_stream_connect_playback(
950 stream, sink_name, bap, 0, &spsd->chanvol, NULL);
952 if (spd->ml_running_p && spd->ml_threaded_p) {
953 WITH_SXE_SEMAPH_SYNCH(
955 PULSE_DEBUG_ML("unlock.\n");
956 pa_threaded_mainloop_unlock(spd->tml);
957 PULSE_DEBUG_MX("play.\n"););
958 PULSE_DEBUG_PT("ACK, shall finish.\n");
959 } else if (spd->ml_running_p) {
960 /* iterate by hand */
961 pa_stream_state_t state;
962 while (spd->ml_running_p) {
963 pa_mainloop_iterate(spd->ml, 1, NULL);
964 state = pa_stream_get_state(stream);
965 if (!(state == PA_STREAM_READY ||
966 state == PA_STREAM_CREATING)) {
972 /* ... and outta here */
973 PULSE_DEBUG_S("finish.\n");
975 /* close and shutdown */
977 SXE_MUTEX_LOCK(&aj->mtx);
978 if (alloced_myself && aj->buffer) {
979 PULSE_DEBUG_S("freeing stream buffer.\n");
983 aj->buffer_alloc_size = 0;
985 /* device data could be finished already, hence we refetch it */
986 spd = get_audio_device_data(aj->device);
987 SXE_MUTEX_UNLOCK(&aj->mtx);
989 if (spd && spd->ml_running_p && spd->ml_threaded_p) {
990 PULSE_DEBUG_ML("lock.\n");
991 pa_threaded_mainloop_lock(spd->tml);
995 /* kick those timers */
996 if (spsd->time_ev != NULL) {
997 spd->mlapi->time_free(spsd->time_ev);
999 spsd->time_ev = NULL;
1004 PULSE_DEBUG_S("unref.\n");
1005 pa_stream_unref(stream);
1010 if (spd && spd->ml_running_p && spd->ml_threaded_p) {
1011 PULSE_DEBUG_ML("unlock.\n");
1012 pa_threaded_mainloop_unlock(spd->tml);
1015 SXE_MUTEX_LOCK(&aj->mtx);
1016 audio_job_device_data(aj) = NULL;
1017 SXE_MUTEX_UNLOCK(&aj->mtx);
1019 /* finish the pulse device data if pulse is not running anymore */
1020 if (spd && !spd->ml_running_p) {
1021 SXE_MUTEX_LOCK(&aj->mtx);
1022 XAUDIO_DEVICE_STATE(aj->device) = ASTATE_DEAD;
1023 SXE_MUTEX_UNLOCK(&aj->mtx);
1024 sound_pulse_finish(spd);
1028 /* deinitialise our thread semaphore */
1029 PULSE_DEBUG_PT("deinit pulse local semaphore\n");
1030 SXE_SEMAPH_FINI(sem);
1036 #define CHECK_DEAD_GOTO(label) \
1039 pa_context_get_state(spd->ctx) != PA_CONTEXT_READY) { \
1040 PULSE_CRITICAL("Uh oh, operation failed.\n"); \
1046 sink_info_callback(pa_context *c, const pa_sink_info *i, int eol, void *data)
1048 sound_pulse_data_t spd = data;
1051 PULSE_DEBUG_CTX("No sink info\n");
1052 spd->sink_info = NULL;
1053 } else if (i == NULL) {
1056 PULSE_DEBUG_CTX("Name: %s, Index: %d\nDescr: %s\n",
1057 i->name, i->index, i->description);
1058 spd->sink_info = NULL;
1064 /* This is called whenever the context status changes */
1066 context_state_callback(pa_context *c, void *userdata)
1068 sound_pulse_data_t spd = userdata;
1070 char *sink_name = NULL;
1074 switch (pa_context_get_state(c)) {
1075 case PA_CONTEXT_UNCONNECTED:
1076 case PA_CONTEXT_CONNECTING:
1077 case PA_CONTEXT_AUTHORIZING:
1078 case PA_CONTEXT_SETTING_NAME:
1079 PULSE_DEBUG_CTX("CONN/AUTH.\n");
1080 spd->ml_running_p = 0;
1083 case PA_CONTEXT_READY:
1084 PULSE_DEBUG_CTX("ESTA.\n");
1085 sink_name = (NILP(spd->sink) ? NULL :
1086 (char*)XSTRING_DATA(spd->sink));
1089 if (!(o = pa_context_get_sink_info_by_name(
1090 spd->ctx, sink_name,
1091 sink_info_callback, spd))) {
1092 PULSE_DEBUG_CTX("Hm, no sink info ... what now?\n");
1097 pa_operation_unref(o);
1098 spd->ml_running_p = 1;
1099 pa_threaded_mainloop_signal(spd->tml, 0);
1102 case PA_CONTEXT_TERMINATED:
1103 PULSE_DEBUG_CTX("DEAD.\n");
1104 spd->ml_running_p = 0;
1105 pa_threaded_mainloop_signal(spd->tml, 0);
1108 case PA_CONTEXT_FAILED:
1110 PULSE_DEBUG_CTX("FAIL.\n");
1111 spd->ml_running_p = 0;
1112 PULSE_DEBUG_CTX("triggering semaphore.\n");
1113 pa_threaded_mainloop_signal(spd->tml, 0);
1119 /* mainloop in an extra thread API */
1121 sound_pulse_init_mainloop(ad_device_data *devdata)
1124 sound_pulse_data_t spd = (sound_pulse_data_t)devdata;
1125 /* some predeclarations to avoid ugly trigraphs */
1126 const char *client =
1127 (NILP(spd->client) ? "SXEmacs" :
1128 (const char*)XSTRING_DATA(spd->client));
1129 const char *server =
1130 (NILP(spd->server) ? NULL :
1131 (const char*)XSTRING_DATA(spd->server));
1133 (NILP(spd->role) ? "event" :
1134 (const char*)XSTRING_DATA(spd->role));
1135 int threadedp = spd->ml_threaded_p;
1137 /* cannot use Pulse on incomplete or corrupt audio devices */
1141 SXE_SEMAPH_INIT(&(spd->ctxsem));
1143 setenv("PULSE_PROP_media.role", role, 1);
1145 /* Set up a new main loop */
1147 spd->tml = pa_threaded_mainloop_new();
1149 spd->ml = pa_mainloop_new();
1151 if (!spd->tml && !spd->ml) {
1152 message(GETTEXT("audio-pulse: "
1153 "Failed to connect to server."));
1158 spd->mlapi = pa_threaded_mainloop_get_api(spd->tml);
1160 spd->mlapi = pa_mainloop_get_api(spd->ml);
1162 /* Create a new connection context */
1163 if (!(spd->ctx = pa_context_new(spd->mlapi, client))) {
1164 message(GETTEXT("audio-pulse: "
1165 "pa_context_new() failed."));
1171 /* initialise callback semaphore */
1173 spd->ml_running_p = 0;
1174 pa_context_set_state_callback(
1175 spd->ctx, context_state_callback, spd);
1177 /* Connect the context */
1178 if (pa_context_connect(spd->ctx, server, 0, NULL) < 0) {
1179 PULSE_DEBUG_ML("failed to connect to server\n");
1183 PULSE_DEBUG_ML("locking mainloop\n");
1184 pa_threaded_mainloop_lock(spd->tml);
1186 if (pa_threaded_mainloop_start(spd->tml) < 0) {
1187 PULSE_DEBUG_ML("failed to start mainloop\n");
1188 goto unlock_and_fail;
1191 /* Wait until the context is ready */
1192 pa_threaded_mainloop_wait(spd->tml);
1194 if (pa_context_get_state(spd->ctx) != PA_CONTEXT_READY) {
1195 PULSE_DEBUG_ML("failed to connect to server\n");
1196 goto unlock_and_fail;
1199 /* Connect the context */
1200 pa_context_connect(spd->ctx, server, 0, NULL);
1201 /* iterate manually */
1203 pa_context_state_t st;
1205 pa_mainloop_iterate(spd->ml, 1, NULL);
1206 st = pa_context_get_state(spd->ctx);
1208 switch ((unsigned int)st) {
1209 case PA_CONTEXT_CONNECTING:
1210 case PA_CONTEXT_AUTHORIZING:
1211 case PA_CONTEXT_SETTING_NAME:
1212 spd->ml_running_p = 0;
1215 case PA_CONTEXT_READY:
1216 PULSE_DEBUG_CTX("ESTA.\n");
1217 PULSE_DEBUG_CTX("READY.\n");
1218 return (spd->ml_running_p = 1);
1220 case PA_CONTEXT_TERMINATED:
1221 PULSE_DEBUG_CTX("DEAD.\n");
1222 return (spd->ml_running_p = 0);
1224 case PA_CONTEXT_FAILED:
1226 PULSE_DEBUG_CTX("FAIL.\n");
1227 return (spd->ml_running_p = 0);
1233 PULSE_DEBUG_ML("READY: %d.\n", spd->ml_running_p);
1236 if (threadedp && spd->tml) {
1237 pa_threaded_mainloop_unlock(spd->tml);
1240 /* indicate success */
1241 return spd->ml_running_p;
1244 /* DEFUN("pulse-get-sink-info-list", Fpulse_get_sink_info_list, 1, 1, 0, */
1249 /* sound-pulse.c ends here */