drv_esd.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:8k
源码类别:

Windows CE

开发平台:

C/C++

  1. /* MikMod sound library
  2. (c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
  3. complete list.
  4. This library is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Library General Public License as
  6. published by the Free Software Foundation; either version 2 of
  7. the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. GNU Library General Public License for more details.
  13.  
  14. You should have received a copy of the GNU Library General Public
  15. License along with this library; if not, write to the Free Software
  16. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  17. 02111-1307, USA.
  18. */
  19. /*==============================================================================
  20.   $Id: drv_esd.c,v 1.3 2004/01/31 22:39:40 raph Exp $
  21.   Driver for the Enlightened sound daemon (EsounD)
  22. ==============================================================================*/
  23. /*
  24. You should set the hostname of the machine running esd in the environment
  25. variable 'ESPEAKER'. If this variable is not set, localhost is used.
  26. */
  27. #ifdef HAVE_CONFIG_H
  28. #include "config.h"
  29. #endif
  30. #include "mikmod_internals.h"
  31. #ifdef DRV_ESD
  32. #ifdef HAVE_UNISTD_H
  33. #include <unistd.h>
  34. #endif
  35. #ifdef MIKMOD_DYNAMIC
  36. #include <dlfcn.h>
  37. #endif
  38. #include <errno.h>
  39. #ifdef HAVE_FCNTL_H
  40. #include <fcntl.h>
  41. #endif
  42. #include <stdlib.h>
  43. #include <signal.h>
  44. #include <time.h>
  45. #include <esd.h>
  46. #ifdef MIKMOD_DYNAMIC
  47. /* runtime link with libesd */
  48. /* note that since we only need the network part of EsounD, we don't need to
  49.    load libasound.so or libaudiofile.so as well */
  50. static int(*esd_closestream)(int);
  51. static int(*esd_playstream)(esd_format_t,int,char*,char*);
  52. static void* libesd=NULL;
  53. #ifndef HAVE_RTLD_GLOBAL
  54. #define RTLD_GLOBAL (0)
  55. #endif
  56. #else /* MIKMOD_DYNAMIC */
  57. /* compile-time link with libesd */
  58. #define esd_closestream esd_close
  59. #define esd_playstream esd_play_stream
  60. #endif
  61. #ifdef HAVE_SETENV
  62. #define SETENV setenv("ESD_NO_SPAWN","1",0)
  63. #else
  64. #define SETENV putenv("ESD_NO_SPAWN=1")
  65. #endif
  66. static int sndfd=-1;
  67. static esd_format_t format;
  68. static SBYTE *audiobuffer=NULL;
  69. static CHAR *espeaker=NULL;
  70. #ifdef MIKMOD_DYNAMIC
  71. /* straight from audio.c in esd sources */
  72. esd_format_t esd_audio_format=ESD_BITS16|ESD_STEREO;
  73. int esd_audio_rate=ESD_DEFAULT_RATE;
  74. #ifdef MIKMOD_DYNAMIC_ESD_NEEDS_ALSA
  75. /* straight from audio_alsa.c in esd 0.2.[678] sources
  76.    non-static variables that should be static are a *bad* thing... */
  77. void *handle;
  78. int writes;
  79. #endif
  80. static BOOL ESD_Link(void)
  81. {
  82. if (libesd) return 0;
  83. /* load libesd.so */
  84. libesd=dlopen("libesd.so",RTLD_LAZY|RTLD_GLOBAL);
  85. if (!libesd) return 1;
  86. /* resolve function references */
  87. if (!(esd_closestream=dlsym(libesd,"esd_close"))) return 1;
  88. if (!(esd_playstream=dlsym(libesd,"esd_play_stream"))) return 1;
  89. return 0;
  90. }
  91. static void ESD_Unlink(void)
  92. {
  93. #ifdef HAVE_ESD_CLOSE
  94. esd_closestream=NULL;
  95. #endif
  96. esd_playstream=NULL;
  97. if (libesd) {
  98. dlclose(libesd);
  99. libesd=NULL;
  100. }
  101. }
  102. #endif
  103. /* I hope to have this function integrated into libesd someday...*/
  104. static ssize_t esd_writebuf(int fd,const void *buffer,size_t count)
  105. {
  106. ssize_t start=0;
  107. while (start<count) {
  108. ssize_t res;
  109. res=write(fd,(char*)buffer+start,count-start);
  110. if (res<0) {
  111. /* connection lost */
  112. if (errno==EPIPE)
  113. return -1-start;
  114. } else
  115. start+=res;
  116. }
  117. return start;
  118. }
  119. static void ESD_CommandLine(CHAR *cmdline)
  120. {
  121. CHAR *ptr=MD_GetAtom("machine",cmdline,0);
  122. if (ptr) {
  123. if (espeaker) free(espeaker);
  124. espeaker=ptr;
  125. }
  126. }
  127. static BOOL ESD_IsThere(void)
  128. {
  129. int fd,retval;
  130. #ifdef MIKMOD_DYNAMIC
  131. if (ESD_Link()) return 0;
  132. #endif
  133. /* Try to esablish a connection with default esd settings, but we don't
  134.    want esdlib to spawn esd if esd is not running ! */
  135. if (SETENV)
  136. retval=0;
  137. else {
  138. if ((fd=esd_playstream(ESD_BITS16|ESD_STEREO|ESD_STREAM|ESD_PLAY,
  139.                        ESD_DEFAULT_RATE,espeaker,"libmikmod"))<0)
  140. retval=0;
  141. else {
  142. esd_closestream(fd);
  143. retval=1;
  144. }
  145. }
  146. #ifdef MIKMOD_DYNAMIC
  147. ESD_Unlink();
  148. #endif
  149. return retval;
  150. }
  151. static BOOL ESD_Init_internal(void)
  152. {
  153. format=(md_mode&DMODE_16BITS?ESD_BITS16:ESD_BITS8)|
  154.        (md_mode&DMODE_STEREO?ESD_STEREO:ESD_MONO)|ESD_STREAM|ESD_PLAY;
  155. if (md_mixfreq > ESD_DEFAULT_RATE)
  156. md_mixfreq = ESD_DEFAULT_RATE;
  157. /* make sure we can open an esd stream with our parameters */
  158. if (!(SETENV)) {
  159. if ((sndfd=esd_playstream(format,md_mixfreq,espeaker,"libmikmod"))<0) {
  160. _mm_errno=MMERR_OPENING_AUDIO;
  161. return 1;
  162. }
  163. } else {
  164. _mm_errno=MMERR_OUT_OF_MEMORY;
  165. return 1;
  166. }
  167. if (!(audiobuffer=(SBYTE*)_mm_malloc(ESD_BUF_SIZE*sizeof(char))))
  168. return 1;
  169. return VC_Init();
  170. }
  171. static BOOL ESD_Init(void)
  172. {
  173. #ifdef MIKMOD_DYNAMIC
  174. if (ESD_Link()) {
  175. _mm_errno=MMERR_DYNAMIC_LINKING;
  176. return 1;
  177. }
  178. #endif
  179. return ESD_Init_internal();
  180. }
  181. static void ESD_Exit_internal(void)
  182. {
  183. VC_Exit();
  184. _mm_free(audiobuffer);
  185. if (sndfd>=0) {
  186. esd_closestream(sndfd);
  187. sndfd=-1;
  188. signal(SIGPIPE,SIG_DFL);
  189. }
  190. }
  191. static void ESD_Exit(void)
  192. {
  193. ESD_Exit_internal();
  194. #ifdef MIKMOD_DYNAMIC
  195. ESD_Unlink();
  196. #endif
  197. }
  198. static void ESD_Update_internal(int count)
  199. {
  200. static time_t losttime;
  201. if (sndfd>=0) {
  202. if (esd_writebuf(sndfd,audiobuffer,count)<0) {
  203. /* if we lost our connection with esd, clean up and work as the
  204.    nosound driver until we can reconnect */
  205. esd_closestream(sndfd);
  206. sndfd=-1;
  207. signal(SIGPIPE,SIG_DFL);
  208. losttime=time(NULL);
  209. }
  210. } else {
  211. /* an alarm would be better, but then the library user could not use
  212.    alarm(2) himself... */
  213. if (time(NULL)-losttime>=5) {
  214. losttime=time(NULL);
  215. /* Attempt to reconnect every 5 seconds */
  216. if (!(SETENV))
  217. if ((sndfd=esd_playstream(format,md_mixfreq,espeaker,"libmikmod"))>=0) {
  218. VC_SilenceBytes(audiobuffer,ESD_BUF_SIZE);
  219. esd_writebuf(sndfd,audiobuffer,ESD_BUF_SIZE);
  220. }
  221. }
  222. }
  223. }
  224. static void ESD_Update(void)
  225. {
  226. ESD_Update_internal(VC_WriteBytes(audiobuffer,ESD_BUF_SIZE));
  227. }
  228. static void ESD_Pause(void)
  229. {
  230. ESD_Update_internal(VC_SilenceBytes(audiobuffer,ESD_BUF_SIZE));
  231. }
  232. static BOOL ESD_PlayStart(void)
  233. {
  234. if (sndfd<0)
  235. if (!(SETENV))
  236. if ((sndfd=esd_playstream(format,md_mixfreq,espeaker,"libmikmod"))<0) {
  237. _mm_errno=MMERR_OPENING_AUDIO;
  238. return 1;
  239. }
  240. /* since the default behaviour of SIGPIPE on most Unices is to kill the
  241.    program, we'll prefer handle EPIPE ourselves should the esd die - recent
  242.    esdlib use a do-nothing handler, which prevents us from receiving EPIPE,
  243.    so we override this */
  244. signal(SIGPIPE,SIG_IGN);
  245. /* silence buffers */
  246. VC_SilenceBytes(audiobuffer,ESD_BUF_SIZE);
  247. esd_writebuf(sndfd,audiobuffer,ESD_BUF_SIZE);
  248. return VC_PlayStart();
  249. }
  250. static void ESD_PlayStop(void)
  251. {
  252. if (sndfd>=0) {
  253. /* silence buffers */
  254. VC_SilenceBytes(audiobuffer,ESD_BUF_SIZE);
  255. esd_writebuf(sndfd,audiobuffer,ESD_BUF_SIZE);
  256. signal(SIGPIPE,SIG_DFL);
  257. }
  258. VC_PlayStop();
  259. }
  260. static BOOL ESD_Reset(void)
  261. {
  262. ESD_Exit_internal();
  263. return ESD_Init_internal();
  264. }
  265. MIKMODAPI MDRIVER drv_esd={
  266. NULL,
  267. "Enlightened sound daemon",
  268. /* use the same version number as the EsounD release it works best with */
  269. "Enlightened sound daemon (EsounD) driver v0.2.23",
  270. 0,255,
  271. "esd",
  272. "machine:t::Audio server machine (hostname:port)n",
  273. ESD_CommandLine,
  274. ESD_IsThere,
  275. VC_SampleLoad,
  276. VC_SampleUnload,
  277. VC_SampleSpace,
  278. VC_SampleLength,
  279. ESD_Init,
  280. ESD_Exit,
  281. ESD_Reset,
  282. VC_SetNumVoices,
  283. ESD_PlayStart,
  284. ESD_PlayStop,
  285. ESD_Update,
  286. ESD_Pause,
  287. VC_VoiceSetVolume,
  288. VC_VoiceGetVolume,
  289. VC_VoiceSetFrequency,
  290. VC_VoiceGetFrequency,
  291. VC_VoiceSetPanning,
  292. VC_VoiceGetPanning,
  293. VC_VoicePlay,
  294. VC_VoiceStop,
  295. VC_VoiceStopped,
  296. VC_VoiceGetPosition,
  297. VC_VoiceRealVolume
  298. };
  299. #else
  300. MISSING(drv_esd);
  301. #endif
  302. /* ex:set ts=4: */