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

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*
  2.     SDL - Simple DirectMedia Layer
  3.     Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Sam Lantinga
  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.     Sam Lantinga
  16.     slouken@libsdl.org
  17. */
  18. #ifdef SAVE_RCSID
  19. static char rcsid =
  20.  "@(#) $Id: SDL_dspaudio.c,v 1.3 2002/04/22 21:38:02 wmay Exp $";
  21. #endif
  22. /* Allow access to a raw mixing buffer */
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <errno.h>
  27. #include <unistd.h>
  28. #include <fcntl.h>
  29. #include <signal.h>
  30. #include <sys/time.h>
  31. #include <sys/ioctl.h>
  32. #include <sys/stat.h>
  33. #ifdef OSS_USE_SOUNDCARD_H
  34. /* This is installed on some systems */
  35. #include <soundcard.h>
  36. #else
  37. /* This is recommended by OSS */
  38. #include <sys/soundcard.h>
  39. #endif
  40. #include "SDL_audio.h"
  41. #include "SDL_error.h"
  42. #include "SDL_audiomem.h"
  43. #include "SDL_audio_c.h"
  44. #include "SDL_timer.h"
  45. #include "SDL_audiodev_c.h"
  46. #include "SDL_dspaudio.h"
  47. /* The tag name used by DSP audio */
  48. #define DSP_DRIVER_NAME         "dsp"
  49. /* Open the audio device for playback, and don't block if busy */
  50. /*#define USE_BLOCKING_WRITES*/
  51. #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK)
  52. /* Audio driver functions */
  53. static int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec);
  54. static void DSP_WaitAudio(_THIS);
  55. static void DSP_PlayAudio(_THIS);
  56. static Uint8 *DSP_GetAudioBuf(_THIS);
  57. static int DSP_AudioDelayMsec(_THIS);
  58. static void DSP_CloseAudio(_THIS);
  59. /* Audio driver bootstrap functions */
  60. static int Audio_Available(void)
  61. {
  62. int fd;
  63. int available;
  64. available = 0;
  65. fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
  66. if ( fd >= 0 ) {
  67. available = 1;
  68. close(fd);
  69. }
  70. return(available);
  71. }
  72. static void Audio_DeleteDevice(SDL_AudioDevice *device)
  73. {
  74. free(device->hidden);
  75. free(device);
  76. }
  77. static SDL_AudioDevice *Audio_CreateDevice(int devindex)
  78. {
  79. SDL_AudioDevice *this;
  80. /* Initialize all variables that we clean on shutdown */
  81. this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
  82. if ( this ) {
  83. memset(this, 0, (sizeof *this));
  84. this->hidden = (struct SDL_PrivateAudioData *)
  85. malloc((sizeof *this->hidden));
  86. }
  87. if ( (this == NULL) || (this->hidden == NULL) ) {
  88. SDL_OutOfMemory();
  89. if ( this ) {
  90. free(this);
  91. }
  92. return(0);
  93. }
  94. memset(this->hidden, 0, (sizeof *this->hidden));
  95. audio_fd = -1;
  96. /* Set the function pointers */
  97. this->OpenAudio = DSP_OpenAudio;
  98. this->WaitAudio = DSP_WaitAudio;
  99. this->PlayAudio = DSP_PlayAudio;
  100. this->GetAudioBuf = DSP_GetAudioBuf;
  101. this->CloseAudio = DSP_CloseAudio;
  102. this->AudioDelayMsec = DSP_AudioDelayMsec;
  103. this->free = Audio_DeleteDevice;
  104. return this;
  105. }
  106. AudioBootStrap DSP_bootstrap = {
  107. DSP_DRIVER_NAME, "OSS /dev/dsp standard audio",
  108. Audio_Available, Audio_CreateDevice
  109. };
  110. /* This function waits until it is possible to write a full sound buffer */
  111. static void DSP_WaitAudio(_THIS)
  112. {
  113. /* Check to see if the thread-parent process is still alive */
  114. { static int cnt = 0;
  115. /* Note that this only works with thread implementations 
  116.    that use a different process id for each thread.
  117. */
  118. if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */
  119. if ( kill(parent, 0) < 0 ) {
  120. this->enabled = 0;
  121. }
  122. }
  123. }
  124. #ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */
  125. /* See if we need to use timed audio synchronization */
  126. if ( frame_ticks ) {
  127. /* Use timer for general audio synchronization */
  128. Sint32 ticks;
  129. ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
  130. if ( ticks > 0 ) {
  131. SDL_Delay(ticks);
  132. }
  133. } else {
  134. /* Use select() for audio synchronization */
  135. fd_set fdset;
  136. struct timeval timeout;
  137. FD_ZERO(&fdset);
  138. FD_SET(audio_fd, &fdset);
  139. timeout.tv_sec = 10;
  140. timeout.tv_usec = 0;
  141. #ifdef DEBUG_AUDIO
  142. fprintf(stderr, "Waiting for audio to get readyn");
  143. #endif
  144. if ( select(audio_fd+1, NULL, &fdset, NULL, &timeout) <= 0 ) {
  145. const char *message =
  146. "Audio timeout - buggy audio driver? (disabled)";
  147. /* In general we should never print to the screen,
  148.    but in this case we have no other way of letting
  149.    the user know what happened.
  150. */
  151. fprintf(stderr, "SDL: %sn", message);
  152. this->enabled = 0;
  153. /* Don't try to close - may hang */
  154. audio_fd = -1;
  155. #ifdef DEBUG_AUDIO
  156. fprintf(stderr, "Done disabling audion");
  157. #endif
  158. }
  159. #ifdef DEBUG_AUDIO
  160. fprintf(stderr, "Ready!n");
  161. #endif
  162. }
  163. #endif /* !USE_BLOCKING_WRITES */
  164. }
  165. static void DSP_PlayAudio(_THIS)
  166. {
  167. int written, p=0;
  168. /* Write the audio data, checking for EAGAIN on broken audio drivers */
  169. do {
  170. written = write(audio_fd, &mixbuf[p], mixlen-p);
  171. if (written>0)
  172.    p += written;
  173. if (written == -1 && errno != 0 && errno != EAGAIN && errno != EINTR)
  174. {
  175.    /* Non recoverable error has occurred. It should be reported!!! */
  176.    perror("audio");
  177.    break;
  178. }
  179. if ( p < written || ((written < 0) && ((errno == 0) || (errno == EAGAIN))) ) {
  180. SDL_Delay(1); /* Let a little CPU time go by */
  181. }
  182. } while ( p < written );
  183. /* If timer synchronization is enabled, set the next write frame */
  184. if ( frame_ticks ) {
  185. next_frame += frame_ticks;
  186. }
  187. /* If we couldn't write, assume fatal error for now */
  188. if ( written < 0 ) {
  189. this->enabled = 0;
  190. }
  191. #ifdef DEBUG_AUDIO
  192. fprintf(stderr, "Wrote %d bytes of audio datan", written);
  193. #endif
  194. }
  195. static Uint8 *DSP_GetAudioBuf(_THIS)
  196. {
  197. return(mixbuf);
  198. }
  199. static void DSP_CloseAudio(_THIS)
  200. {
  201. if ( mixbuf != NULL ) {
  202. SDL_FreeAudioMem(mixbuf);
  203. mixbuf = NULL;
  204. }
  205. if ( audio_fd >= 0 ) {
  206. int value;
  207. ioctl(audio_fd, SNDCTL_DSP_RESET, &value);
  208. close(audio_fd);
  209. audio_fd = -1;
  210. }
  211. }
  212. static int DSP_ReopenAudio(_THIS, const char *audiodev, int format,
  213. SDL_AudioSpec *spec)
  214. {
  215. int frag_spec;
  216. int value;
  217. /* Close and then reopen the audio device */
  218. close(audio_fd);
  219. audio_fd = open(audiodev, O_WRONLY, 0);
  220. if ( audio_fd < 0 ) {
  221. SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
  222. return(-1);
  223. }
  224. /* Calculate the final parameters for this audio specification */
  225. SDL_CalculateAudioSpec(spec);
  226. /* Determine the power of two of the fragment size */
  227. for ( frag_spec = 0; (0x01<<frag_spec) < spec->size; ++frag_spec );
  228. if ( (0x01<<frag_spec) != spec->size ) {
  229. SDL_SetError("Fragment size must be a power of two");
  230. return(-1);
  231. }
  232. frag_spec |= 0x00020000; /* two fragments, for low latency */
  233. /* Set the audio buffering parameters */
  234. #ifdef DEBUG_AUDIO
  235. fprintf(stderr, "Requesting %d fragments of size %dn",
  236. (frag_spec >> 16), 1<<(frag_spec&0xFFFF));
  237. #endif
  238. if ( ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0 ) {
  239. fprintf(stderr, "Warning: Couldn't set audio fragment sizen");
  240. }
  241. #ifdef DEBUG_AUDIO
  242. { audio_buf_info info;
  243.   ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info);
  244.   fprintf(stderr, "fragments = %dn", info.fragments);
  245.   fprintf(stderr, "fragstotal = %dn", info.fragstotal);
  246.   fprintf(stderr, "fragsize = %dn", info.fragsize);
  247.   fprintf(stderr, "bytes = %dn", info.bytes);
  248. }
  249. #endif
  250. /* Set the audio format */
  251. value = format;
  252. if ( (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
  253. (value != format) ) {
  254. SDL_SetError("Couldn't set audio format");
  255. return(-1);
  256. }
  257. /* Set the number of channels of output */
  258. value = spec->channels;
  259. #ifdef SNDCTL_DSP_CHANNELS
  260. if ( ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0 ) {
  261. #endif
  262. value = (spec->channels > 1);
  263. ioctl(audio_fd, SNDCTL_DSP_STEREO, &value);
  264. value = (value ? 2 : 1);
  265. #ifdef SNDCTL_DSP_CHANNELS
  266. }
  267. #endif
  268. if ( value != spec->channels ) {
  269. SDL_SetError("Couldn't set audio channels");
  270. return(-1);
  271. }
  272. /* Set the DSP frequency */
  273. value = spec->freq;
  274. if ( ioctl(audio_fd, SOUND_PCM_WRITE_RATE, &value) < 0 ) {
  275. SDL_SetError("Couldn't set audio frequency");
  276. return(-1);
  277. }
  278. spec->freq = value;
  279. /* We successfully re-opened the audio */
  280. return(0);
  281. }
  282. static int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec)
  283. {
  284. char audiodev[1024];
  285. int format;
  286. int value;
  287. Uint16 test_format;
  288. /* Reset the timer synchronization flag */
  289. frame_ticks = 0.0;
  290. /* Open the audio device */
  291. audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
  292. if ( audio_fd < 0 ) {
  293. SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
  294. return(-1);
  295. }
  296. mixbuf = NULL;
  297. #ifdef USE_BLOCKING_WRITES
  298. /* Make the file descriptor use blocking writes with fcntl() */
  299. { long flags;
  300. flags = fcntl(audio_fd, F_GETFL);
  301. flags &= ~O_NONBLOCK;
  302. if ( fcntl(audio_fd, F_SETFL, flags) < 0 ) {
  303. SDL_SetError("Couldn't set audio blocking mode");
  304. return(-1);
  305. }
  306. }
  307. #endif
  308. /* Get a list of supported hardware formats */
  309. if ( ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0 ) {
  310. SDL_SetError("Couldn't get audio format list");
  311. return(-1);
  312. }
  313. /* Try for a closest match on audio format */
  314. format = 0;
  315. for ( test_format = SDL_FirstAudioFormat(spec->format);
  316. ! format && test_format; ) {
  317. #ifdef DEBUG_AUDIO
  318. fprintf(stderr, "Trying format 0x%4.4xn", test_format);
  319. #endif
  320. switch ( test_format ) {
  321. case AUDIO_U8:
  322. if ( value & AFMT_U8 ) {
  323. format = AFMT_U8;
  324. }
  325. break;
  326. case AUDIO_S8:
  327. if ( value & AFMT_S8 ) {
  328. format = AFMT_S8;
  329. }
  330. break;
  331. case AUDIO_S16LSB:
  332. if ( value & AFMT_S16_LE ) {
  333. format = AFMT_S16_LE;
  334. }
  335. break;
  336. case AUDIO_S16MSB:
  337. if ( value & AFMT_S16_BE ) {
  338. format = AFMT_S16_BE;
  339. }
  340. break;
  341. case AUDIO_U16LSB:
  342. if ( value & AFMT_U16_LE ) {
  343. format = AFMT_U16_LE;
  344. }
  345. break;
  346. case AUDIO_U16MSB:
  347. if ( value & AFMT_U16_BE ) {
  348. format = AFMT_U16_BE;
  349. }
  350. break;
  351. default:
  352. break;
  353. }
  354. if ( ! format ) {
  355. test_format = SDL_NextAudioFormat();
  356. }
  357. }
  358. if ( format == 0 ) {
  359. SDL_SetError("Couldn't find any hardware audio formats");
  360. return(-1);
  361. }
  362. spec->format = test_format;
  363. /* Set the audio format */
  364. value = format;
  365. if ( (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
  366. (value != format) ) {
  367. SDL_SetError("Couldn't set audio format");
  368. return(-1);
  369. }
  370. /* Set the number of channels of output */
  371. value = spec->channels;
  372. #ifdef SNDCTL_DSP_CHANNELS
  373. if ( ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0 ) {
  374. #endif
  375. value = (spec->channels > 1);
  376. ioctl(audio_fd, SNDCTL_DSP_STEREO, &value);
  377. value = (value ? 2 : 1);
  378. #ifdef SNDCTL_DSP_CHANNELS
  379. }
  380. #endif
  381. spec->channels = value;
  382. /* Because some drivers don't allow setting the buffer size
  383.    after setting the format, we must re-open the audio device
  384.    once we know what format and channels are supported
  385.  */
  386. if ( DSP_ReopenAudio(this, audiodev, format, spec) < 0 ) {
  387. /* Error is set by DSP_ReopenAudio() */
  388. return(-1);
  389. }
  390. /* Allocate mixing buffer */
  391. mixlen = spec->size;
  392. mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
  393. if ( mixbuf == NULL ) {
  394. return(-1);
  395. }
  396. memset(mixbuf, spec->silence, spec->size);
  397. #ifndef USE_BLOCKING_WRITES
  398. /* Check to see if we need to use select() workaround */
  399. { char *workaround;
  400. workaround = getenv("SDL_DSP_NOSELECT");
  401. if ( workaround ) {
  402. frame_ticks = (float)(spec->samples*1000)/spec->freq;
  403. next_frame = SDL_GetTicks()+frame_ticks;
  404. }
  405. }
  406. #endif /* !USE_BLOCKING_WRITES */
  407. /* Get the parent process id (we're the parent of the audio thread) */
  408. parent = getpid();
  409. /* We're ready to rock and roll. :-) */
  410. return(0);
  411. }
  412. static int DSP_AudioDelayMsec (_THIS)
  413. {
  414.   int odelay;
  415.   ioctl(audio_fd, SNDCTL_DSP_GETODELAY, &odelay);
  416.   if (odelay > 0) {  
  417.     /*
  418.      * delay in msec is bytes  * 1000 / (bytes per sample * channels * freq)
  419.      */
  420.     odelay *= 1000;
  421.     odelay /= this->spec.channels;
  422.     if (!(this->spec.format == AUDIO_U8 ||
  423.     this->spec.format == AUDIO_S8)) {
  424.       odelay /= 2; // 2 bytes per sample
  425.     }
  426.     odelay /= this->spec.freq;
  427.   }
  428.   return (odelay);
  429. }