1 /* sound-ao.c - play a sound over the libao devices
3 Copyright (C) 2006 Sebastian Freundt
5 This file is part of SXEmacs
7 SXEmacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 SXEmacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 /* Synched up with: Not in FSF. */
40 #define MYSELF ADRIVER_AO
42 #define __AO_DEBUG__(args...) fprintf(stderr, "AO " args)
44 #define AO_DEBUG(args...)
46 #define AO_DEBUG(args...) __AO_DEBUG__(args)
48 #define AO_DEBUG_C(args...) AO_DEBUG("[connection]: " args)
49 #define AO_DEBUG_S(args...) AO_DEBUG("[stream]: " args)
50 #define AO_DEBUG_COE(args...) AO_DEBUG("[coerce]: " args)
51 #define AO_DEBUG_AJ(args...) AO_DEBUG("[audio-job]: " args)
52 #define AO_CRITICAL(args...) __AO_DEBUG__("CRITICAL: " args)
55 DECLARE_AUDIO_DEVICE_SIMPLE_METHS(sound_ao);
56 DEFINE_AUDIO_DEVICE_SIMPLE(sound_ao);
60 sound_ao_mark(ad_device_data *devdata)
66 sound_ao_print(Lisp_Object device, Lisp_Object pcfun, int ef)
68 sound_ao_data_t *saod = NULL;
70 saod = get_audio_device_data(device);
71 /* cannot use AO on incomplete or corrupt audio devices */
72 if (XAUDIO_DEVICE_DRIVER(device) != MYSELF || saod == NULL) {
73 write_c_string("VOID", pcfun);
74 /* now that we are here, mark AO device as dead */
75 XAUDIO_DEVICE_STATE(device) = ASTATE_DEAD;
79 /* info about the connected output plugin */
80 write_c_string(" :driver \"", pcfun);
81 write_c_string(ao_driver_info(saod->driver_id)->short_name, pcfun);
82 write_c_string("\"", pcfun);
88 static ad_device_data *
89 sound_ao_create(Lisp_Object ao_options)
94 ao_sample_format *fmt;
98 Lisp_Object opt_driver;
99 char *optext_driver = NULL;
102 opt_driver = Fplist_get(ao_options, intern(":driver"), Qnil);
103 if (!NILP(opt_driver) && !STRINGP(opt_driver)) {
104 wrong_type_argument(Qstringp, opt_driver);
106 } else if (STRINGP(opt_driver))
107 optext_driver = (char*)XSTRING_DATA(opt_driver);
109 /* -- initialise -- */
111 fmt = xmalloc_and_zero(sizeof(ao_sample_format));
113 /* -- Setup for driver -- */
114 if (optext_driver != NULL)
115 driver = ao_driver_id(optext_driver);
117 driver = ao_default_driver_id();
119 /* just some generics */
123 fmt->byte_format = AO_FMT_LITTLE;
127 /* -- Open driver -- */
128 device = ao_open_live(driver, fmt, options);
129 if (device == NULL) {
130 message(GETTEXT("audio-ao: Unsupported driver."));
134 aod = xnew_and_zero(sound_ao_data_t);
139 aod->driver_id = driver;
146 sound_ao_finish(ad_device_data *data)
148 sound_ao_data_t *ao_dev = data;
149 if (ao_dev != NULL) {
150 ao_close(ao_dev->ad);
159 ao_push(audio_job_t aj, int nframes)
161 size_t len = 0, tmplen = 0;
162 sxe_media_sample_t *tmpbuf;
163 sound_ao_aj_data_t *sasd = audio_job_device_data(aj);
166 tmpbuf = (sxe_media_sample_t*)(aj->buffer);
167 len = media_stream_meth(aj->substream->up, read)(
168 aj->substream, aj->buffer, nframes);
170 /* set up the volume args */
171 sasd->volargs->volume[0] = sasd->volargs->volume[1] = aj->volume;
172 /* set up the rerate args */
173 sasd->rrargs->tweak = aj->ratetrafo;
175 /* coerce the stuff */
176 tmplen = sasd->mtap->channels*len;
177 for (i = 0; i < sasd->coe_ch_cnt; i++) {
178 AO_DEBUG_COE("calling coerce "
179 "%d on b:0x%x l:%d\n",
180 i, (unsigned int)tmpbuf, tmplen);
181 tmplen = CALL_MEDIA_SAMPLE_EFFECT(
182 sasd->coe_chain, i, tmpbuf, tmpbuf, tmplen);
184 /* bring back to S16 or U8 */
185 MEDIA_SAMPLE_FORMAT_DOWNSAMPLE(sasd->msf)(
186 aj->buffer, aj->buffer, tmplen);
188 ao_play(sasd->dev, aj->buffer,
189 tmplen * sasd->framesize / sasd->mtap->channels);
197 sound_ao_change_volume(audio_job_t aj, audio_job_event_args_t args)
199 SXE_MUTEX_LOCK(&aj->mtx);
200 aj->volume = args->volume_args;
201 SXE_MUTEX_UNLOCK(&aj->mtx);
205 sound_ao_change_rate(audio_job_t aj, audio_job_event_args_t args)
207 SXE_MUTEX_LOCK(&aj->mtx);
208 aj->ratetrafo = args->rate_args;
209 SXE_MUTEX_UNLOCK(&aj->mtx);
213 sound_ao_change_state(audio_job_t aj, audio_job_event_args_t args)
215 SXE_MUTEX_LOCK(&aj->mtx);
216 switch (args->state_args) {
218 AO_DEBUG_AJ("->pause state\n");
219 aj->play_state = MTPSTATE_PAUSE;
222 AO_DEBUG_AJ("->resume state\n");
223 aj->play_state = MTPSTATE_RUN;
226 AO_DEBUG_AJ("->start state\n");
229 AO_DEBUG_AJ("->stop state\n");
230 aj->play_state = MTPSTATE_STOP;
233 case no_audio_job_change_states:
235 AO_DEBUG_AJ("->unknown state\n");
238 SXE_MUTEX_UNLOCK(&aj->mtx);
242 sound_ao_handle_aj_events(audio_job_t aj)
243 __attribute__((always_inline));
245 sound_ao_handle_aj_events(audio_job_t aj)
247 sound_ao_aj_data_t *sasd;
248 audio_job_event_t ev = NULL;
251 assert(audio_job_queue(aj));
254 SXE_MUTEX_LOCK(&aj->mtx);
255 sasd = audio_job_device_data(aj);
256 SXE_SET_UNUSED(sasd);
258 if ((ev = eq_noseeum_dequeue(audio_job_queue(aj))) == NULL) {
259 SXE_MUTEX_UNLOCK(&aj->mtx);
262 SXE_MUTEX_UNLOCK(&aj->mtx);
264 AO_DEBUG_AJ("Event 0x%lx\n", (long unsigned int)ev);
265 switch (audio_job_event_kind(ev)) {
266 case aj_change_state:
267 AO_DEBUG_AJ("change state event\n");
268 sound_ao_change_state(aj, &audio_job_event_args(ev));
270 case aj_change_volume:
271 AO_DEBUG_AJ("change volume event\n");
272 sound_ao_change_volume(aj, &audio_job_event_args(ev));
275 AO_DEBUG_AJ("change rate event\n");
276 sound_ao_change_rate(aj, &audio_job_event_args(ev));
279 case no_audio_job_event_kinds:
281 AO_CRITICAL("unknown event\n");
284 free_audio_job_event(ev);
286 #endif /* EF_USE_ASYNEQ */
288 sound_ao_play(audio_job_t aj)
291 Lisp_Media_Stream *ms;
292 media_substream *mss;
294 media_thread_play_state mtp;
297 Lisp_Audio_Device *lad = NULL;
298 sound_ao_data_t *saod = NULL;
300 ao_sample_format *format;
305 /* subthread stuff */
306 sound_ao_aj_data_t _sasd, *sasd = &_sasd;
307 sxe_mse_volume_args _volargs, *volargs = &_volargs;
308 sxe_mse_rerate_args _rrargs, *rrargs = &_rrargs;
310 int alloced_myself = 0;
312 SOUND_UNPACK_MT(aj, device, ms, mss, lad, saod, sasd->mtap);
314 /* setup for the driver */
315 driver = saod->driver_id;
317 options = saod->options;
319 /* setup format specs from audio props */
320 format->channels = sasd->mtap->channels;
321 format->rate = sasd->mtap->samplerate;
322 format->bits = 16; /* HARDCODED, was: mtap->samplewidth; */
323 format->byte_format = AO_FMT_LITTLE; /* hmpf */
325 /* open the driver */
326 sasd->dev = ao_open_live(driver, format, options);
327 if (sasd->dev == NULL) {
328 message(GETTEXT("audio: Unsupported device."));
329 XAUDIO_DEVICE_STATE(device) = ASTATE_DEAD;
333 /* fill the subthread data structure */
334 sasd->msf = MEDIA_SAMPLE_FORMAT(sxe_msf_S16);
335 sasd->framesize = sasd->mtap->channels * sizeof(int16_t);
336 sasd->coe_ch_cnt = 0;
337 audio_job_device_data(aj) = sasd;
339 /* the volume effect */
340 ADD_MEDIA_SAMPLE_EFFECT(
341 sasd->coe_chain, sasd->coe_ch_cnt,
342 MEDIA_SAMPLE_EFFECT(sxe_mse_volume), volargs);
343 volargs->num_channels = sasd->mtap->channels;
344 sasd->volargs = volargs;
346 /* the rerate effect */
347 ADD_MEDIA_SAMPLE_EFFECT(
348 sasd->coe_chain, sasd->coe_ch_cnt,
349 MEDIA_SAMPLE_EFFECT(sxe_mse_rerate), rrargs);
350 rrargs->num_channels = sasd->mtap->channels;
351 rrargs->srcrate = rrargs->tgtrate = 1;
352 sasd->rrargs = rrargs;
355 media_stream_meth(ms, rewind)(mss);
357 XAUDIO_DEVICE_STATE(device) = ASTATE_ALIVE;
359 /* ... and play it */
360 SXE_MUTEX_LOCK(&aj->mtx);
361 mtp = aj->play_state;
362 if (aj->buffer_alloc_size < SOUND_MAX_AUDIO_FRAME_SIZE) {
364 aj->buffer = xmalloc_atomic(SOUND_MAX_AUDIO_FRAME_SIZE);
365 aj->buffer_alloc_size = SOUND_MAX_AUDIO_FRAME_SIZE;
367 SXE_MUTEX_UNLOCK(&aj->mtx);
368 resolution = (sasd->mtap->samplerate * MTPSTATE_REACT_TIME) / 1000000;
370 while (mtp != MTPSTATE_STOP) {
373 /* events are there? */
374 if (audio_job_queue(aj)) {
375 sound_ao_handle_aj_events(aj);
379 SXE_MUTEX_LOCK(&aj->mtx);
380 switch (aj->play_state) {
382 if (!ao_push(aj, resolution))
383 aj->play_state = MTPSTATE_STOP;
386 /* must sleep resolution outside of lock */
388 case MTPSTATE_UNKNOWN:
390 case NUMBER_OF_MEDIA_THREAD_PLAY_STATES:
392 AO_DEBUG("ACK, quit\n");
393 aj->play_state = MTPSTATE_STOP;
396 mtp = aj->play_state;
397 SXE_MUTEX_UNLOCK(&aj->mtx);
398 if (mtp == MTPSTATE_PAUSE) {
399 AO_DEBUG("sleeping for %d\n", resolution);
405 /* -- Close and shutdown -- */
406 SXE_MUTEX_LOCK(&aj->mtx);
407 if (alloced_myself && aj->buffer) {
411 aj->buffer_alloc_size = 0;
412 SXE_MUTEX_UNLOCK(&aj->mtx);
414 /* sasd is always != NULL here per its initialization */
426 /* sound-ao.c ends here */