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