This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_umsaudio.c
561 lines (495 loc) · 17.2 KB
1
/*
2
3
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga
4
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Lesser General Public
7
License as published by the Free Software Foundation; either
8
version 2.1 of the License, or (at your option) any later version.
9
10
11
12
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Lesser General Public License for more details.
14
15
16
17
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19
20
21
22
23
Carsten Griwodz
griff@kom.tu-darmstadt.de
based on linux/SDL_dspaudio.c by Sam Lantinga
*/
24
#include "SDL_config.h"
25
26
27
28
29
30
31
32
33
34
35
36
37
/* Allow access to a raw mixing buffer */
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "SDL_audio.h"
38
39
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
40
41
42
43
44
45
46
47
#include "SDL_umsaudio.h"
/* The tag name used by UMS audio */
#define UMS_DRIVER_NAME "ums"
#define DEBUG_AUDIO 1
/* Audio driver functions */
48
static int UMS_OpenAudio(_THIS, SDL_AudioSpec * spec);
49
50
51
52
static void UMS_PlayAudio(_THIS);
static Uint8 *UMS_GetAudioBuf(_THIS);
static void UMS_CloseAudio(_THIS);
53
54
static UMSAudioDevice_ReturnCode UADOpen(_THIS, string device, string mode,
long flags);
55
static UMSAudioDevice_ReturnCode UADClose(_THIS);
56
static UMSAudioDevice_ReturnCode UADGetBitsPerSample(_THIS, long *bits);
57
static UMSAudioDevice_ReturnCode UADSetBitsPerSample(_THIS, long bits);
58
59
static UMSAudioDevice_ReturnCode UADSetSampleRate(_THIS, long rate,
long *set_rate);
60
61
62
63
64
65
static UMSAudioDevice_ReturnCode UADSetByteOrder(_THIS, string byte_order);
static UMSAudioDevice_ReturnCode UADSetAudioFormatType(_THIS, string fmt);
static UMSAudioDevice_ReturnCode UADSetNumberFormat(_THIS, string fmt);
static UMSAudioDevice_ReturnCode UADInitialize(_THIS);
static UMSAudioDevice_ReturnCode UADStart(_THIS);
static UMSAudioDevice_ReturnCode UADStop(_THIS);
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
static UMSAudioDevice_ReturnCode UADSetTimeFormat(_THIS,
UMSAudioTypes_TimeFormat
fmt);
static UMSAudioDevice_ReturnCode UADWriteBuffSize(_THIS, long *buff_size);
static UMSAudioDevice_ReturnCode UADWriteBuffRemain(_THIS, long *buff_size);
static UMSAudioDevice_ReturnCode UADWriteBuffUsed(_THIS, long *buff_size);
static UMSAudioDevice_ReturnCode UADSetDMABufferSize(_THIS, long bytes,
long *bytes_ret);
static UMSAudioDevice_ReturnCode UADSetVolume(_THIS, long volume);
static UMSAudioDevice_ReturnCode UADSetBalance(_THIS, long balance);
static UMSAudioDevice_ReturnCode UADSetChannels(_THIS, long channels);
static UMSAudioDevice_ReturnCode UADPlayRemainingData(_THIS, boolean block);
static UMSAudioDevice_ReturnCode UADEnableOutput(_THIS, string output,
long *left_gain,
long *right_gain);
static UMSAudioDevice_ReturnCode UADWrite(_THIS, UMSAudioTypes_Buffer * buff,
long samples,
long *samples_written);
84
85
/* Audio driver bootstrap functions */
86
87
static int
Audio_Available(void)
88
89
90
91
{
return 1;
}
92
93
static void
Audio_DeleteDevice(_THIS)
94
{
95
96
97
98
99
if (this->hidden->playbuf._buffer)
SDL_free(this->hidden->playbuf._buffer);
if (this->hidden->fillbuf._buffer)
SDL_free(this->hidden->fillbuf._buffer);
_somFree(this->hidden->umsdev);
100
101
SDL_free(this->hidden);
SDL_free(this);
102
103
}
104
105
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
106
107
108
109
110
111
112
{
SDL_AudioDevice *this;
/*
* Allocate and initialize management storage and private management
* storage for this SDL-using library.
*/
113
114
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
115
SDL_memset(this, 0, (sizeof *this));
116
117
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
118
}
119
if ((this == NULL) || (this->hidden == NULL)) {
120
SDL_OutOfMemory();
121
if (this) {
122
SDL_free(this);
123
}
124
return (0);
125
}
126
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
127
128
129
130
131
132
133
#ifdef DEBUG_AUDIO
fprintf(stderr, "Creating UMS Audio device\n");
#endif
/*
* Calls for UMS env initialization and audio object construction.
*/
134
this->hidden->ev = somGetGlobalEnvironment();
135
136
137
138
139
this->hidden->umsdev = UMSAudioDeviceNew();
/*
* Set the function pointers.
*/
140
141
142
this->OpenAudio = UMS_OpenAudio;
this->WaitAudio = NULL; /* we do blocking output */
this->PlayAudio = UMS_PlayAudio;
143
this->GetAudioBuf = UMS_GetAudioBuf;
144
145
this->CloseAudio = UMS_CloseAudio;
this->free = Audio_DeleteDevice;
146
147
148
149
150
151
152
153
#ifdef DEBUG_AUDIO
fprintf(stderr, "done\n");
#endif
return this;
}
AudioBootStrap UMS_bootstrap = {
154
UMS_DRIVER_NAME, "AIX UMS audio",
155
Audio_Available, Audio_CreateDevice, 0
156
157
};
158
159
static Uint8 *
UMS_GetAudioBuf(_THIS)
160
161
162
163
164
165
166
167
168
169
170
171
172
173
{
#ifdef DEBUG_AUDIO
fprintf(stderr, "enter UMS_GetAudioBuf\n");
#endif
return this->hidden->fillbuf._buffer;
/*
long bufSize;
UMSAudioDevice_ReturnCode rc;
rc = UADSetTimeFormat(this, UMSAudioTypes_Bytes );
rc = UADWriteBuffSize(this, bufSize );
*/
}
174
175
static void
UMS_CloseAudio(_THIS)
176
177
178
179
180
181
182
183
184
185
186
{
UMSAudioDevice_ReturnCode rc;
#ifdef DEBUG_AUDIO
fprintf(stderr, "enter UMS_CloseAudio\n");
#endif
rc = UADPlayRemainingData(this, TRUE);
rc = UADStop(this);
rc = UADClose(this);
}
187
188
static void
UMS_PlayAudio(_THIS)
189
190
{
UMSAudioDevice_ReturnCode rc;
191
192
193
long samplesToWrite;
long samplesWritten;
UMSAudioTypes_Buffer swpbuf;
194
195
196
197
#ifdef DEBUG_AUDIO
fprintf(stderr, "enter UMS_PlayAudio\n");
#endif
198
199
200
201
202
203
204
205
206
207
208
209
210
211
samplesToWrite =
this->hidden->playbuf._length / this->hidden->bytesPerSample;
do {
rc = UADWrite(this, &this->hidden->playbuf,
samplesToWrite, &samplesWritten);
samplesToWrite -= samplesWritten;
/* rc values: UMSAudioDevice_Success
* UMSAudioDevice_Failure
* UMSAudioDevice_Preempted
* UMSAudioDevice_Interrupted
* UMSAudioDevice_DeviceError
*/
if (rc == UMSAudioDevice_DeviceError) {
212
#ifdef DEBUG_AUDIO
213
fprintf(stderr, "Returning from PlayAudio with devices error\n");
214
#endif
215
216
return;
}
217
}
218
while (samplesToWrite > 0);
219
220
SDL_LockAudio();
221
222
223
224
SDL_memcpy(&swpbuf, &this->hidden->playbuf, sizeof(UMSAudioTypes_Buffer));
SDL_memcpy(&this->hidden->playbuf, &this->hidden->fillbuf,
sizeof(UMSAudioTypes_Buffer));
SDL_memcpy(&this->hidden->fillbuf, &swpbuf, sizeof(UMSAudioTypes_Buffer));
225
226
227
228
229
230
231
232
SDL_UnlockAudio();
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote audio data and swapped buffer\n");
#endif
}
#if 0
233
234
235
236
237
238
239
// /* Set the DSP frequency */
// value = spec->freq;
// if ( ioctl(this->hidden->audio_fd, SOUND_PCM_WRITE_RATE, &value) < 0 ) {
// SDL_SetError("Couldn't set audio frequency");
// return(-1);
// }
// spec->freq = value;
240
241
#endif
242
243
static int
UMS_OpenAudio(_THIS, SDL_AudioSpec * spec)
244
{
245
246
247
248
249
250
251
252
char *audiodev = "/dev/paud0";
long lgain;
long rgain;
long outRate;
long outBufSize;
long bitsPerSample;
long samplesPerSec;
long success;
253
SDL_AudioFormat test_format;
254
int frag_spec;
255
256
257
258
259
UMSAudioDevice_ReturnCode rc;
#ifdef DEBUG_AUDIO
fprintf(stderr, "enter UMS_OpenAudio\n");
#endif
260
261
262
263
rc = UADOpen(this, audiodev, "PLAY", UMSAudioDevice_BlockingIO);
if (rc != UMSAudioDevice_Success) {
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
return -1;
264
}
265
266
rc = UADSetAudioFormatType(this, "PCM");
267
268
269
success = 0;
test_format = SDL_FirstAudioFormat(spec->format);
270
do {
271
272
273
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
#endif
274
switch (test_format) {
275
276
277
case AUDIO_U8:
/* from the mac code: better ? */
/* sample_bits = spec->size / spec->samples / spec->channels * 8; */
278
success = 1;
279
bitsPerSample = 8;
280
281
rc = UADSetSampleRate(this, spec->freq << 16, &outRate);
rc = UADSetByteOrder(this, "MSB"); /* irrelevant */
282
283
284
rc = UADSetNumberFormat(this, "UNSIGNED");
break;
case AUDIO_S8:
285
success = 1;
286
bitsPerSample = 8;
287
288
rc = UADSetSampleRate(this, spec->freq << 16, &outRate);
rc = UADSetByteOrder(this, "MSB"); /* irrelevant */
289
290
291
rc = UADSetNumberFormat(this, "SIGNED");
break;
case AUDIO_S16LSB:
292
success = 1;
293
bitsPerSample = 16;
294
rc = UADSetSampleRate(this, spec->freq << 16, &outRate);
295
296
297
298
rc = UADSetByteOrder(this, "LSB");
rc = UADSetNumberFormat(this, "SIGNED");
break;
case AUDIO_S16MSB:
299
success = 1;
300
bitsPerSample = 16;
301
rc = UADSetSampleRate(this, spec->freq << 16, &outRate);
302
303
304
305
rc = UADSetByteOrder(this, "MSB");
rc = UADSetNumberFormat(this, "SIGNED");
break;
case AUDIO_U16LSB:
306
success = 1;
307
bitsPerSample = 16;
308
rc = UADSetSampleRate(this, spec->freq << 16, &outRate);
309
310
311
312
rc = UADSetByteOrder(this, "LSB");
rc = UADSetNumberFormat(this, "UNSIGNED");
break;
case AUDIO_U16MSB:
313
success = 1;
314
bitsPerSample = 16;
315
rc = UADSetSampleRate(this, spec->freq << 16, &outRate);
316
317
318
319
320
321
rc = UADSetByteOrder(this, "MSB");
rc = UADSetNumberFormat(this, "UNSIGNED");
break;
default:
break;
}
322
if (!success) {
323
324
325
test_format = SDL_NextAudioFormat();
}
}
326
while (!success && test_format);
327
328
if (success == 0) {
329
330
331
332
333
334
SDL_SetError("Couldn't find any hardware audio formats");
return -1;
}
spec->format = test_format;
335
336
for (frag_spec = 0; (0x01 << frag_spec) < spec->size; ++frag_spec);
if ((0x01 << frag_spec) != spec->size) {
337
338
339
SDL_SetError("Fragment size must be a power of two");
return -1;
}
340
341
if (frag_spec > 2048)
frag_spec = 2048;
342
343
344
this->hidden->bytesPerSample = (bitsPerSample / 8) * spec->channels;
samplesPerSec = this->hidden->bytesPerSample * outRate;
345
346
this->hidden->playbuf._length = 0;
347
this->hidden->playbuf._maximum = spec->size;
348
349
this->hidden->playbuf._buffer = (unsigned char *) SDL_malloc(spec->size);
this->hidden->fillbuf._length = 0;
350
this->hidden->fillbuf._maximum = spec->size;
351
this->hidden->fillbuf._buffer = (unsigned char *) SDL_malloc(spec->size);
352
353
354
355
rc = UADSetBitsPerSample(this, bitsPerSample);
rc = UADSetDMABufferSize(this, frag_spec, &outBufSize);
rc = UADSetChannels(this, spec->channels); /* functions reduces to mono or stereo */
356
357
358
359
lgain = 100; /*maximum left input gain */
rgain = 100; /*maimum right input gain */
rc = UADEnableOutput(this, "LINE_OUT", &lgain, &rgain);
360
361
362
363
364
365
366
367
368
rc = UADInitialize(this);
rc = UADStart(this);
rc = UADSetVolume(this, 100);
rc = UADSetBalance(this, 0);
/* We're ready to rock and roll. :-) */
return 0;
}
369
370
371
static UMSAudioDevice_ReturnCode
UADGetBitsPerSample(_THIS, long *bits)
372
{
373
374
return UMSAudioDevice_get_bits_per_sample(this->hidden->umsdev,
this->hidden->ev, bits);
375
376
}
377
378
static UMSAudioDevice_ReturnCode
UADSetBitsPerSample(_THIS, long bits)
379
{
380
381
return UMSAudioDevice_set_bits_per_sample(this->hidden->umsdev,
this->hidden->ev, bits);
382
383
}
384
385
static UMSAudioDevice_ReturnCode
UADSetSampleRate(_THIS, long rate, long *set_rate)
386
387
{
/* from the mac code: sample rate = spec->freq << 16; */
388
389
return UMSAudioDevice_set_sample_rate(this->hidden->umsdev,
this->hidden->ev, rate, set_rate);
390
391
}
392
393
static UMSAudioDevice_ReturnCode
UADSetByteOrder(_THIS, string byte_order)
394
{
395
396
return UMSAudioDevice_set_byte_order(this->hidden->umsdev,
this->hidden->ev, byte_order);
397
398
}
399
400
static UMSAudioDevice_ReturnCode
UADSetAudioFormatType(_THIS, string fmt)
401
402
{
/* possible PCM, A_LAW or MU_LAW */
403
404
return UMSAudioDevice_set_audio_format_type(this->hidden->umsdev,
this->hidden->ev, fmt);
405
406
}
407
408
static UMSAudioDevice_ReturnCode
UADSetNumberFormat(_THIS, string fmt)
409
410
{
/* possible SIGNED, UNSIGNED, or TWOS_COMPLEMENT */
411
412
return UMSAudioDevice_set_number_format(this->hidden->umsdev,
this->hidden->ev, fmt);
413
414
}
415
416
static UMSAudioDevice_ReturnCode
UADInitialize(_THIS)
417
{
418
return UMSAudioDevice_initialize(this->hidden->umsdev, this->hidden->ev);
419
420
}
421
422
static UMSAudioDevice_ReturnCode
UADStart(_THIS)
423
{
424
return UMSAudioDevice_start(this->hidden->umsdev, this->hidden->ev);
425
426
}
427
428
static UMSAudioDevice_ReturnCode
UADSetTimeFormat(_THIS, UMSAudioTypes_TimeFormat fmt)
429
430
431
432
433
{
/*
* Switches the time format to the new format, immediately.
* possible UMSAudioTypes_Msecs, UMSAudioTypes_Bytes or UMSAudioTypes_Samples
*/
434
435
return UMSAudioDevice_set_time_format(this->hidden->umsdev,
this->hidden->ev, fmt);
436
437
}
438
439
static UMSAudioDevice_ReturnCode
UADWriteBuffSize(_THIS, long *buff_size)
440
441
442
443
{
/*
* returns write buffer size in the current time format
*/
444
445
return UMSAudioDevice_write_buff_size(this->hidden->umsdev,
this->hidden->ev, buff_size);
446
447
}
448
449
static UMSAudioDevice_ReturnCode
UADWriteBuffRemain(_THIS, long *buff_size)
450
451
452
453
454
{
/*
* returns amount of available space in the write buffer
* in the current time format
*/
455
456
return UMSAudioDevice_write_buff_remain(this->hidden->umsdev,
this->hidden->ev, buff_size);
457
458
}
459
460
static UMSAudioDevice_ReturnCode
UADWriteBuffUsed(_THIS, long *buff_size)
461
462
463
464
465
{
/*
* returns amount of filled space in the write buffer
* in the current time format
*/
466
467
return UMSAudioDevice_write_buff_used(this->hidden->umsdev,
this->hidden->ev, buff_size);
468
469
}
470
471
static UMSAudioDevice_ReturnCode
UADSetDMABufferSize(_THIS, long bytes, long *bytes_ret)
472
473
474
475
476
477
{
/*
* Request a new DMA buffer size, maximum requested size 2048.
* Takes effect with next initialize() call.
* Devices may or may not support DMA.
*/
478
479
480
return UMSAudioDevice_set_DMA_buffer_size(this->hidden->umsdev,
this->hidden->ev,
bytes, bytes_ret);
481
482
}
483
484
static UMSAudioDevice_ReturnCode
UADSetVolume(_THIS, long volume)
485
486
487
488
489
{
/*
* Set the volume.
* Takes effect immediately.
*/
490
491
return UMSAudioDevice_set_volume(this->hidden->umsdev,
this->hidden->ev, volume);
492
493
}
494
495
static UMSAudioDevice_ReturnCode
UADSetBalance(_THIS, long balance)
496
497
498
499
500
{
/*
* Set the balance.
* Takes effect immediately.
*/
501
502
return UMSAudioDevice_set_balance(this->hidden->umsdev,
this->hidden->ev, balance);
503
504
}
505
506
static UMSAudioDevice_ReturnCode
UADSetChannels(_THIS, long channels)
507
508
509
510
511
{
/*
* Set mono or stereo.
* Takes effect with next initialize() call.
*/
512
513
514
515
if (channels != 1)
channels = 2;
return UMSAudioDevice_set_number_of_channels(this->hidden->umsdev,
this->hidden->ev, channels);
516
517
}
518
519
static UMSAudioDevice_ReturnCode
UADOpen(_THIS, string device, string mode, long flags)
520
{
521
522
return UMSAudioDevice_open(this->hidden->umsdev,
this->hidden->ev, device, mode, flags);
523
524
}
525
526
527
static UMSAudioDevice_ReturnCode
UADWrite(_THIS, UMSAudioTypes_Buffer * buff,
long samples, long *samples_written)
528
{
529
530
531
return UMSAudioDevice_write(this->hidden->umsdev,
this->hidden->ev,
buff, samples, samples_written);
532
533
}
534
535
static UMSAudioDevice_ReturnCode
UADPlayRemainingData(_THIS, boolean block)
536
{
537
538
return UMSAudioDevice_play_remaining_data(this->hidden->umsdev,
this->hidden->ev, block);
539
540
}
541
542
static UMSAudioDevice_ReturnCode
UADStop(_THIS)
543
{
544
return UMSAudioDevice_stop(this->hidden->umsdev, this->hidden->ev);
545
546
}
547
548
static UMSAudioDevice_ReturnCode
UADClose(_THIS)
549
{
550
return UMSAudioDevice_close(this->hidden->umsdev, this->hidden->ev);
551
552
}
553
554
static UMSAudioDevice_ReturnCode
UADEnableOutput(_THIS, string output, long *left_gain, long *right_gain)
555
{
556
557
558
return UMSAudioDevice_enable_output(this->hidden->umsdev,
this->hidden->ev,
output, left_gain, right_gain);
559
560
}
561
/* vi: set ts=4 sw=4 expandtab: */