SDL_esdaudio.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_esdaudio.c,v 1.4 2002/04/22 21:38:02 wmay Exp $";
  21. #endif
  22. /* Allow access to an ESD network stream mixing buffer */
  23. #ifdef ESD_SUPPORT
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <errno.h>
  28. #include <signal.h>
  29. #include <unistd.h>
  30. #include <esd.h>
  31. #include "SDL_audio.h"
  32. #include "SDL_error.h"
  33. #include "SDL_audiomem.h"
  34. #include "SDL_audio_c.h"
  35. #include "SDL_timer.h"
  36. #include "SDL_audiodev_c.h"
  37. #include "SDL_esdaudio.h"
  38. #ifdef ESD_DYNAMIC
  39. #include "SDL_name.h"
  40. #include "SDL_loadso.h"
  41. #else
  42. #define SDL_NAME(X) X
  43. #endif
  44. /* The tag name used by ESD audio */
  45. #define ESD_DRIVER_NAME "esd"
  46. /* Audio driver functions */
  47. static int ESD_OpenAudio(_THIS, SDL_AudioSpec *spec);
  48. static void ESD_WaitAudio(_THIS);
  49. static void ESD_PlayAudio(_THIS);
  50. static Uint8 *ESD_GetAudioBuf(_THIS);
  51. static void ESD_CloseAudio(_THIS);
  52. #ifdef ESD_DYNAMIC
  53. static const char *esd_library = ESD_DYNAMIC;
  54. static void *esd_handle = NULL;
  55. static int esd_loaded = 0;
  56. static int (*SDL_NAME(esd_open_sound))( const char *host );
  57. static int (*SDL_NAME(esd_close))( int esd );
  58. static int (*SDL_NAME(esd_play_stream))( esd_format_t format, int rate,
  59.                                          const char *host, const char *name );
  60. static struct {
  61. const char *name;
  62. void **func;
  63. } esd_functions[] = {
  64. { "esd_open_sound", (void **)&SDL_NAME(esd_open_sound) },
  65. { "esd_close", (void **)&SDL_NAME(esd_close) },
  66. { "esd_play_stream", (void **)&SDL_NAME(esd_play_stream) },
  67. };
  68. static void UnloadESDLibrary()
  69. {
  70. if ( esd_loaded ) {
  71. SDL_UnloadObject(esd_handle);
  72. esd_handle = NULL;
  73. esd_loaded = 0;
  74. }
  75. }
  76. static int LoadESDLibrary(void)
  77. {
  78. int i, retval = -1;
  79. esd_handle = SDL_LoadObject(esd_library);
  80. if ( esd_handle ) {
  81. esd_loaded = 1;
  82. retval = 0;
  83. for ( i=0; i<SDL_TABLESIZE(esd_functions); ++i ) {
  84. *esd_functions[i].func = SDL_LoadFunction(esd_handle, esd_functions[i].name);
  85. if ( ! esd_functions[i].func ) {
  86. retval = -1;
  87. UnloadESDLibrary();
  88. break;
  89. }
  90. }
  91. }
  92. return retval;
  93. }
  94. #else
  95. static void UnloadESDLibrary()
  96. {
  97. return;
  98. }
  99. static int LoadESDLibrary(void)
  100. {
  101. return 0;
  102. }
  103. #endif /* ESD_DYNAMIC */
  104. /* Audio driver bootstrap functions */
  105. static int Audio_Available(void)
  106. {
  107. int connection;
  108. int available;
  109. available = 0;
  110. if ( LoadESDLibrary() < 0 ) {
  111. return available;
  112. }
  113. connection = SDL_NAME(esd_open_sound)(NULL);
  114. if ( connection >= 0 ) {
  115. available = 1;
  116. SDL_NAME(esd_close)(connection);
  117. }
  118. UnloadESDLibrary();
  119. return(available);
  120. }
  121. static void Audio_DeleteDevice(SDL_AudioDevice *device)
  122. {
  123. free(device->hidden);
  124. free(device);
  125. UnloadESDLibrary();
  126. }
  127. static SDL_AudioDevice *Audio_CreateDevice(int devindex)
  128. {
  129. SDL_AudioDevice *this;
  130. /* Initialize all variables that we clean on shutdown */
  131. LoadESDLibrary();
  132. this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
  133. if ( this ) {
  134. memset(this, 0, (sizeof *this));
  135. this->hidden = (struct SDL_PrivateAudioData *)
  136. malloc((sizeof *this->hidden));
  137. }
  138. if ( (this == NULL) || (this->hidden == NULL) ) {
  139. SDL_OutOfMemory();
  140. if ( this ) {
  141. free(this);
  142. }
  143. return(0);
  144. }
  145. memset(this->hidden, 0, (sizeof *this->hidden));
  146. audio_fd = -1;
  147. /* Set the function pointers */
  148. this->OpenAudio = ESD_OpenAudio;
  149. this->WaitAudio = ESD_WaitAudio;
  150. this->PlayAudio = ESD_PlayAudio;
  151. this->GetAudioBuf = ESD_GetAudioBuf;
  152. this->CloseAudio = ESD_CloseAudio;
  153. this->free = Audio_DeleteDevice;
  154. return this;
  155. }
  156. AudioBootStrap ESD_bootstrap = {
  157. ESD_DRIVER_NAME, "Enlightened Sound Daemon",
  158. Audio_Available, Audio_CreateDevice
  159. };
  160. /* This function waits until it is possible to write a full sound buffer */
  161. static void ESD_WaitAudio(_THIS)
  162. {
  163. Sint32 ticks;
  164. /* Check to see if the thread-parent process is still alive */
  165. { static int cnt = 0;
  166. /* Note that this only works with thread implementations 
  167.    that use a different process id for each thread.
  168. */
  169. if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */
  170. if ( kill(parent, 0) < 0 ) {
  171. this->enabled = 0;
  172. }
  173. }
  174. }
  175. /* Use timer for general audio synchronization */
  176. ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
  177. if ( ticks > 0 ) {
  178. SDL_Delay(ticks);
  179. }
  180. }
  181. static void ESD_PlayAudio(_THIS)
  182. {
  183. int written;
  184. /* Write the audio data, checking for EAGAIN on broken audio drivers */
  185. do {
  186. written = write(audio_fd, mixbuf, mixlen);
  187. if ( (written < 0) && ((errno == 0) || (errno == EAGAIN)) ) {
  188. SDL_Delay(1); /* Let a little CPU time go by */
  189. }
  190. } while ( (written < 0) && 
  191.           ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)) );
  192. /* Set the next write frame */
  193. next_frame += frame_ticks;
  194. /* If we couldn't write, assume fatal error for now */
  195. if ( written < 0 ) {
  196. this->enabled = 0;
  197. }
  198. }
  199. static Uint8 *ESD_GetAudioBuf(_THIS)
  200. {
  201. return(mixbuf);
  202. }
  203. static void ESD_CloseAudio(_THIS)
  204. {
  205. if ( mixbuf != NULL ) {
  206. SDL_FreeAudioMem(mixbuf);
  207. mixbuf = NULL;
  208. }
  209. if ( audio_fd >= 0 ) {
  210. SDL_NAME(esd_close)(audio_fd);
  211. audio_fd = -1;
  212. }
  213. }
  214. /* Try to get the name of the program */
  215. static char *get_progname(void)
  216. {
  217. char *progname = NULL;
  218. #ifdef linux
  219. FILE *fp;
  220. static char temp[BUFSIZ];
  221. sprintf(temp, "/proc/%d/cmdline", getpid());
  222. fp = fopen(temp, "r");
  223. if ( fp != NULL ) {
  224. if ( fgets(temp, sizeof(temp)-1, fp) ) {
  225. progname = strrchr(temp, '/');
  226. if ( progname == NULL ) {
  227. progname = temp;
  228. } else {
  229. progname = progname+1;
  230. }
  231. }
  232. fclose(fp);
  233. }
  234. #endif
  235. return(progname);
  236. }
  237. static int ESD_OpenAudio(_THIS, SDL_AudioSpec *spec)
  238. {
  239. esd_format_t format;
  240. /* Convert audio spec to the ESD audio format */
  241. format = (ESD_STREAM | ESD_PLAY);
  242. switch ( spec->format & 0xFF ) {
  243. case 8:
  244. format |= ESD_BITS8;
  245. break;
  246. case 16:
  247. format |= ESD_BITS16;
  248. break;
  249. default:
  250. SDL_SetError("Unsupported ESD audio format");
  251. return(-1);
  252. }
  253. if ( spec->channels == 1 ) {
  254. format |= ESD_MONO;
  255. } else {
  256. format |= ESD_STEREO;
  257. }
  258. #if 0
  259. spec->samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */
  260. #endif
  261. /* Open a connection to the ESD audio server */
  262. audio_fd = SDL_NAME(esd_play_stream)(format, spec->freq, NULL, get_progname());
  263. if ( audio_fd < 0 ) {
  264. SDL_SetError("Couldn't open ESD connection");
  265. return(-1);
  266. }
  267. /* Calculate the final parameters for this audio specification */
  268. SDL_CalculateAudioSpec(spec);
  269. frame_ticks = (float)(spec->samples*1000)/spec->freq;
  270. next_frame = SDL_GetTicks()+frame_ticks;
  271. /* Allocate mixing buffer */
  272. mixlen = spec->size;
  273. mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
  274. if ( mixbuf == NULL ) {
  275. return(-1);
  276. }
  277. memset(mixbuf, spec->silence, spec->size);
  278. /* Get the parent process id (we're the parent of the audio thread) */
  279. parent = getpid();
  280. /* We're ready to rock and roll. :-) */
  281. return(0);
  282. }
  283. #endif /* ESD_SUPPORT */