545de381fcb54c7f2c8b240d05bb41f4494a996a
[sxemacs] / src / media / sound.h
1 /* New Generation Sound Functions.
2    Copyright (C) 2006 Sebastian Freundt
3
4 This file is part of SXEmacs
5
6 SXEmacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 SXEmacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
18
19
20 /* Synched up with: Not in FSF. */
21
22 #ifndef INCLUDED_sound_h_
23 #define INCLUDED_sound_h_
24
25 #include "media.h"
26 #include "semaphore.h"
27 #ifdef EF_USE_ASYNEQ
28 #include "events/event-queue.h"
29 #endif
30
31 extern Lisp_Object Q_device, Q_keep_open, Q_server, Q_client;
32
33 \f
34 typedef enum audio_drivers audio_driver;
35 typedef enum audio_states audio_state;
36 typedef enum media_thread_states media_thread_state;
37 typedef enum media_thread_play_states media_thread_play_state;
38 typedef struct ad_meths ad_meths;
39 typedef struct Lisp_Audio_Device Lisp_Audio_Device;
40
41 typedef enum media_thread_states media_thread_state_t;
42 typedef enum media_thread_play_states media_thread_play_state_t;
43 typedef struct audio_job_s *audio_job_t;
44
45 typedef void ad_device_data;
46 typedef ad_device_data*(*ad_create_fun)(Lisp_Object options);
47 typedef void(*ad_finish_fun)(ad_device_data*);
48 typedef void(*ad_print_fun)(Lisp_Object device, Lisp_Object, int);
49 typedef Lisp_Object(*ad_mark_fun)(ad_device_data *device_data);
50 typedef int(*ad_play_fun)(audio_job_t);
51 typedef int(*ad_record_fun)(audio_job_t);
52
53 \f
54 enum audio_drivers {
55         ADRIVER_UNKNOWN,
56         ADRIVER_OSS,
57         ADRIVER_NAS,
58         ADRIVER_ESD,
59         ADRIVER_POLYP,
60         ADRIVER_PULSE,
61         ADRIVER_ARTS,
62         ADRIVER_JACK,
63         ADRIVER_ALSA,
64         ADRIVER_AO,
65         NUMBER_OF_AUDIO_DRIVERS
66 };
67
68 enum audio_states {
69         ASTATE_UNKNOWN,
70         ASTATE_ALIVE,
71         ASTATE_SUSPENDED,
72         ASTATE_DEAD,
73         NUMBER_OF_AUDIO_STATES
74 };
75
76 \f
77 #ifdef ALL_DEBUG_FLAGS
78 #undef SOUND_DEBUG_FLAG
79 #define SOUND_DEBUG_FLAG
80 #endif
81
82 #define __SOUND_DEBUG__(args...)        fprintf(stderr, "SOUND " args)
83 #ifndef SOUND_DEBUG_FLAG
84 #define SOUND_DEBUG(args...)
85 #else
86 #define SOUND_DEBUG(args...)            __SOUND_DEBUG__(args)
87 #endif
88 #define SOUND_DEBUG_DEV(args...)        SOUND_DEBUG("[audio-device]: " args)
89 #define SOUND_DEBUG_MT(args...)         SOUND_DEBUG("[media-thread]: " args)
90 #define SOUND_DEBUG_MW(args...)         SOUND_DEBUG("[media-workers]: " args)
91 #define SOUND_DEBUG_MW_ENQ(args...)             \
92         SOUND_DEBUG_MW("[enqueue]: st:0x%x, " args)
93 #define SOUND_DEBUG_MW_DEQ(args...)             \
94         SOUND_DEBUG_MW("[dequeue]: st:0x%x, " args)
95 #define SOUND_DEBUG_PT(args...)         SOUND_DEBUG("[pthread]: " args)
96 #define SOUND_DEBUG_AJ(args...)         SOUND_DEBUG("[audio-job]: " args)
97 #define SOUND_CRITICAL(args...)         __SOUND_DEBUG__("CRITICAL: " args)
98
99 /* now device driver dependent stuff */
100 struct ad_meths {
101         ad_create_fun create;
102         ad_finish_fun finish;
103         ad_print_fun print;
104         ad_mark_fun mark;
105         ad_play_fun play;
106         ad_record_fun record;
107 };
108
109 extern Lisp_Object Vdefault_audio_device;
110
111 struct Lisp_Audio_Device {
112         struct lcrecord_header lheader;
113         audio_driver driver;
114         audio_state state;
115         const ad_meths *meths;
116         ad_device_data *device_data;
117         pthread_mutex_t device_data_mtx;
118 };
119
120 DECLARE_LRECORD(audio_device, Lisp_Audio_Device);
121 #define XAUDIO_DEVICE(x) XRECORD(x, audio_device, Lisp_Audio_Device)
122 #define XSETAUDIO_DEVICE(x, p) XSETRECORD(x, p, audio_device)
123 #define wrap_audio_device(p) wrap_object(p)
124 #define AUDIO_DEVICEP(x) RECORDP(x, audio_device)
125 #define CHECK_AUDIO_DEVICE(x) CHECK_RECORD(x, audio_device)
126 #define CONCHECK_AUDIO_DEVICE(x) CONCHECK_RECORD(x, audio_device)
127
128 #define audio_device_driver(ad) ((ad)->driver)
129 #define audio_device_state(ad) ((ad)->state)
130 #define audio_device_data(ad) ((ad)->device_data)
131 #define audio_device_set_meths(_ad, _m) ((_ad)->meths = _m)
132 #define audio_device_meths(_ad) ((_ad)->meths)
133 #define audio_device_meth(_ad, _m) (audio_device_meths(_ad)->_m)
134 #define XAUDIO_DEVICE_DRIVER(x) (audio_device_driver(XAUDIO_DEVICE(x)))
135 #define XAUDIO_DEVICE_STATE(x) (audio_device_state(XAUDIO_DEVICE(x)))
136 #define XAUDIO_DEVICE_DATA(x) (audio_device_data(XAUDIO_DEVICE(x)))
137 #define XAUDIO_DEVICE_SET_METHS(_d, _m) (audio_device_set_meths(_d, _m))
138 #define XAUDIO_DEVICE_METHS(_d) (audio_device_meths(XAUDIO_DEVICE(_d)))
139 #define XAUDIO_DEVICE_METH(_d, _m) (audio_device_meth(XAUDIO_DEVICE(_d), _m))
140
141 extern audio_driver decode_audio_type(Lisp_Object);
142 extern audio_driver decode_audio_device(Lisp_Object);
143 extern void *get_audio_device_data(Lisp_Object);
144 extern Lisp_Audio_Device *get_audio_device(Lisp_Object);
145
146 EXFUN(Fmake_audio_device, MANY);
147 EXFUN(Faudio_device_p, 1);
148 #if 0
149 EXFUN(Fdelete_audio_device, 1); /* too dangerous at the moment */
150 #endif
151
152 #define DECLARE_AUDIO_DEVICE(_name)                                     \
153         extern ad_meths _name[1]
154 #define DECLARE_AUDIO_DEVICE_SIMPLE_METHS(_name)                        \
155         static ad_device_data *_name##_create(Lisp_Object);             \
156         static void _name##_finish(ad_device_data*);                    \
157         static void _name##_print(Lisp_Object, Lisp_Object, int);       \
158         static Lisp_Object _name##_mark(ad_device_data*);               \
159         static int _name##_play(audio_job_t);                           \
160         static int _name##_record(audio_job_t);                         \
161         /* we currently have no record support so define a nop here */  \
162         static int                                                      \
163         _name##_record(audio_job_t SXE_UNUSED(foo))                     \
164         {                                                               \
165                 return 0;                                               \
166         }
167
168 #define DEFINE_AUDIO_DEVICE_CUSTOM(_na, _cr, _fi, _pr, _ma, _pl, _re)   \
169         ad_meths _na[1] = { { (_cr), (_fi), (_pr), (_ma), (_pl), (_re) } }
170 #define DEFINE_AUDIO_DEVICE(_name, _crea, _fini, _prin, _mark, _play, _reco) \
171         DEFINE_AUDIO_DEVICE_CUSTOM((_name),                             \
172                                    (_name##_##_crea),                   \
173                                    (_name##_##_fini),                   \
174                                    (_name##_##_prin),                   \
175                                    (_name##_##_mark),                   \
176                                    (_name##_##_play),                   \
177                                    (_name##_##_reco))
178 #define DEFINE_AUDIO_DEVICE_SIMPLE(_name)                               \
179         DEFINE_AUDIO_DEVICE(_name,                                      \
180                             create, finish, print, mark, play, record)
181 #define DEFINE_AUDIO_DEVICE_EMPTY(_name)                                \
182         DEFINE_AUDIO_DEVICE_CUSTOM((_name),                             \
183                                    NULL, NULL, NULL, NULL, NULL, NULL)
184 #define DEFINE_AUDIO_DEVICE_EMPTY_BUT_PLAY(_name, _play)                \
185         DEFINE_AUDIO_DEVICE_CUSTOM((_name),                             \
186                                    NULL, NULL, NULL, NULL, (_play), NULL)
187 #define SET_AUDIO_DEVICE_FUNCTION_CUSTOM(_device, _slot, _function)     \
188         (_device->_slot = _function)
189 #define SET_AUDIO_DEVICE_FUNCTION(_device, _function)                   \
190         SET_AUDIO_DEVICE_FUNCTION_CUSTOM(_device,                       \
191                                          _function,                     \
192                                          _device##_##_function)
193
194 \f
195 /* maximal number of channels, 8ch should be okay */
196 #define SOUND_MAX_CHANNELS      8
197 /* maximal sample width */
198 #define SOUND_MAX_SAMPLE_WIDTH  sizeof(uint32_t)
199 /* maximal sampling frequency, could be 96 kHz though */
200 #define SOUND_MAX_SAMPLE_FREQ   48000
201 /* 1 sec of sound at extreme values */
202 #define SOUND_MAX_AUDIO_FRAME_SIZE              \
203         SOUND_MAX_SAMPLE_FREQ * SOUND_MAX_SAMPLE_WIDTH * SOUND_MAX_CHANNELS
204
205 /*
206  * Threads are the containers for the streams. Streams are stored
207  * (along with devices) inside threads, while substreams are stored inside
208  * subthreads. In source/sink language, a thread is the cable to plug a source
209  * (stream) to a sink (device).
210  *
211  * This brings us to:
212  *
213  *                      up  +========+  up
214  *                  ,-----> | Thread | <-----,
215  *                 /        +--------+        \
216  *                /         | Stream |         \
217  *               /          | Device |          \
218  *              /           | State  |           \
219  *             /            | PState |            \
220  *            /             | Result |             \
221  *           /              +========+              \
222  *           |                   ^                  |
223  *     first |                   | up               | last
224  *           v                   |                  v
225  *    +==========+    next +==========+    next +==========+
226  *    |subthread1| <-----> |subthread2| <-----> |subthread3|
227  *    +----------+ prev    +----------+ prev    +----------+
228  *    |substream1|         |substream2|         |substream3|
229  *    |pthread_t1|         |pthread_t2|         |pthread_t3|
230  *    |privdata1 |         |privdata2 |         |privdata3 |
231  *    +==========+         +==========+         +==========+
232  *
233  * Note: It is yet _not_ possible to specify different devices for each
234  * subthread. This will require another split of the device structure into
235  * a device+subdevice tree.
236  */
237
238 /* some defs for the pthreaded version */
239
240 enum media_thread_states {
241         MTSTATE_UNKNOWN,
242         MTSTATE_RUNNING,
243         MTSTATE_FINISHED,
244         NUMBER_OF_MEDIA_THREAD_STATES
245 };
246
247 enum media_thread_play_states {
248         MTPSTATE_UNKNOWN,
249         MTPSTATE_RUN,
250         MTPSTATE_PAUSE,
251         MTPSTATE_STOP,
252         NUMBER_OF_MEDIA_THREAD_PLAY_STATES
253 };
254
255 struct audio_job_s {
256         /* data and handling info */
257         Lisp_Object stream;
258         Lisp_Object device;
259         media_substream *substream;
260
261         /* state information */
262         media_thread_state state;
263         media_thread_play_state play_state;
264 #if defined(HAVE_THREADS)
265         sxe_mutex_t mtx;
266 #endif
267 #if defined(EF_USE_ASYNEQ)
268         event_queue_t queue;
269 #endif
270
271         /* anonymous data, used by the various backends */
272         /* do not use it, it is not freed by gc */
273         void *job_device_data;
274         void *job_stream_data;
275
276         /* cache buffer */
277         char *buffer;
278         size_t buffer_alloc_size;
279
280         /* audio-specific job options */
281         int resolution;
282         int framesize;
283         int channels;
284         int volume;
285         uint8_t chanvol[MEDIA_MAX_AUDIO_CHANNELS];
286         float ratetrafo;
287
288         /* communication objects */
289         Lisp_Object result;
290         Lisp_Object sentinel;
291 };
292
293 #define MTPSTATE_REACT_TIME 20000       /* in usec */
294
295 enum sxe_finalise_conds {
296         SXE_SMPH_SHALL_START,
297         SXE_SMPH_HAVE_STARTED,
298         SXE_SMPH_SHALL_FINISH,
299         SXE_SMPH_HAVE_FINISHED
300 };
301
302 #define audio_job(_x)                   (((audio_job_t)worker_job_data(_x)))
303 #define audio_job_stream(_x)            (audio_job(_x)->stream)
304 #define audio_job_device(_x)            (audio_job(_x)->device)
305 #define audio_job_sentinel(_x)          (audio_job(_x)->sentinel)
306 #define audio_job_device_data(_aj)      (_aj)->job_device_data
307 #define audio_job_stream_data(_aj)      (_aj)->job_stream_data
308 #define audio_job_queue(_aj)            (_aj)->queue
309 #define XAUDIO_JOB(_x)                  ((audio_job_t)(XWORKER_JOB_DATA(_x)))
310 #define XAUDIO_JOB_STREAM(_x)           audio_job_stream(XWORKER_JOB(_x))
311 #define XAUDIO_JOB_DEVICE(_x)           audio_job_device(XWORKER_JOB(_x))
312 #define XAUDIO_JOB_SENTINEL(_x)         audio_job_sentinel(XWORKER_JOB(_x))
313 #define XAUDIO_JOB_QUEUE(_x)            (audio_job_queue(XAUDIO_JOB(_x)))
314 #define AUDIO_JOBP(_x)                                                  \
315         (WORKER_JOBP(_x) && XWORKER_JOB_HANDLER(_x) == &audio_job_handler)
316 #define CHECK_AUDIO_JOB(_x)                                             \
317         do {                                                            \
318                 if (!AUDIO_JOBP(_x))                                    \
319                         dead_wrong_type_argument(Qaudio_jobp, _x);      \
320         } while (0)
321 #define CONCHECK_AUDIO_JOB(_x)                                          \
322         do {                                                            \
323                 if (!AUDIO_JOBP(_x))                                    \
324                         return wrong_type_argument(Qaudio_jobp, _x);    \
325         } while (0)
326
327 #if 0
328 #define SXE_WORKERS_SMPH_INIT(_mt)                                      \
329         SOUND_DEBUG_MW("initialising state semaphore: 0x%x\n",          \
330                        (unsigned int)(_mt));                            \
331         SXE_MSEMAPH_INIT(&(_mt)->state_smph);
332 #define SXE_WORKERS_SMPH_FINI(_mt)                                      \
333         SOUND_DEBUG_MW("finishing state semaphore: 0x%x\n",             \
334                        (unsigned int)(_mt));                            \
335         SXE_MSEMAPH_FINI(&(_mt)->state_smph);
336 #define SXE_WORKERS_SMPH_LOCK(_mt)                                      \
337         SOUND_DEBUG_MW("locking mutex of state semaphore: 0x%x\n",      \
338                        (unsigned int)(_mt));                            \
339         SXE_MSEMAPH_LOCK(&(_mt)->state_smph);
340 #define SXE_WORKERS_SMPH_UNLOCK(_mt)                                    \
341         SOUND_DEBUG_MW("unlocking mutex of state semaphore: 0x%x\n",    \
342                        (unsigned int)(_mt));                            \
343         SXE_MSEMAPH_UNLOCK(&(_mt)->state_smph);
344
345 #define SXE_WORKERS_SMPH_SIGNAL(_mt, _state)                            \
346         SOUND_DEBUG_MW("signalling "#_state": 0x%x\n",                  \
347                        (unsigned int)(_mt));                            \
348         SXE_MSEMAPH_SIGNAL(&(_mt)->state_smph, _state);                 \
349         SOUND_DEBUG_MW("signalled "#_state": 0x%x\n",                   \
350                        (unsigned int)(_mt));
351 #define SXE_WORKERS_SMPH_BROADCAST(_mt, _state)                         \
352         SOUND_DEBUG_MW("broadcasting "#_state": 0x%x\n",                \
353                        (unsigned int)(_mt));                            \
354         SXE_MSEMAPH_BROADCAST(&(_mt)->state_smph, _state);              \
355         SOUND_DEBUG_MW("broadcast "#_state": 0x%x\n",                   \
356                        (unsigned int)(_mt));
357 #define SXE_WORKERS_SMPH_WAIT(_mt, _state)                              \
358         SOUND_DEBUG_MW("waiting for "#_state": 0x%x\n",                 \
359                        (unsigned int)(_mt));                            \
360         SXE_MSEMAPH_WAIT(&(_mt)->state_smph, _state);                   \
361         SOUND_DEBUG_MW("ACK, got "#_state": 0x%x\n",                    \
362                        (unsigned int)(_mt));
363
364 #define SXE_WORKERS_SMPH_SYNCH(_mt, _state)                             \
365         SOUND_DEBUG_MW("waiting for "#_state": 0x%x\n",                 \
366                        (unsigned int)(_mt));                            \
367         SXE_MSEMAPH_SYNCH(&(_mt)->state_smph, _state);                  \
368         SOUND_DEBUG_MW("ACK, got "#_state": 0x%x\n",                    \
369                        (unsigned int)(_mt));
370 #define WITH_SXE_WORKERS_SMPH_SYNCH(_mt, _state, args...)               \
371         SOUND_DEBUG_MW("waiting for "#_state": 0x%x\n",                 \
372                        (unsigned int)(_mt));                            \
373         WITH_SXE_MSEMAPH_SYNCH(&(_mt)->state_smph, _state, args);       \
374         SOUND_DEBUG_MW("ACK, got "#_state": 0x%x\n",                    \
375                        (unsigned int)(_mt));
376 #define SXE_WORKERS_SMPH_TRIGGER(_mt, _state)                           \
377         SOUND_DEBUG_MW("triggering "#_state": 0x%x\n",                  \
378                        (unsigned int)(_mt));                            \
379         SXE_MSEMAPH_TRIGGER(&(_mt)->state_smph, _state);                \
380         SOUND_DEBUG_MW("triggered "#_state": 0x%x\n",                   \
381                        (unsigned int)(_mt));
382 #define SXE_WORKERS_SMPH_TRIGGER_ALL(_mt, _state)                       \
383         SOUND_DEBUG_MW("triggering all "#_state": 0x%x\n",              \
384                        (unsigned int)(_mt));                            \
385         SXE_MSEMAPH_TRIGGER_ALL(&(_mt)->state_smph, _state);            \
386         SOUND_DEBUG_MW("triggered all "#_state": 0x%x\n",               \
387                        (unsigned int)(_mt));
388 #endif
389
390 /* convenience macros, dunno how sensible they are */
391 #define SOUND_UNPACK_MT(aj, dev, ms, mss, ad, cad, mtap)                \
392         /* unpack the media thread */                                   \
393         dev = (aj)->device;                                             \
394         ms = XMEDIA_STREAM((aj)->stream);                               \
395         mss = aj->substream;                                            \
396                                                                         \
397         /* unpack device */                                             \
398         ad = get_audio_device(dev);                                     \
399         cad = get_audio_device_data(dev);                               \
400                                                                         \
401         /* cannot use incomplete or corrupt audio devices */            \
402         if ((ad) == NULL || cad == NULL ||                              \
403             media_stream_meth((ms), rewind) == NULL ||                  \
404             media_stream_meth((ms), read) == NULL ||                    \
405             XAUDIO_DEVICE_DRIVER(dev) != MYSELF)                        \
406                 return 0;                                               \
407                                                                         \
408         /* cannot use most devices to play non-audio stuff */           \
409         if (media_substream_type(mss) != MTYPE_AUDIO)                   \
410                 return 0;                                               \
411         mtap = media_substream_type_properties(mss).aprops;
412
413 \f
414 #ifdef EF_USE_ASYNEQ
415 /* for the communication with (async'ly) running audio jobs */
416 typedef struct audio_job_event_s *audio_job_event_t;
417 typedef enum audio_job_event_kinds audio_job_event_kind_t;
418 typedef enum audio_job_change_states audio_job_change_state_t;
419 typedef int audio_job_change_volume_t;
420 typedef float audio_job_change_rate_t;
421 typedef union audio_job_event_args_u *audio_job_event_args_t;
422
423 enum audio_job_change_states {
424         aj_pause,
425         aj_resume,
426         aj_start,
427         aj_stop,
428         no_audio_job_change_states
429 };
430
431 union audio_job_event_args_u {
432         audio_job_change_state_t state_args;
433         audio_job_change_volume_t volume_args;
434         audio_job_change_rate_t rate_args;
435 };
436
437 enum audio_job_event_kinds {
438         aj_change_state,
439         aj_change_volume,
440         aj_change_rate,
441         no_audio_job_event_kinds
442 };
443
444 struct audio_job_event_s {
445         audio_job_event_kind_t kind;
446         union audio_job_event_args_u args;
447         int free_after_use;
448 };
449
450 #define audio_job_event_kind(_x)        ((_x)->kind)
451 #define audio_job_event_args(_x)        ((_x)->args)
452 #define audio_job_event_fau(_x)         ((_x)->free_after_use)
453
454 /* some often used events */
455 extern struct audio_job_event_s pause_event;
456 extern struct audio_job_event_s resume_event;
457 extern struct audio_job_event_s start_event;
458 extern struct audio_job_event_s stop_event;
459 extern struct audio_job_event_s change_volume_event;
460 extern struct audio_job_event_s change_rate_event;
461
462 extern_inline audio_job_event_t
463 make_audio_job_event(audio_job_event_kind_t kind);
464
465 extern_inline audio_job_event_t
466 make_audio_job_event(audio_job_event_kind_t kind)
467 {
468         audio_job_event_t aje = xnew(struct audio_job_event_s);
469         audio_job_event_kind(aje) = kind;
470         audio_job_event_fau(aje) = 1;
471         return aje;
472 }
473
474 static inline void
475 free_audio_job_event(audio_job_event_t aje)
476 {
477         if (audio_job_event_fau(aje)) {
478                 xfree(aje);
479         }
480         return;
481 }
482
483 #endif  /* EF_USE_ASYNEQ */
484
485 #endif  /* INCLUDED_sound_h_ */