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