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

流媒体/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_sunaudio.c,v 1.5 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 <fcntl.h>
  26. #include <errno.h>
  27. #include <string.h>
  28. #ifdef __NetBSD__
  29. #include <sys/ioctl.h>
  30. #include <sys/audioio.h>
  31. #endif
  32. #ifdef __SVR4
  33. #include <sys/audio.h>
  34. #else
  35. #include <sys/time.h>
  36. #include <sys/types.h>
  37. #endif
  38. #include <unistd.h>
  39. #include "SDL_endian.h"
  40. #include "SDL_audio.h"
  41. #include "SDL_audiomem.h"
  42. #include "SDL_audiodev_c.h"
  43. #include "SDL_sunaudio.h"
  44. #include "SDL_audio_c.h"
  45. #include "SDL_timer.h"
  46. /* Open the audio device for playback, and don't block if busy */
  47. #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK)
  48. /* Audio driver functions */
  49. static int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec);
  50. static void DSP_WaitAudio(_THIS);
  51. static void DSP_PlayAudio(_THIS);
  52. static Uint8 *DSP_GetAudioBuf(_THIS);
  53. static int DSP_AudioDelayMsec(_THIS);
  54. static void DSP_CloseAudio(_THIS);
  55. /* Audio driver bootstrap functions */
  56. static int Audio_Available(void)
  57. {
  58. int fd;
  59. int available;
  60. available = 0;
  61. fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 1);
  62. if ( fd >= 0 ) {
  63. available = 1;
  64. close(fd);
  65. }
  66. return(available);
  67. }
  68. static void Audio_DeleteDevice(SDL_AudioDevice *device)
  69. {
  70. free(device->hidden);
  71. free(device);
  72. }
  73. static SDL_AudioDevice *Audio_CreateDevice(int devindex)
  74. {
  75. SDL_AudioDevice *this;
  76. /* Initialize all variables that we clean on shutdown */
  77. this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
  78. if ( this ) {
  79. memset(this, 0, (sizeof *this));
  80. this->hidden = (struct SDL_PrivateAudioData *)
  81. malloc((sizeof *this->hidden));
  82. }
  83. if ( (this == NULL) || (this->hidden == NULL) ) {
  84. SDL_OutOfMemory();
  85. if ( this ) {
  86. free(this);
  87. }
  88. return(0);
  89. }
  90. memset(this->hidden, 0, (sizeof *this->hidden));
  91. audio_fd = -1;
  92. /* Set the function pointers */
  93. this->OpenAudio = DSP_OpenAudio;
  94. this->WaitAudio = DSP_WaitAudio;
  95. this->PlayAudio = DSP_PlayAudio;
  96. this->GetAudioBuf = DSP_GetAudioBuf;
  97. this->CloseAudio = DSP_CloseAudio;
  98. this->AudioDelayMsec = DSP_AudioDelayMsec;
  99. this->free = Audio_DeleteDevice;
  100. return this;
  101. }
  102. AudioBootStrap SUNAUDIO_bootstrap = {
  103. "audio", "UNIX /dev/audio interface",
  104. Audio_Available, Audio_CreateDevice
  105. };
  106. #ifdef DEBUG_AUDIO
  107. void CheckUnderflow(_THIS)
  108. {
  109. #ifdef AUDIO_GETINFO
  110. audio_info_t info;
  111. int left;
  112. ioctl(audio_fd, AUDIO_GETINFO, &info);
  113. left = (written - info.play.samples);
  114. if ( written && (left == 0) ) {
  115. fprintf(stderr, "audio underflow!n");
  116. }
  117. #endif
  118. }
  119. #endif
  120. void DSP_WaitAudio(_THIS)
  121. {
  122. #ifdef AUDIO_GETINFO
  123. #define SLEEP_FUDGE 10 /* 10 ms scheduling fudge factor */
  124. audio_info_t info;
  125. Sint32 left;
  126. ioctl(audio_fd, AUDIO_GETINFO, &info);
  127. left = (written - info.play.samples);
  128. if ( left > fragsize ) {
  129. Sint32 sleepy;
  130. sleepy = ((left - fragsize)/frequency);
  131. sleepy -= SLEEP_FUDGE;
  132. if ( sleepy > 0 ) {
  133. SDL_Delay(sleepy);
  134. }
  135. }
  136. #else
  137. fd_set fdset;
  138. FD_ZERO(&fdset);
  139. FD_SET(audio_fd, &fdset);
  140. select(audio_fd+1, NULL, &fdset, NULL, NULL);
  141. #endif
  142. }
  143. void DSP_PlayAudio(_THIS)
  144. {
  145. static Uint8 snd2au(int sample);
  146. /* Write the audio data */
  147. if ( ulaw_only ) {
  148. /* Assuming that this->spec.freq >= 8000 Hz */
  149. int accum, incr, pos;
  150. Uint8 *aubuf;
  151. accum = 0;
  152. incr  = this->spec.freq/8;
  153. aubuf = ulaw_buf;
  154. switch (audio_fmt & 0xFF) {
  155. case 8: {
  156. Uint8 *sndbuf;
  157. sndbuf = mixbuf;
  158. for ( pos=0; pos < fragsize; ++pos ) {
  159. *aubuf = snd2au((0x80-*sndbuf)*64);
  160. accum += incr;
  161. while ( accum > 0 ) {
  162. accum -= 1000;
  163. sndbuf += 1;
  164. }
  165. aubuf += 1;
  166. }
  167. }
  168. break;
  169. case 16: {
  170. Sint16 *sndbuf;
  171. sndbuf = (Sint16 *)mixbuf;
  172. for ( pos=0; pos < fragsize; ++pos ) {
  173. *aubuf = snd2au(*sndbuf/4);
  174. accum += incr;
  175. while ( accum > 0 ) {
  176. accum -= 1000;
  177. sndbuf += 1;
  178. }
  179. aubuf += 1;
  180. }
  181. }
  182. break;
  183. }
  184. #ifdef DEBUG_AUDIO
  185. CheckUnderflow(this);
  186. #endif
  187. if ( write(audio_fd, ulaw_buf, fragsize) < 0 ) {
  188. /* Assume fatal error, for now */
  189. this->enabled = 0;
  190. }
  191. written += fragsize;
  192. } else {
  193. #ifdef DEBUG_AUDIO
  194. CheckUnderflow(this);
  195. #endif
  196. if ( write(audio_fd, mixbuf, this->spec.size) < 0 ) {
  197. /* Assume fatal error, for now */
  198. this->enabled = 0;
  199. }
  200. written += fragsize;
  201. }
  202. }
  203. Uint8 *DSP_GetAudioBuf(_THIS)
  204. {
  205. return(mixbuf);
  206. }
  207. void DSP_CloseAudio(_THIS)
  208. {
  209. if ( mixbuf != NULL ) {
  210. SDL_FreeAudioMem(mixbuf);
  211. mixbuf = NULL;
  212. }
  213. if ( ulaw_buf != NULL ) {
  214. free(ulaw_buf);
  215. ulaw_buf = NULL;
  216. }
  217. close(audio_fd);
  218. }
  219. int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec)
  220. {
  221. char audiodev[1024];
  222. #ifdef AUDIO_SETINFO
  223. int enc;
  224. #endif
  225. int desired_freq = spec->freq;
  226. /* Initialize our freeable variables, in case we fail*/
  227. audio_fd = -1;
  228. mixbuf = NULL;
  229. ulaw_buf = NULL;
  230. /* Determine the audio parameters from the AudioSpec */
  231. switch ( spec->format & 0xFF ) {
  232. case 8: { /* Unsigned 8 bit audio data */
  233. spec->format = AUDIO_U8;
  234. #ifdef AUDIO_SETINFO
  235. enc = AUDIO_ENCODING_LINEAR8;
  236. #endif
  237. }
  238. break;
  239. case 16: { /* Signed 16 bit audio data */
  240.         spec->format = AUDIO_S16SYS;
  241. #ifdef AUDIO_SETINFO
  242. enc = AUDIO_ENCODING_LINEAR;
  243. #endif
  244. }
  245. break;
  246. default: {
  247. SDL_SetError("Unsupported audio format");
  248. return(-1);
  249. }
  250. }
  251. audio_fmt = spec->format;
  252. /* Open the audio device */
  253. audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 1);
  254. if ( audio_fd < 0 ) {
  255. SDL_SetError("Couldn't open %s: %s", audiodev,
  256.      strerror(errno));
  257. return(-1);
  258. }
  259. ulaw_only = 0; /* modern Suns do support linear audio */
  260. #ifdef AUDIO_SETINFO
  261. for(;;) {
  262.     audio_info_t info;
  263.     AUDIO_INITINFO(&info); /* init all fields to "no change" */
  264.     /* Try to set the requested settings */
  265.     info.play.sample_rate = spec->freq;
  266.     info.play.channels = spec->channels;
  267.     info.play.precision = (enc == AUDIO_ENCODING_ULAW)
  268.                   ? 8 : spec->format & 0xff;
  269.     info.play.encoding = enc;
  270.     if( ioctl(audio_fd, AUDIO_SETINFO, &info) == 0 ) {
  271. /* Check to be sure we got what we wanted */
  272. if(ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) {
  273.     SDL_SetError("Error getting audio parameters: %s",
  274.  strerror(errno));
  275.     return -1;
  276. }
  277. if(info.play.encoding == enc
  278.    && info.play.precision == (spec->format & 0xff)
  279.    && info.play.channels == spec->channels) {
  280.     /* Yow! All seems to be well! */
  281.     spec->freq = info.play.sample_rate;
  282.     break;
  283. }
  284.     }
  285.     switch(enc) {
  286.     case AUDIO_ENCODING_LINEAR8:
  287. /* unsigned 8bit apparently not supported here */
  288. enc = AUDIO_ENCODING_LINEAR;
  289. spec->format = AUDIO_S16SYS;
  290. break; /* try again */
  291.     case AUDIO_ENCODING_LINEAR:
  292. /* linear 16bit didn't work either, resort to