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

流媒体/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_dibaudio.c,v 1.4 2002/04/22 21:38:02 wmay Exp $";
  21. #endif
  22. /* Allow access to a raw mixing buffer */
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <windows.h>
  26. #include <mmsystem.h>
  27. #include "SDL_audio.h"
  28. #include "SDL_mutex.h"
  29. #include "SDL_timer.h"
  30. #include "SDL_audio_c.h"
  31. #include "SDL_dibaudio.h"
  32. #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
  33. #include "win_ce_semaphore.h"
  34. #endif
  35. /* Audio driver functions */
  36. static int DIB_OpenAudio(_THIS, SDL_AudioSpec *spec);
  37. static void DIB_ThreadInit(_THIS);
  38. static void DIB_WaitAudio(_THIS);
  39. static Uint8 *DIB_GetAudioBuf(_THIS);
  40. static void DIB_PlayAudio(_THIS);
  41. static void DIB_WaitDone(_THIS);
  42. static void DIB_CloseAudio(_THIS);
  43. /* Audio driver bootstrap functions */
  44. static int Audio_Available(void)
  45. {
  46. return(1);
  47. }
  48. static void Audio_DeleteDevice(SDL_AudioDevice *device)
  49. {
  50. free(device->hidden);
  51. free(device);
  52. }
  53. static SDL_AudioDevice *Audio_CreateDevice(int devindex)
  54. {
  55. SDL_AudioDevice *this;
  56. /* Initialize all variables that we clean on shutdown */
  57. this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
  58. if ( this ) {
  59. memset(this, 0, (sizeof *this));
  60. this->hidden = (struct SDL_PrivateAudioData *)
  61. malloc((sizeof *this->hidden));
  62. }
  63. if ( (this == NULL) || (this->hidden == NULL) ) {
  64. SDL_OutOfMemory();
  65. if ( this ) {
  66. free(this);
  67. }
  68. return(0);
  69. }
  70. memset(this->hidden, 0, (sizeof *this->hidden));
  71. /* Set the function pointers */
  72. this->OpenAudio = DIB_OpenAudio;
  73. this->ThreadInit = DIB_ThreadInit;
  74. this->WaitAudio = DIB_WaitAudio;
  75. this->PlayAudio = DIB_PlayAudio;
  76. this->GetAudioBuf = DIB_GetAudioBuf;
  77. this->WaitDone = DIB_WaitDone;
  78. this->CloseAudio = DIB_CloseAudio;
  79. this->free = Audio_DeleteDevice;
  80. return this;
  81. }
  82. AudioBootStrap WAVEOUT_bootstrap = {
  83. "waveout", "Win95/98/NT/2000 WaveOut",
  84. Audio_Available, Audio_CreateDevice
  85. };
  86. /* The Win32 callback for filling the WAVE device */
  87. static void CALLBACK FillSound(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance,
  88. DWORD dwParam1, DWORD dwParam2)
  89. {
  90. SDL_AudioDevice *this = (SDL_AudioDevice *)dwInstance;
  91. /* Only service "buffer done playing" messages */
  92. if ( uMsg != WOM_DONE )
  93. return;
  94. /* Signal that we are done playing a buffer */
  95. #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
  96. ReleaseSemaphoreCE(audio_sem, 1, NULL);
  97. #else
  98. ReleaseSemaphore(audio_sem, 1, NULL);
  99. #endif
  100. }
  101. static void SetMMerror(char *function, MMRESULT code)
  102. {
  103. int len;
  104. char errbuf[MAXERRORLENGTH];
  105. #ifdef _WIN32_WCE
  106. wchar_t werrbuf[MAXERRORLENGTH];
  107. #endif
  108. sprintf(errbuf, "%s: ", function);
  109. len = strlen(errbuf);
  110. #ifdef _WIN32_WCE
  111. /* UNICODE version */
  112. waveOutGetErrorText(code, werrbuf, MAXERRORLENGTH-len);
  113. WideCharToMultiByte(CP_ACP,0,werrbuf,-1,errbuf+len,MAXERRORLENGTH-len,NULL,NULL);
  114. #else
  115. waveOutGetErrorText(code, errbuf+len, MAXERRORLENGTH-len);
  116. #endif
  117. SDL_SetError("%s",errbuf);
  118. }
  119. /* Set high priority for the audio thread */
  120. static void DIB_ThreadInit(_THIS)
  121. {
  122. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
  123. }
  124. void DIB_WaitAudio(_THIS)
  125. {
  126. /* Wait for an audio chunk to finish */
  127. #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
  128. WaitForSemaphoreCE(audio_sem, INFINITE);
  129. #else
  130. WaitForSingleObject(audio_sem, INFINITE);
  131. #endif
  132. }
  133. Uint8 *DIB_GetAudioBuf(_THIS)
  134. {
  135.         Uint8 *retval;
  136. retval = (Uint8 *)(wavebuf[next_buffer].lpData);
  137. return retval;
  138. }
  139. void DIB_PlayAudio(_THIS)
  140. {
  141. /* Queue it up */
  142. waveOutWrite(sound, &wavebuf[next_buffer], sizeof(wavebuf[0]));
  143. next_buffer = (next_buffer+1)%NUM_BUFFERS;
  144. }
  145. void DIB_WaitDone(_THIS)
  146. {
  147. int i, left;
  148. do {
  149. left = NUM_BUFFERS;
  150. for ( i=0; i<NUM_BUFFERS; ++i ) {
  151. if ( wavebuf[i].dwFlags & WHDR_DONE ) {
  152. --left;
  153. }
  154. }
  155. if ( left > 0 ) {
  156. SDL_Delay(100);
  157. }
  158. } while ( left > 0 );
  159. }
  160. void DIB_CloseAudio(_THIS)
  161. {
  162. int i;
  163. /* Close up audio */
  164. if ( audio_sem ) {
  165. #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
  166. CloseSynchHandle(audio_sem);
  167. #else
  168. CloseHandle(audio_sem);
  169. #endif
  170. }
  171. if ( sound ) {
  172. waveOutClose(sound);
  173. }
  174. /* Clean up mixing buffers */
  175. for ( i=0; i<NUM_BUFFERS; ++i ) {
  176. if ( wavebuf[i].dwUser != 0xFFFF ) {
  177. waveOutUnprepareHeader(sound, &wavebuf[i],
  178. sizeof(wavebuf[i]));
  179. wavebuf[i].dwUser = 0xFFFF;
  180. }
  181. }
  182. /* Free raw mixing buffer */
  183. if ( mixbuf != NULL ) {
  184. free(mixbuf);
  185. mixbuf = NULL;
  186. }
  187. }
  188. int DIB_OpenAudio(_THIS, SDL_AudioSpec *spec)
  189. {
  190. MMRESULT result;
  191. int i;
  192. WAVEFORMATEX waveformat;
  193. /* Initialize the wavebuf structures for closing */
  194. sound = NULL;
  195. audio_sem = NULL;
  196. for ( i = 0; i < NUM_BUFFERS; ++i )
  197. wavebuf[i].dwUser = 0xFFFF;
  198. mixbuf = NULL;
  199. /* Set basic WAVE format parameters */
  200. memset(&waveformat, 0, sizeof(waveformat));
  201. waveformat.wFormatTag = WAVE_FORMAT_PCM;
  202. /* Determine the audio parameters from the AudioSpec */
  203. switch ( spec->format & 0xFF ) {
  204. case 8:
  205. /* Unsigned 8 bit audio data */
  206. spec->format = AUDIO_U8;
  207. waveformat.wBitsPerSample = 8;
  208. break;
  209. case 16:
  210. /* Signed 16 bit audio data */
  211. spec->format = AUDIO_S16;
  212. waveformat.wBitsPerSample = 16;
  213. break;
  214. default:
  215. SDL_SetError("Unsupported audio format");
  216. return(-1);
  217. }
  218. waveformat.nChannels = spec->channels;
  219. waveformat.nSamplesPerSec = spec->freq;
  220. waveformat.nBlockAlign =
  221. waveformat.nChannels * (waveformat.wBitsPerSample/8);
  222. waveformat.nAvgBytesPerSec = 
  223. waveformat.nSamplesPerSec * waveformat.nBlockAlign;
  224. /* Check the buffer size -- minimum of 1/4 second (word aligned) */
  225. if ( spec->samples < (spec->freq/4) )
  226. spec->samples = ((spec->freq/4)+3)&~3;
  227. /* Update the fragment size as size in bytes */
  228. SDL_CalculateAudioSpec(spec);
  229. /* Open the audio device */
  230. result = waveOutOpen(&sound, WAVE_MAPPER, &waveformat,
  231. (DWORD)FillSound, (DWORD)this, CALLBACK_FUNCTION);
  232. if ( result != MMSYSERR_NOERROR ) {
  233. SetMMerror("waveOutOpen()", result);
  234. return(-1);
  235. }
  236. #ifdef SOUND_DEBUG
  237. /* Check the sound device we retrieved */
  238. {
  239. WAVEOUTCAPS caps;
  240. result = waveOutGetDevCaps((UINT)sound, &caps, sizeof(caps));
  241. if ( result != MMSYSERR_NOERROR ) {
  242. SetMMerror("waveOutGetDevCaps()", result);
  243. return(-1);
  244. }
  245. printf("Audio device: %sn", caps.szPname);
  246. }
  247. #endif
  248. /* Create the audio buffer semaphore */
  249. #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
  250. audio_sem = CreateSemaphoreCE(NULL, NUM_BUFFERS-1, NUM_BUFFERS, NULL);
  251. #else
  252. audio_sem = CreateSemaphore(NULL, NUM_BUFFERS-1, NUM_BUFFERS, NULL);
  253. #endif
  254. if ( audio_sem == NULL ) {
  255. SDL_SetError("Couldn't create semaphore");
  256. return(-1);
  257. }
  258. /* Create the sound buffers */
  259. mixbuf = (Uint8 *)malloc(NUM_BUFFERS*spec->size);
  260. if ( mixbuf == NULL ) {
  261. SDL_SetError("Out of memory");
  262. return(-1);
  263. }
  264. for ( i = 0; i < NUM_BUFFERS; ++i ) {
  265. memset(&wavebuf[i], 0, sizeof(wavebuf[i]));
  266. wavebuf[i].lpData = (LPSTR) &mixbuf[i*spec->size];
  267. wavebuf[i].dwBufferLength = spec->size;
  268. wavebuf[i].dwFlags = WHDR_DONE;
  269. result = waveOutPrepareHeader(sound, &wavebuf[i],
  270. sizeof(wavebuf[i]));
  271. if ( result != MMSYSERR_NOERROR ) {
  272. SetMMerror("waveOutPrepareHeader()", result);
  273. return(-1);
  274. }
  275. }
  276. /* Ready to go! */
  277. next_buffer = 0;
  278. return(0);
  279. }