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(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 if ((ev = eq_noseeum_dequeue(audio_job_queue(aj))) == NULL) {
257 SXE_MUTEX_UNLOCK(&aj->mtx);
260 SXE_MUTEX_UNLOCK(&aj->mtx);
262 AO_DEBUG_AJ("Event 0x%lx\n", (long unsigned int)ev);
263 switch (audio_job_event_kind(ev)) {
264 case aj_change_state:
265 AO_DEBUG_AJ("change state event\n");
266 sound_ao_change_state(aj, &audio_job_event_args(ev));
268 case aj_change_volume:
269 AO_DEBUG_AJ("change volume event\n");
270 sound_ao_change_volume(aj, &audio_job_event_args(ev));
273 AO_DEBUG_AJ("change rate event\n");
274 sound_ao_change_rate(aj, &audio_job_event_args(ev));
277 case no_audio_job_event_kinds:
279 AO_CRITICAL("unknown event\n");
282 free_audio_job_event(ev);
284 #endif /* EF_USE_ASYNEQ */
286 sound_ao_play(audio_job_t aj)
289 Lisp_Media_Stream *ms;
290 media_substream *mss;
292 media_thread_play_state mtp;
295 Lisp_Audio_Device *lad = NULL;
296 sound_ao_data_t *saod = NULL;
298 ao_sample_format *format;
303 /* subthread stuff */
304 sound_ao_aj_data_t _sasd, *sasd = &_sasd;
305 sxe_mse_volume_args _volargs, *volargs = &_volargs;
306 sxe_mse_rerate_args _rrargs, *rrargs = &_rrargs;
308 int alloced_myself = 0;
310 SOUND_UNPACK_MT(aj, device, ms, mss, lad, saod, sasd->mtap);
312 /* setup for the driver */
313 driver = saod->driver_id;
315 options = saod->options;
317 /* setup format specs from audio props */
318 format->channels = sasd->mtap->channels;
319 format->rate = sasd->mtap->samplerate;
320 format->bits = 16; /* HARDCODED, was: mtap->samplewidth; */
321 format->byte_format = AO_FMT_LITTLE; /* hmpf */
323 /* open the driver */
324 sasd->dev = ao_open_live(driver, format, options);
325 if (sasd->dev == NULL) {
326 message(GETTEXT("audio: Unsupported device."));
327 XAUDIO_DEVICE_STATE(device) = ASTATE_DEAD;
331 /* fill the subthread data structure */
332 sasd->msf = MEDIA_SAMPLE_FORMAT(sxe_msf_S16);
333 sasd->framesize = sasd->mtap->channels * sizeof(int16_t);
334 sasd->coe_ch_cnt = 0;
335 audio_job_device_data(aj) = sasd;
337 /* the volume effect */
338 ADD_MEDIA_SAMPLE_EFFECT(
339 sasd->coe_chain, sasd->coe_ch_cnt,
340 MEDIA_SAMPLE_EFFECT(sxe_mse_volume), volargs);
341 volargs->num_channels = sasd->mtap->channels;
342 sasd->volargs = volargs;
344 /* the rerate effect */
345 ADD_MEDIA_SAMPLE_EFFECT(
346 sasd->coe_chain, sasd->coe_ch_cnt,
347 MEDIA_SAMPLE_EFFECT(sxe_mse_rerate), rrargs);
348 rrargs->num_channels = sasd->mtap->channels;
349 rrargs->srcrate = rrargs->tgtrate = 1;
350 sasd->rrargs = rrargs;
353 media_stream_meth(ms, rewind)(mss);
355 XAUDIO_DEVICE_STATE(device) = ASTATE_ALIVE;
357 /* ... and play it */
358 SXE_MUTEX_LOCK(&aj->mtx);
359 mtp = aj->play_state;
360 if (aj->buffer_alloc_size < SOUND_MAX_AUDIO_FRAME_SIZE) {
362 aj->buffer = xmalloc_atomic(SOUND_MAX_AUDIO_FRAME_SIZE);
363 aj->buffer_alloc_size = SOUND_MAX_AUDIO_FRAME_SIZE;
365 SXE_MUTEX_UNLOCK(&aj->mtx);
366 resolution = (sasd->mtap->samplerate * MTPSTATE_REACT_TIME) / 1000000;
368 while (mtp != MTPSTATE_STOP) {
371 /* events are there? */
372 if (audio_job_queue(aj)) {
373 sound_ao_handle_aj_events(aj);
377 SXE_MUTEX_LOCK(&aj->mtx);
378 switch (aj->play_state) {
380 if (!ao_push(aj, resolution))
381 aj->play_state = MTPSTATE_STOP;
384 /* must sleep resolution outside of lock */
386 case MTPSTATE_UNKNOWN:
388 case NUMBER_OF_MEDIA_THREAD_PLAY_STATES:
390 AO_DEBUG("ACK, quit\n");
391 aj->play_state = MTPSTATE_STOP;
394 mtp = aj->play_state;
395 SXE_MUTEX_UNLOCK(&aj->mtx);
396 if (mtp == MTPSTATE_PAUSE) {
397 AO_DEBUG("sleeping for %d\n", resolution);
403 /* -- Close and shutdown -- */
404 SXE_MUTEX_LOCK(&aj->mtx);
405 if (alloced_myself && aj->buffer) {
409 aj->buffer_alloc_size = 0;
410 SXE_MUTEX_UNLOCK(&aj->mtx);
412 /* sasd is always != NULL here per its initialization */
424 /* sound-ao.c ends here */