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