snd_linux.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. #include <unistd.h>
  2. #include <fcntl.h>
  3. #include <stdlib.h>
  4. #include <sys/types.h>
  5. #include <sys/ioctl.h>
  6. #include <sys/mman.h>
  7. #include <sys/shm.h>
  8. #include <sys/wait.h>
  9. #include <linux/soundcard.h>
  10. #include <stdio.h>
  11. #include "../client/client.h"
  12. #include "../client/snd_loc.h"
  13. int audio_fd;
  14. int snd_inited;
  15. cvar_t *sndbits;
  16. cvar_t *sndspeed;
  17. cvar_t *sndchannels;
  18. cvar_t *snddevice;
  19. static int tryrates[] = { 11025, 22051, 44100, 8000 };
  20. qboolean SNDDMA_Init(void)
  21. {
  22. int rc;
  23. int fmt;
  24. int tmp;
  25. int i;
  26. char *s;
  27. struct audio_buf_info info;
  28. int caps;
  29. extern uid_t saved_euid;
  30. if (snd_inited)
  31. return;
  32. if (!snddevice) {
  33. sndbits = Cvar_Get("sndbits", "16", CVAR_ARCHIVE);
  34. sndspeed = Cvar_Get("sndspeed", "0", CVAR_ARCHIVE);
  35. sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE);
  36. snddevice = Cvar_Get("snddevice", "/dev/dsp", CVAR_ARCHIVE);
  37. }
  38. // open /dev/dsp, confirm capability to mmap, and get size of dma buffer
  39. if (!audio_fd) {
  40. seteuid(saved_euid);
  41. audio_fd = open(snddevice->string, O_RDWR);
  42. seteuid(getuid());
  43. if (audio_fd < 0)
  44. {
  45. perror(snddevice->string);
  46. Com_Printf("Could not open %s\n", snddevice->string);
  47. return 0;
  48. }
  49. }
  50. rc = ioctl(audio_fd, SNDCTL_DSP_RESET, 0);
  51. if (rc < 0)
  52. {
  53. perror(snddevice->string);
  54. Com_Printf("Could not reset %s\n", snddevice->string);
  55. close(audio_fd);
  56. return 0;
  57. }
  58. if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &caps)==-1)
  59. {
  60. perror(snddevice->string);
  61. Com_Printf("Sound driver too old\n");
  62. close(audio_fd);
  63. return 0;
  64. }
  65. if (!(caps & DSP_CAP_TRIGGER) || !(caps & DSP_CAP_MMAP))
  66. {
  67. Com_Printf("Sorry but your soundcard can't do this\n");
  68. close(audio_fd);
  69. return 0;
  70. }
  71. if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info)==-1)
  72. {
  73. perror("GETOSPACE");
  74. Com_Printf("Um, can't do GETOSPACE?\n");
  75. close(audio_fd);
  76. return 0;
  77. }
  78. // set sample bits & speed
  79. dma.samplebits = (int)sndbits->value;
  80. if (dma.samplebits != 16 && dma.samplebits != 8)
  81. {
  82. ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt);
  83. if (fmt & AFMT_S16_LE) dma.samplebits = 16;
  84. else if (fmt & AFMT_U8) dma.samplebits = 8;
  85. }
  86. dma.speed = (int)sndspeed->value;
  87. if (!dma.speed) {
  88. for (i=0 ; i<sizeof(tryrates)/4 ; i++)
  89. if (!ioctl(audio_fd, SNDCTL_DSP_SPEED, &tryrates[i])) break;
  90. dma.speed = tryrates[i];
  91. }
  92. dma.channels = (int)sndchannels->value;
  93. if (dma.channels < 1 || dma.channels > 2)
  94. dma.channels = 2;
  95. dma.samples = info.fragstotal * info.fragsize / (dma.samplebits/8);
  96. dma.submission_chunk = 1;
  97. // memory map the dma buffer
  98. if (!dma.buffer)
  99. dma.buffer = (unsigned char *) mmap(NULL, info.fragstotal
  100. * info.fragsize, PROT_WRITE, MAP_FILE|MAP_SHARED, audio_fd, 0);
  101. if (!dma.buffer)
  102. {
  103. perror(snddevice->string);
  104. Com_Printf("Could not mmap %s\n", snddevice->string);
  105. close(audio_fd);
  106. return 0;
  107. }
  108. tmp = 0;
  109. if (dma.channels == 2)
  110. tmp = 1;
  111. rc = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp);
  112. if (rc < 0)
  113. {
  114. perror(snddevice->string);
  115. Com_Printf("Could not set %s to stereo=%d", snddevice->string, dma.channels);
  116. close(audio_fd);
  117. return 0;
  118. }
  119. if (tmp)
  120. dma.channels = 2;
  121. else
  122. dma.channels = 1;
  123. rc = ioctl(audio_fd, SNDCTL_DSP_SPEED, &dma.speed);
  124. if (rc < 0)
  125. {
  126. perror(snddevice->string);
  127. Com_Printf("Could not set %s speed to %d", snddevice->string, dma.speed);
  128. close(audio_fd);
  129. return 0;
  130. }
  131. if (dma.samplebits == 16)
  132. {
  133. rc = AFMT_S16_LE;
  134. rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
  135. if (rc < 0)
  136. {
  137. perror(snddevice->string);
  138. Com_Printf("Could not support 16-bit data. Try 8-bit.\n");
  139. close(audio_fd);
  140. return 0;
  141. }
  142. }
  143. else if (dma.samplebits == 8)
  144. {
  145. rc = AFMT_U8;
  146. rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
  147. if (rc < 0)
  148. {
  149. perror(snddevice->string);
  150. Com_Printf("Could not support 8-bit data.\n");
  151. close(audio_fd);
  152. return 0;
  153. }
  154. }
  155. else
  156. {
  157. perror(snddevice->string);
  158. Com_Printf("%d-bit sound not supported.", dma.samplebits);
  159. close(audio_fd);
  160. return 0;
  161. }
  162. // toggle the trigger & start her up
  163. tmp = 0;
  164. rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
  165. if (rc < 0)
  166. {
  167. perror(snddevice->string);
  168. Com_Printf("Could not toggle.\n");
  169. close(audio_fd);
  170. return 0;
  171. }
  172. tmp = PCM_ENABLE_OUTPUT;
  173. rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
  174. if (rc < 0)
  175. {
  176. perror(snddevice->string);
  177. Com_Printf("Could not toggle.\n");
  178. close(audio_fd);
  179. return 0;
  180. }
  181. dma.samplepos = 0;
  182. snd_inited = 1;
  183. return 1;
  184. }
  185. int SNDDMA_GetDMAPos(void)
  186. {
  187. struct count_info count;
  188. if (!snd_inited) return 0;
  189. if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &count)==-1)
  190. {
  191. perror(snddevice->string);
  192. Com_Printf("Uh, sound dead.\n");
  193. close(audio_fd);
  194. snd_inited = 0;
  195. return 0;
  196. }
  197. // dma.samplepos = (count.bytes / (dma.samplebits / 8)) & (dma.samples-1);
  198. // fprintf(stderr, "%d \r", count.ptr);
  199. dma.samplepos = count.ptr / (dma.samplebits / 8);
  200. return dma.samplepos;
  201. }
  202. void SNDDMA_Shutdown(void)
  203. {
  204. #if 0
  205. if (snd_inited)
  206. {
  207. close(audio_fd);
  208. snd_inited = 0;
  209. }
  210. #endif
  211. }
  212. /*
  213. ==============
  214. SNDDMA_Submit
  215. Send sound to device if buffer isn't really the dma buffer
  216. ===============
  217. */
  218. void SNDDMA_Submit(void)
  219. {
  220. }
  221. void SNDDMA_BeginPainting (void)
  222. {
  223. }