SDL_paudio.c
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:16k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*
  2.     AIX support for the SDL - Simple DirectMedia Layer
  3.     Copyright (C) 2000  Carsten Griwodz
  4.     This library is free software; you can redistribute it and/or
  5.     modify it under the terms of the GNU Library General Public
  6.     License as published by the Free Software Foundation; either
  7.     version 2 of the License, or (at your option) any later version.
  8.     This library is distributed in the hope that it will be useful,
  9.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11.     Library General Public License for more details.
  12.     You should have received a copy of the GNU Library General Public
  13.     License along with this library; if not, write to the Free
  14.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  15.     Carsten Griwodz
  16.     griff@kom.tu-darmstadt.de
  17.     based on linux/SDL_dspaudio.c by Sam Lantinga
  18. */
  19. #ifdef SAVE_RCSID
  20. static char rcsid =
  21.  "@(#) $Id: SDL_paudio.c,v 1.4 2002/04/22 21:38:02 wmay Exp $";
  22. #endif
  23. /* Allow access to a raw mixing buffer */
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <errno.h>
  28. #include <unistd.h>
  29. #include <fcntl.h>
  30. #include <sys/time.h>
  31. #include <sys/ioctl.h>
  32. #include <sys/stat.h>
  33. #include "SDL_audio.h"
  34. #include "SDL_error.h"
  35. #include "SDL_audiomem.h"
  36. #include "SDL_audio_c.h"
  37. #include "SDL_timer.h"
  38. #include "SDL_audiodev_c.h"
  39. #include "SDL_paudio.h"
  40. #define DEBUG_AUDIO 1
  41. /* A conflict within AIX 4.3.3 <sys/> headers and probably others as well.
  42.  * I guess nobody ever uses audio... Shame over AIX header files.  */
  43. #include <sys/machine.h>
  44. #undef BIG_ENDIAN
  45. #include <sys/audio.h>
  46. /* The tag name used by paud audio */
  47. #define Paud_DRIVER_NAME         "paud"
  48. /* Open the audio device for playback, and don't block if busy */
  49. /* #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) */
  50. #define OPEN_FLAGS O_WRONLY
  51. /* Audio driver functions */
  52. static int Paud_OpenAudio(_THIS, SDL_AudioSpec *spec);
  53. static void Paud_WaitAudio(_THIS);
  54. static void Paud_PlayAudio(_THIS);
  55. static Uint8 *Paud_GetAudioBuf(_THIS);
  56. static void Paud_CloseAudio(_THIS);
  57. /* Audio driver bootstrap functions */
  58. static int Audio_Available(void)
  59. {
  60. int fd;
  61. int available;
  62. available = 0;
  63. fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
  64. if ( fd >= 0 ) {
  65. available = 1;
  66. close(fd);
  67. }
  68. return(available);
  69. }
  70. static void Audio_DeleteDevice(SDL_AudioDevice *device)
  71. {
  72. free(device->hidden);
  73. free(device);
  74. }
  75. static SDL_AudioDevice *Audio_CreateDevice(int devindex)
  76. {
  77. SDL_AudioDevice *this;
  78. /* Initialize all variables that we clean on shutdown */
  79. this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
  80. if ( this ) {
  81. memset(this, 0, (sizeof *this));
  82. this->hidden = (struct SDL_PrivateAudioData *)
  83. malloc((sizeof *this->hidden));
  84. }
  85. if ( (this == NULL) || (this->hidden == NULL) ) {
  86. SDL_OutOfMemory();
  87. if ( this ) {
  88. free(this);
  89. }
  90. return(0);
  91. }
  92. memset(this->hidden, 0, (sizeof *this->hidden));
  93. audio_fd = -1;
  94. /* Set the function pointers */
  95. this->OpenAudio = Paud_OpenAudio;
  96. this->WaitAudio = Paud_WaitAudio;
  97. this->PlayAudio = Paud_PlayAudio;
  98. this->GetAudioBuf = Paud_GetAudioBuf;
  99. this->CloseAudio = Paud_CloseAudio;
  100. this->free = Audio_DeleteDevice;
  101. return this;
  102. }
  103. AudioBootStrap Paud_bootstrap = {
  104. Paud_DRIVER_NAME, "AIX Paudio",
  105. Audio_Available, Audio_CreateDevice
  106. };
  107. /* This function waits until it is possible to write a full sound buffer */
  108. static void Paud_WaitAudio(_THIS)
  109. {
  110.     fd_set fdset;
  111.     /* See if we need to use timed audio synchronization */
  112.     if ( frame_ticks ) {
  113.         /* Use timer for general audio synchronization */
  114.         Sint32 ticks;
  115.         ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
  116.         if ( ticks > 0 ) {
  117.     SDL_Delay(ticks);
  118.         }
  119.     } else {
  120.         audio_buffer  paud_bufinfo;
  121.         /* Use select() for audio synchronization */
  122.         struct timeval timeout;
  123.         FD_ZERO(&fdset);
  124.         FD_SET(audio_fd, &fdset);
  125.         if ( ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0 ) {
  126. #ifdef DEBUG_AUDIO
  127.             fprintf(stderr, "Couldn't get audio buffer informationn");
  128. #endif
  129.             timeout.tv_sec  = 10;
  130.             timeout.tv_usec = 0;
  131.         } else {
  132.     long ms_in_buf = paud_bufinfo.write_buf_time;
  133.             timeout.tv_sec  = ms_in_buf/1000;
  134.     ms_in_buf       = ms_in_buf - timeout.tv_sec*1000;
  135.             timeout.tv_usec = ms_in_buf*1000;
  136. #ifdef DEBUG_AUDIO
  137.             fprintf( stderr,
  138.      "Waiting for write_buf_time=%ld,%ldn",
  139.      timeout.tv_sec,
  140.      timeout.tv_usec );
  141. #endif
  142. }
  143. #ifdef DEBUG_AUDIO
  144.         fprintf(stderr, "Waiting for audio to get readyn");
  145. #endif
  146.         if ( select(audio_fd+1, NULL, &fdset, NULL, &timeout) <= 0 ) {
  147.             const char *message = "Audio timeout - buggy audio driver? (disabled)";
  148.             /*
  149.      * In general we should never print to the screen,
  150.              * but in this case we have no other way of letting
  151.              * the user know what happened.
  152.              */
  153.             fprintf(stderr, "SDL: %s - %sn", strerror(errno), message);
  154.             this->enabled = 0;
  155.             /* Don't try to close - may hang */
  156.             audio_fd = -1;
  157. #ifdef DEBUG_AUDIO
  158.             fprintf(stderr, "Done disabling audion");
  159. #endif
  160.         }
  161. #ifdef DEBUG_AUDIO
  162.         fprintf(stderr, "Ready!n");
  163. #endif
  164.     }
  165. }
  166. static void Paud_PlayAudio(_THIS)
  167. {
  168. int written;
  169. /* Write the audio data, checking for EAGAIN on broken audio drivers */
  170. do {
  171. written = write(audio_fd, mixbuf, mixlen);
  172. if ( (written < 0) && ((errno == 0) || (errno == EAGAIN)) ) {
  173. SDL_Delay(1); /* Let a little CPU time go by */
  174. }
  175. } while ( (written < 0) && 
  176.           ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)) );
  177. /* If timer synchronization is enabled, set the next write frame */
  178. if ( frame_ticks ) {
  179. next_frame += frame_ticks;
  180. }
  181. /* If we couldn't write, assume fatal error for now */
  182. if ( written < 0 ) {
  183. this->enabled = 0;
  184. }
  185. #ifdef DEBUG_AUDIO
  186. fprintf(stderr, "Wrote %d bytes of audio datan", written);
  187. #endif
  188. }
  189. static Uint8 *Paud_GetAudioBuf(_THIS)
  190. {
  191. return mixbuf;
  192. }
  193. static void Paud_CloseAudio(_THIS)
  194. {
  195. if ( mixbuf != NULL ) {
  196. SDL_FreeAudioMem(mixbuf);
  197. mixbuf = NULL;
  198. }
  199. if ( audio_fd >= 0 ) {
  200. close(audio_fd);
  201. audio_fd = -1;
  202. }
  203. }
  204. static int Paud_OpenAudio(_THIS, SDL_AudioSpec *spec)
  205. {
  206. char          audiodev[1024];
  207. int           format;
  208. int           bytes_per_sample;
  209. Uint16        test_format;
  210. audio_init    paud_init;
  211. audio_buffer  paud_bufinfo;
  212. audio_status  paud_status;
  213. audio_control paud_control;
  214. audio_change  paud_change;
  215. /* Reset the timer synchronization flag */
  216. frame_ticks = 0.0;
  217. /* Open the audio device */
  218. audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
  219. if ( audio_fd < 0 ) {
  220. SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
  221. return -1;
  222. }
  223. /*
  224.  * We can't set the buffer size - just ask the device for the maximum
  225.  * that we can have.
  226.  */
  227. if ( ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0 ) {
  228. SDL_SetError("Couldn't get audio buffer information");
  229. return -1;
  230. }
  231. mixbuf = NULL;
  232. if ( spec->channels > 1 )
  233.     spec->channels = 2;
  234. else
  235.     spec->channels = 1;
  236. /*
  237.  * Fields in the audio_init structure:
  238.  *
  239.  * Ignored by us:
  240.  *
  241.  * paud.loadpath[LOAD_PATH]; * DSP code to load, MWave chip only?
  242.  * paud.slot_number;         * slot number of the adapter
  243.  * paud.device_id;           * adapter identification number
  244.  *
  245.  * Input:
  246.  *
  247.  * paud.srate;           * the sampling rate in Hz
  248.  * paud.bits_per_sample; * 8, 16, 32, ...
  249.  * paud.bsize;           * block size for this rate
  250.  * paud.mode;            * ADPCM, PCM, MU_LAW, A_LAW, SOURCE_MIX
  251.  * paud.channels;        * 1=mono, 2=stereo
  252.  * paud.flags;           * FIXED - fixed length data
  253.  *                       * LEFT_ALIGNED, RIGHT_ALIGNED (var len only)
  254.  *                       * TWOS_COMPLEMENT - 2's complement data
  255.  *                       * SIGNED - signed? comment seems wrong in sys/audio.h
  256.  *                       * BIG_ENDIAN
  257.  * paud.operation;       * PLAY, RECORD
  258.  *
  259.  * Output:
  260.  *
  261.  * paud.flags;           * PITCH            - pitch is supported
  262.  *                       * INPUT            - input is supported
  263.  *                       * OUTPUT           - output is supported
  264.  *                       * MONITOR          - monitor is supported
  265.  *                       * VOLUME           - volume is supported
  266.  *                       * VOLUME_DELAY     - volume delay is supported
  267.  *                       * BALANCE          - balance is supported
  268.  *                       * BALANCE_DELAY    - balance delay is supported
  269.  *                       * TREBLE           - treble control is supported
  270.  *                       * BASS             - bass control is supported
  271.  *                       * BESTFIT_PROVIDED - best fit returned
  272.  *                       * LOAD_CODE        - DSP load needed
  273.  * paud.rc;              * NO_PLAY         - DSP code can't do play requests
  274.  *                       * NO_RECORD       - DSP code can't do record requests
  275.  *                       * INVALID_REQUEST - request was invalid
  276.  *                       * CONFLICT        - conflict with open's flags
  277.  *                       * OVERLOADED      - out of DSP MIPS or memory
  278.  * paud.position_resolution; * smallest increment for position
  279.  */
  280.         paud_init.srate = spec->freq;
  281. paud_init.mode = PCM;
  282. paud_init.operation = PLAY;
  283. paud_init.channels = spec->channels;
  284. /* Try for a closest match on audio format */
  285. format = 0;
  286. for ( test_format = SDL_FirstAudioFormat(spec->format);
  287. ! format && test_format; ) {
  288. #ifdef DEBUG_AUDIO
  289. fprintf(stderr, "Trying format 0x%4.4xn", test_format);
  290. #endif
  291. switch ( test_format ) {
  292. case AUDIO_U8:
  293.     bytes_per_sample = 1;
  294.     paud_init.bits_per_sample = 8;
  295.     paud_init.flags = TWOS_COMPLEMENT | FIXED;
  296.     format = 1;
  297.     break;
  298. case AUDIO_S8:
  299.     bytes_per_sample = 1;
  300.     paud_init.bits_per_sample = 8;
  301.     paud_init.flags = SIGNED |
  302.       TWOS_COMPLEMENT | FIXED;
  303.     format = 1;
  304.     break;
  305. case AUDIO_S16LSB:
  306.     bytes_per_sample = 2;
  307.     paud_init.bits_per_sample = 16;
  308.     paud_init.flags = SIGNED |
  309.       TWOS_COMPLEMENT | FIXED;
  310.     format = 1;
  311.     break;
  312. case AUDIO_S16MSB:
  313.     bytes_per_sample = 2;
  314.     paud_init.bits_per_sample = 16;
  315.     paud_init.flags = BIG_ENDIAN |
  316.       SIGNED |
  317.       TWOS_COMPLEMENT | FIXED;
  318.     format = 1;
  319.     break;
  320. case AUDIO_U16LSB:
  321.     bytes_per_sample = 2;
  322.     paud_init.bits_per_sample = 16;
  323.     paud_init.flags = TWOS_COMPLEMENT | FIXED;
  324.     format = 1;
  325.     break;
  326. case AUDIO_U16MSB:
  327.     bytes_per_sample = 2;
  328.     paud_init.bits_per_sample = 16;
  329.     paud_init.flags = BIG_ENDIAN |
  330.       TWOS_COMPLEMENT | FIXED;
  331.     format = 1;
  332.     break;
  333. default:
  334. break;
  335. }
  336. if ( ! format ) {
  337. test_format = SDL_NextAudioFormat();
  338. }
  339. }
  340. if ( format == 0 ) {
  341. #ifdef DEBUG_AUDIO
  342.             fprintf(stderr, "Couldn't find any hardware audio formatsn");
  343. #endif
  344.     SDL_SetError("Couldn't find any hardware audio formats");
  345.     return -1;
  346. }
  347. spec->format = test_format;
  348. /*
  349.  * We know the buffer size and the max number of subsequent writes
  350.  * that can be pending. If more than one can pend, allow the application
  351.  * to do something like double buffering between our write buffer and
  352.  * the device's own buffer that we are filling with write() anyway.
  353.  *
  354.  * We calculate spec->samples like this because SDL_CalculateAudioSpec()
  355.  * will give put paud_bufinfo.write_buf_cap (or paud_bufinfo.write_buf_cap/2)
  356.  * into spec->size in return.
  357.  */
  358. if ( paud_bufinfo.request_buf_cap == 1 )
  359. {
  360.     spec->samples = paud_bufinfo.write_buf_cap
  361.   / bytes_per_sample
  362.   / spec->channels;
  363. }
  364. else
  365. {
  366.     spec->samples = paud_bufinfo.write_buf_cap
  367.   / bytes_per_sample
  368.   / spec->channels
  369.   / 2;
  370. }
  371.         paud_init.bsize = bytes_per_sample * spec->channels;
  372. SDL_CalculateAudioSpec(spec);
  373. /*
  374.  * The AIX paud device init can't modify the values of the audio_init
  375.  * structure that we pass to it. So we don't need any recalculation
  376.  * of this stuff and no reinit call as in linux dsp and dma code.
  377.  *
  378.  * /dev/paud supports all of the encoding formats, so we don't need
  379.  * to do anything like reopening the device, either.
  380.  */
  381. if ( ioctl(audio_fd, AUDIO_INIT, &paud_init) < 0 ) {
  382.     switch ( paud_init.rc )
  383.     {
  384.     case 1 :
  385. SDL_SetError("Couldn't set audio format: DSP can't do play requests");
  386. return -1;
  387. break;
  388.     case 2 :
  389. SDL_SetError("Couldn't set audio format: DSP can't do record requests");
  390. return -1;
  391. break;
  392.     case 4 :
  393. SDL_SetError("Couldn't set audio format: request was invalid");
  394. return -1;
  395. break;
  396.     case 5 :
  397. SDL_SetError("Couldn't set audio format: conflict with open's flags");
  398. return -1;
  399. break;
  400.     case 6 :
  401. SDL_SetError("Couldn't set audio format: out of DSP MIPS or memory");
  402. return -1;
  403. break;
  404.     default :
  405. SDL_SetError("Couldn't set audio format: not documented in sys/audio.h");
  406. return -1;
  407. break;
  408.     }
  409. }
  410. /* Allocate mixing buffer */
  411. mixlen = spec->size;
  412. mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
  413. if ( mixbuf == NULL ) {
  414. return -1;
  415. }
  416. memset(mixbuf, spec->silence, spec->size);
  417. /*
  418.  * Set some paramters: full volume, first speaker that we can find.
  419.  * Ignore the other settings for now.
  420.  */
  421. paud_change.input = AUDIO_IGNORE;         /* the new input source */
  422.         paud_change.output = OUTPUT_1;            /* EXTERNAL_SPEAKER,INTERNAL_SPEAKER,OUTPUT_1 */
  423.         paud_change.monitor = AUDIO_IGNORE;       /* the new monitor state */
  424.         paud_change.volume = 0x7fffffff;          /* volume level [0-0x7fffffff] */
  425.         paud_change.volume_delay = AUDIO_IGNORE;  /* the new volume delay */
  426.         paud_change.balance = 0x3fffffff;         /* the new balance */
  427.         paud_change.balance_delay = AUDIO_IGNORE; /* the new balance delay */
  428.         paud_change.treble = AUDIO_IGNORE;        /* the new treble state */
  429.         paud_change.bass = AUDIO_IGNORE;          /* the new bass state */
  430.         paud_change.pitch = AUDIO_IGNORE;         /* the new pitch state */
  431. paud_control.ioctl_request = AUDIO_CHANGE;
  432. paud_control.request_info = (char*)&paud_change;
  433. if ( ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0 ) {
  434. #ifdef DEBUG_AUDIO
  435.             fprintf(stderr, "Can't change audio display settingsn" );
  436. #endif
  437. }
  438. /*
  439.  * Tell the device to expect data. Actual start will wait for
  440.  * the first write() call.
  441.  */
  442. paud_control.ioctl_request = AUDIO_START;
  443. paud_control.position = 0;
  444. if ( ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0 ) {
  445. #ifdef DEBUG_AUDIO
  446.             fprintf(stderr, "Can't start audio playn" );
  447. #endif
  448.     SDL_SetError("Can't start audio play");
  449.     return -1;
  450. }
  451.         /* Check to see if we need to use select() workaround */
  452.         { char *workaround;
  453.                 workaround = getenv("SDL_DSP_NOSELECT");
  454.                 if ( workaround ) {
  455.                         frame_ticks = (float)(spec->samples*1000)/spec->freq;
  456.                         next_frame = SDL_GetTicks()+frame_ticks;
  457.                 }
  458.         }
  459. /* Get the parent process id (we're the parent of the audio thread) */
  460. parent = getpid();
  461. /* We're ready to rock and roll. :-) */
  462. return 0;
  463. }