audiowavfile.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. #include "precompile.h"
  2. #include "audiowavfile.h"
  3. #include "audiocontext.h"
  4. #include "audiolog.h"
  5. #include <MMReg.h>
  6. static int write_wav_header(HANDLE hFile, int clock, int codec_pt)
  7. {
  8. WORD wFormat;
  9. WORD wBitsPerSample;
  10. DWORD dw;
  11. DWORD dwByteWritten;
  12. WAVEFORMATEX fmt;
  13. DWORD dwFmtSize = sizeof(fmt);
  14. if (codec_pt == AUDIO_FILE_CODEC_PCM16) {
  15. wBitsPerSample = 16;
  16. wFormat = WAVE_FORMAT_PCM;
  17. dwFmtSize -= 2;
  18. } else if (codec_pt == AUDIO_FILE_CODEC_ALAW) {
  19. wBitsPerSample = 8;
  20. wFormat = WAVE_FORMAT_ALAW;
  21. } else if (codec_pt == AUDIO_FILE_CODEC_MULAW) {
  22. wBitsPerSample = 8;
  23. wFormat = WAVE_FORMAT_MULAW;
  24. } else if (codec_pt == AUDIO_FILE_CODEC_PCM8) {
  25. wBitsPerSample = 8;
  26. wFormat = WAVE_FORMAT_PCM;
  27. } else {
  28. return -1;
  29. }
  30. dw = 'FFIR'; // riff chunk
  31. WriteFile(hFile, &dw, sizeof(dw), &dwByteWritten, NULL);
  32. dw = 0x7fffffff; // riff chunk size
  33. WriteFile(hFile, &dw, sizeof(dw), &dwByteWritten, NULL);
  34. dw = 'EVAW'; // format
  35. WriteFile(hFile, &dw, sizeof(dw), &dwByteWritten, NULL);
  36. dw = ' tmf'; // fmt subchunk
  37. WriteFile(hFile, &dw, sizeof(dw), &dwByteWritten, NULL);
  38. dw = dwFmtSize;
  39. WriteFile(hFile, &dw, sizeof(dw), &dwByteWritten, NULL);
  40. fmt.wFormatTag = wFormat;
  41. fmt.nChannels = 1;
  42. fmt.nSamplesPerSec = (DWORD)clock;
  43. fmt.nBlockAlign = 2;
  44. fmt.wBitsPerSample = wBitsPerSample;
  45. fmt.cbSize = 0;
  46. fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * wBitsPerSample / 8;
  47. WriteFile(hFile, &fmt, dwFmtSize, &dwByteWritten, NULL);
  48. dw = 'atad'; // data chunk
  49. WriteFile(hFile, &dw, sizeof(dw), &dwByteWritten, NULL);
  50. dw = 0x7fffffff; // data chunk size
  51. WriteFile(hFile, &dw, sizeof(dw), &dwByteWritten, NULL);
  52. return 0;
  53. }
  54. static int write_wav_header_end(HANDLE hFile, int pt)
  55. {
  56. DWORD dwByteWritten;
  57. DWORD dw;
  58. DWORD dwFileLen;
  59. DWORD dwDataChunkOffset;
  60. if (hFile == INVALID_HANDLE_VALUE)
  61. return -1;
  62. dwDataChunkOffset = (pt == AUDIO_FILE_CODEC_PCM16 ? 44 : 46);
  63. SetFilePointer(hFile, 0, NULL, FILE_END);
  64. dwFileLen = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
  65. dw = dwFileLen - 8; // riff chunk size
  66. SetFilePointer(hFile, 4, NULL, FILE_BEGIN);
  67. WriteFile(hFile, &dw, sizeof(dw), &dwByteWritten, NULL);
  68. dw = dwFileLen - dwDataChunkOffset; // data chunk size
  69. SetFilePointer(hFile, dwDataChunkOffset-4, NULL, FILE_BEGIN);
  70. WriteFile(hFile, &dw, sizeof(dw), &dwByteWritten, NULL);
  71. SetFilePointer(hFile, 0, NULL, FILE_END);
  72. return 0;
  73. }
  74. static int write_wav_frame(HANDLE hFile, const char *buf, DWORD size)
  75. {
  76. DWORD dwByteWritten;
  77. BOOL bRet = WriteFile(hFile, buf, size, &dwByteWritten, NULL);
  78. return bRet ? 0 : -1;
  79. }
  80. static int read_wav_header(HANDLE hFile, int *clock, int *pt)
  81. {
  82. DWORD dw;
  83. DWORD dwByteRead;
  84. DWORD dwFileLen;
  85. DWORD dwFormatLen;
  86. WAVEFORMATEX fmt;
  87. SetFilePointer(hFile, 0, NULL, FILE_END);
  88. dwFileLen = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
  89. SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
  90. ReadFile(hFile, &dw, sizeof(dw), &dwByteRead, NULL);
  91. if (dw != 'FFIR')
  92. return -1;
  93. ReadFile(hFile, &dw, sizeof(dw), &dwByteRead, NULL);
  94. if (dw != dwFileLen-8)
  95. return -1;
  96. ReadFile(hFile, &dw, sizeof(dw), &dwByteRead, NULL);
  97. if (dw != 'EVAW')
  98. return -1;
  99. ReadFile(hFile, &dw, sizeof(dw), &dwByteRead, NULL);
  100. if (dw != ' tmf')
  101. return -1;
  102. ReadFile(hFile, &dwFormatLen, sizeof(dwFormatLen), &dwByteRead, NULL);
  103. if (dwFormatLen < 16)
  104. return -1;
  105. ReadFile(hFile, &fmt, dwFormatLen, &dwByteRead, NULL);
  106. if (fmt.wFormatTag == WAVE_FORMAT_PCM) {
  107. if (fmt.wBitsPerSample == 16)
  108. *pt = AUDIO_FILE_CODEC_PCM16;
  109. else if (fmt.wBitsPerSample == 8)
  110. *pt = AUDIO_FILE_CODEC_PCM8;
  111. else
  112. return -1; // not supported
  113. } else if (fmt.wFormatTag == WAVE_FORMAT_ALAW) {
  114. *pt = AUDIO_FILE_CODEC_ALAW;
  115. } else if (fmt.wFormatTag == WAVE_FORMAT_MULAW) {
  116. *pt = AUDIO_FILE_CODEC_MULAW;
  117. } else {
  118. return -1;
  119. }
  120. if (fmt.nChannels != 1)
  121. return -1;
  122. if (fmt.nSamplesPerSec == 8000)
  123. *clock = 8000;
  124. else if (fmt.nSamplesPerSec == 16000)
  125. *clock = 16000;
  126. else
  127. return -1; // not supported
  128. ReadFile(hFile, &dw, sizeof(dw), &dwByteRead, NULL);
  129. while (dw != 'atad') { // is not data chunk
  130. DWORD tmp;
  131. ReadFile(hFile, &tmp, sizeof(tmp), &dwByteRead, NULL);
  132. SetFilePointer(hFile, tmp, NULL, FILE_CURRENT);
  133. ReadFile(hFile, &dw, sizeof(dw), &dwByteRead, NULL);
  134. }
  135. ReadFile(hFile, &dw, sizeof(dw), &dwByteRead, NULL);
  136. return 0;
  137. }
  138. static int read_wav_frame(HANDLE hFile, DWORD dwFrameSize, unsigned char *buf)
  139. {
  140. DWORD dwByteRead;
  141. BOOL bRet;
  142. bRet = ReadFile(hFile, buf, dwFrameSize, &dwByteRead, NULL);
  143. if (!bRet || dwByteRead == 0) {
  144. return -1;
  145. }
  146. if (dwByteRead < dwFrameSize) {
  147. memset(buf+dwByteRead, 0, dwFrameSize-dwByteRead);
  148. }
  149. return 0;
  150. }
  151. static apr_status_t read_frame(void *self, audioframe_t *frame)
  152. {
  153. audiofile_t *audiofile = CONTAINING_RECORD(self, audiofile_t, base);
  154. audiowavfile_t *audiowavfile = CONTAINING_RECORD(audiofile, audiowavfile_t, base);
  155. if (audiofile->opt & AUDIO_FILE_OPT_PLAY) {
  156. int pcnt = FRAME_TIME * audiowavfile->clock / 1000 * (audiowavfile->samplebit / 8);
  157. if (read_wav_frame(audiofile->file_handle, pcnt, frame->buffer) != 0) {
  158. if (GetLastError() == 0 && (audiofile->opt&AUDIO_FILE_OPT_LOOP)) {
  159. SetFilePointer(audiofile->file_handle, 0, NULL, FILE_BEGIN);
  160. audiostream_raise_event(&audiofile->base, STREAM_EVT_FILE_REPLAY, 0, 0);
  161. if (read_wav_frame(audiofile->file_handle, pcnt, frame->buffer) != 0) {
  162. audiostream_raise_event(&audiofile->base, STREAM_EVT_FILE_IOERROR, GetLastError(), 0);
  163. memset(frame->buffer, 0, pcnt);
  164. }
  165. } else {
  166. audiostream_raise_event(&audiofile->base, STREAM_EVT_FILE_IOERROR, GetLastError(), 0);
  167. memset(frame->buffer, 0, pcnt);;
  168. }
  169. }
  170. if (audiowavfile->codec_pt == AUDIO_FILE_CODEC_PCM8) {
  171. unsigned char *src = frame->buffer;
  172. unsigned char *end_src = frame->buffer + pcnt;
  173. short *dst = (short*)frame->buffer+pcnt-1;
  174. while (src != end_src) {
  175. *dst = (short)(*src << 8) - 32768;
  176. ++src;
  177. --dst;
  178. }
  179. frame->size = 2 * pcnt;
  180. } else {
  181. frame->size = pcnt;
  182. }
  183. frame->dtmf = 0;
  184. } else {
  185. return APR_ENOTIMPL;
  186. }
  187. return APR_SUCCESS;
  188. }
  189. static apr_status_t write_frame(void *self, const audioframe_t *frame)
  190. {
  191. audiofile_t *audiofile = CONTAINING_RECORD(self, audiofile_t, base);
  192. audiowavfile_t *audiowavfile = CONTAINING_RECORD(audiofile, audiowavfile_t, base);
  193. if (audiofile->opt & AUDIO_FILE_OPT_RECORD) {
  194. if (audiowavfile->codec_pt == AUDIO_FILE_CODEC_PCM8) {
  195. unsigned char *buf = _alloca(frame->size/2);
  196. const short *src = (const short *)frame->buffer;
  197. int i;
  198. for (i = 0; i < (int)frame->size/2; ++i)
  199. buf[i] = (src[i] >> 8) + 128;
  200. if (write_wav_frame(audiofile->file_handle, buf, frame->size/2) != 0) {
  201. audiostream_raise_event(&audiofile->base, STREAM_EVT_FILE_IOERROR, GetLastError(), 0);
  202. }
  203. } else {
  204. if (write_wav_frame(audiofile->file_handle, frame->buffer, frame->size) != 0) {
  205. audiostream_raise_event(&audiofile->base, STREAM_EVT_FILE_IOERROR, GetLastError(), 0);
  206. }
  207. }
  208. } else {
  209. return APR_ENOTIMPL;
  210. }
  211. return APR_SUCCESS;
  212. }
  213. static audiostream_vtbl_t g_stream_vtbl = {
  214. &read_frame,
  215. &write_frame,
  216. };
  217. apr_status_t audiowavfile_create(apr_pool_t *pool,
  218. audioengine_t *engine,
  219. const char *file,
  220. int opt,
  221. int clock,
  222. int codec_pt, // one of AUDIO_FILE_CODEC_xxx
  223. audiowavfile_t **p_file)
  224. {
  225. apr_status_t status;
  226. audiowavfile_t *audiofile;
  227. audiofile = apr_palloc(pool, sizeof(audiowavfile_t));
  228. status = audiofile_init(pool, engine, file, opt, &audiofile->base);
  229. if (status != APR_SUCCESS) {
  230. return status;
  231. }
  232. audiofile->base.base.vtbl = &g_stream_vtbl;
  233. audiofile->clock = clock;
  234. audiofile->codec_pt = codec_pt;
  235. audiofile->samplebit = (codec_pt == AUDIO_FILE_CODEC_PCM16) ? 16 : 8;
  236. if (opt & AUDIO_FILE_OPT_RECORD) {
  237. if (write_wav_header(audiofile->base.file_handle, clock, codec_pt) != 0) {
  238. CloseHandle(audiofile->base.file_handle);
  239. apr_pool_destroy(pool);
  240. return APR_EGENERAL;
  241. }
  242. } else if (opt & AUDIO_FILE_OPT_PLAY) {
  243. if (read_wav_header(audiofile->base.file_handle, &clock, &audiofile->codec_pt) != 0) {
  244. CloseHandle(audiofile->base.file_handle);
  245. apr_pool_destroy(pool);
  246. return APR_EGENERAL;
  247. }
  248. }
  249. *p_file = audiofile;
  250. return APR_SUCCESS;
  251. }
  252. void audiowavfile_destroy(audiowavfile_t *audiofile)
  253. {
  254. if (audiofile->base.opt & AUDIO_FILE_OPT_RECORD) {
  255. write_wav_header_end(audiofile->base.file_handle, audiofile->codec_pt);
  256. }
  257. audiofile_term(&audiofile->base);
  258. }