• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2012 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 */
48 static int UMS_OpenAudio(_THIS, SDL_AudioSpec *spec);
49 static void UMS_PlayAudio(_THIS);
50 static Uint8 *UMS_GetAudioBuf(_THIS);
51 static void UMS_CloseAudio(_THIS);
52 
53 static UMSAudioDevice_ReturnCode UADOpen(_THIS,  string device, string mode, long flags);
54 static UMSAudioDevice_ReturnCode UADClose(_THIS);
55 static UMSAudioDevice_ReturnCode UADGetBitsPerSample(_THIS, long* bits);
56 static UMSAudioDevice_ReturnCode UADSetBitsPerSample(_THIS, long bits);
57 static UMSAudioDevice_ReturnCode UADSetSampleRate(_THIS, long rate, long* set_rate);
58 static UMSAudioDevice_ReturnCode UADSetByteOrder(_THIS, string byte_order);
59 static UMSAudioDevice_ReturnCode UADSetAudioFormatType(_THIS, string fmt);
60 static UMSAudioDevice_ReturnCode UADSetNumberFormat(_THIS, string fmt);
61 static UMSAudioDevice_ReturnCode UADInitialize(_THIS);
62 static UMSAudioDevice_ReturnCode UADStart(_THIS);
63 static UMSAudioDevice_ReturnCode UADStop(_THIS);
64 static UMSAudioDevice_ReturnCode UADSetTimeFormat(_THIS,  UMSAudioTypes_TimeFormat fmt );
65 static UMSAudioDevice_ReturnCode UADWriteBuffSize(_THIS,  long* buff_size );
66 static UMSAudioDevice_ReturnCode UADWriteBuffRemain(_THIS,  long* buff_size );
67 static UMSAudioDevice_ReturnCode UADWriteBuffUsed(_THIS,  long* buff_size );
68 static UMSAudioDevice_ReturnCode UADSetDMABufferSize(_THIS,  long bytes, long* bytes_ret );
69 static UMSAudioDevice_ReturnCode UADSetVolume(_THIS,  long volume );
70 static UMSAudioDevice_ReturnCode UADSetBalance(_THIS,  long balance );
71 static UMSAudioDevice_ReturnCode UADSetChannels(_THIS,  long channels );
72 static UMSAudioDevice_ReturnCode UADPlayRemainingData(_THIS,  boolean block );
73 static UMSAudioDevice_ReturnCode UADEnableOutput(_THIS,  string output, long* left_gain, long* right_gain);
74 static UMSAudioDevice_ReturnCode UADWrite(_THIS,  UMSAudioTypes_Buffer* buff, long samples, long* samples_written);
75 
76 /* Audio driver bootstrap functions */
Audio_Available(void)77 static int Audio_Available(void)
78 {
79     return 1;
80 }
81 
Audio_DeleteDevice(_THIS)82 static 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 
Audio_CreateDevice(int devindex)91 static 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 
138 AudioBootStrap UMS_bootstrap = {
139 	UMS_DRIVER_NAME, "AIX UMS audio",
140 	Audio_Available, Audio_CreateDevice
141 };
142 
UMS_GetAudioBuf(_THIS)143 static 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 
UMS_CloseAudio(_THIS)158 static 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 
UMS_PlayAudio(_THIS)170 static 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 
UMS_OpenAudio(_THIS,SDL_AudioSpec * spec)224 static 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 
UADGetBitsPerSample(_THIS,long * bits)352 static 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 
UADSetBitsPerSample(_THIS,long bits)359 static 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 
UADSetSampleRate(_THIS,long rate,long * set_rate)366 static 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 
UADSetByteOrder(_THIS,string byte_order)375 static 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 
UADSetAudioFormatType(_THIS,string fmt)382 static 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 
UADSetNumberFormat(_THIS,string fmt)390 static 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 
UADInitialize(_THIS)398 static UMSAudioDevice_ReturnCode UADInitialize(_THIS)
399 {
400     return UMSAudioDevice_initialize( this->hidden->umsdev,
401 				      this->hidden->ev );
402 }
403 
UADStart(_THIS)404 static UMSAudioDevice_ReturnCode UADStart(_THIS)
405 {
406     return UMSAudioDevice_start( this->hidden->umsdev,
407 				 this->hidden->ev );
408 }
409 
UADSetTimeFormat(_THIS,UMSAudioTypes_TimeFormat fmt)410 static 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 
UADWriteBuffSize(_THIS,long * buff_size)421 static 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 
UADWriteBuffRemain(_THIS,long * buff_size)431 static 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 
UADWriteBuffUsed(_THIS,long * buff_size)442 static 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 
UADSetDMABufferSize(_THIS,long bytes,long * bytes_ret)453 static 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 
UADSetVolume(_THIS,long volume)466 static 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 
UADSetBalance(_THIS,long balance)477 static 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 
UADSetChannels(_THIS,long channels)488 static 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 
UADOpen(_THIS,string device,string mode,long flags)500 static 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 
UADWrite(_THIS,UMSAudioTypes_Buffer * buff,long samples,long * samples_written)509 static 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 
UADPlayRemainingData(_THIS,boolean block)520 static UMSAudioDevice_ReturnCode UADPlayRemainingData(_THIS,  boolean block )
521 {
522     return UMSAudioDevice_play_remaining_data( this->hidden->umsdev,
523 					       this->hidden->ev,
524 					       block);
525 }
526 
UADStop(_THIS)527 static UMSAudioDevice_ReturnCode UADStop(_THIS)
528 {
529     return UMSAudioDevice_stop( this->hidden->umsdev,
530 				this->hidden->ev );
531 }
532 
UADClose(_THIS)533 static UMSAudioDevice_ReturnCode UADClose(_THIS)
534 {
535     return UMSAudioDevice_close( this->hidden->umsdev,
536 				 this->hidden->ev );
537 }
538 
UADEnableOutput(_THIS,string output,long * left_gain,long * right_gain)539 static 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 
548