123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- #include "precompile.h"
- #include "audiowavfile.h"
- #include "audiocontext.h"
- #include "audiolog.h"
- #include <MMReg.h>
- static int write_wav_header(HANDLE hFile, int clock, int codec_pt)
- {
- WORD wFormat;
- WORD wBitsPerSample;
- DWORD dw;
- DWORD dwByteWritten;
- WAVEFORMATEX fmt;
- DWORD dwFmtSize = sizeof(fmt);
- if (codec_pt == AUDIO_FILE_CODEC_PCM16) {
- wBitsPerSample = 16;
- wFormat = WAVE_FORMAT_PCM;
- dwFmtSize -= 2;
- } else if (codec_pt == AUDIO_FILE_CODEC_ALAW) {
- wBitsPerSample = 8;
- wFormat = WAVE_FORMAT_ALAW;
- } else if (codec_pt == AUDIO_FILE_CODEC_MULAW) {
- wBitsPerSample = 8;
- wFormat = WAVE_FORMAT_MULAW;
- } else if (codec_pt == AUDIO_FILE_CODEC_PCM8) {
- wBitsPerSample = 8;
- wFormat = WAVE_FORMAT_PCM;
- } else {
- return -1;
- }
- dw = 'FFIR'; // riff chunk
- WriteFile(hFile, &dw, sizeof(dw), &dwByteWritten, NULL);
- dw = 0x7fffffff; // riff chunk size
- WriteFile(hFile, &dw, sizeof(dw), &dwByteWritten, NULL);
- dw = 'EVAW'; // format
- WriteFile(hFile, &dw, sizeof(dw), &dwByteWritten, NULL);
- dw = ' tmf'; // fmt subchunk
- WriteFile(hFile, &dw, sizeof(dw), &dwByteWritten, NULL);
- dw = dwFmtSize;
- WriteFile(hFile, &dw, sizeof(dw), &dwByteWritten, NULL);
- fmt.wFormatTag = wFormat;
- fmt.nChannels = 1;
- fmt.nSamplesPerSec = (DWORD)clock;
- fmt.nBlockAlign = 2;
- fmt.wBitsPerSample = wBitsPerSample;
- fmt.cbSize = 0;
- fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * wBitsPerSample / 8;
- WriteFile(hFile, &fmt, dwFmtSize, &dwByteWritten, NULL);
- dw = 'atad'; // data chunk
- WriteFile(hFile, &dw, sizeof(dw), &dwByteWritten, NULL);
- dw = 0x7fffffff; // data chunk size
- WriteFile(hFile, &dw, sizeof(dw), &dwByteWritten, NULL);
- return 0;
- }
- static int write_wav_header_end(HANDLE hFile, int pt)
- {
- DWORD dwByteWritten;
- DWORD dw;
- DWORD dwFileLen;
- DWORD dwDataChunkOffset;
- if (hFile == INVALID_HANDLE_VALUE)
- return -1;
- dwDataChunkOffset = (pt == AUDIO_FILE_CODEC_PCM16 ? 44 : 46);
- SetFilePointer(hFile, 0, NULL, FILE_END);
- dwFileLen = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
- dw = dwFileLen - 8; // riff chunk size
- SetFilePointer(hFile, 4, NULL, FILE_BEGIN);
- WriteFile(hFile, &dw, sizeof(dw), &dwByteWritten, NULL);
- dw = dwFileLen - dwDataChunkOffset; // data chunk size
- SetFilePointer(hFile, dwDataChunkOffset-4, NULL, FILE_BEGIN);
- WriteFile(hFile, &dw, sizeof(dw), &dwByteWritten, NULL);
- SetFilePointer(hFile, 0, NULL, FILE_END);
- return 0;
- }
- static int write_wav_frame(HANDLE hFile, const char *buf, DWORD size)
- {
- DWORD dwByteWritten;
- BOOL bRet = WriteFile(hFile, buf, size, &dwByteWritten, NULL);
- return bRet ? 0 : -1;
- }
- static int read_wav_header(HANDLE hFile, int *clock, int *pt)
- {
- DWORD dw;
- DWORD dwByteRead;
- DWORD dwFileLen;
- DWORD dwFormatLen;
- WAVEFORMATEX fmt;
- SetFilePointer(hFile, 0, NULL, FILE_END);
- dwFileLen = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
- SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
- ReadFile(hFile, &dw, sizeof(dw), &dwByteRead, NULL);
- if (dw != 'FFIR')
- return -1;
- ReadFile(hFile, &dw, sizeof(dw), &dwByteRead, NULL);
- if (dw != dwFileLen-8)
- return -1;
- ReadFile(hFile, &dw, sizeof(dw), &dwByteRead, NULL);
- if (dw != 'EVAW')
- return -1;
- ReadFile(hFile, &dw, sizeof(dw), &dwByteRead, NULL);
- if (dw != ' tmf')
- return -1;
- ReadFile(hFile, &dwFormatLen, sizeof(dwFormatLen), &dwByteRead, NULL);
- if (dwFormatLen < 16)
- return -1;
- ReadFile(hFile, &fmt, dwFormatLen, &dwByteRead, NULL);
- if (fmt.wFormatTag == WAVE_FORMAT_PCM) {
- if (fmt.wBitsPerSample == 16)
- *pt = AUDIO_FILE_CODEC_PCM16;
- else if (fmt.wBitsPerSample == 8)
- *pt = AUDIO_FILE_CODEC_PCM8;
- else
- return -1; // not supported
- } else if (fmt.wFormatTag == WAVE_FORMAT_ALAW) {
- *pt = AUDIO_FILE_CODEC_ALAW;
- } else if (fmt.wFormatTag == WAVE_FORMAT_MULAW) {
- *pt = AUDIO_FILE_CODEC_MULAW;
- } else {
- return -1;
- }
- if (fmt.nChannels != 1)
- return -1;
- if (fmt.nSamplesPerSec == 8000)
- *clock = 8000;
- else if (fmt.nSamplesPerSec == 16000)
- *clock = 16000;
- else
- return -1; // not supported
- ReadFile(hFile, &dw, sizeof(dw), &dwByteRead, NULL);
- while (dw != 'atad') { // is not data chunk
- DWORD tmp;
- ReadFile(hFile, &tmp, sizeof(tmp), &dwByteRead, NULL);
- SetFilePointer(hFile, tmp, NULL, FILE_CURRENT);
- ReadFile(hFile, &dw, sizeof(dw), &dwByteRead, NULL);
- }
- ReadFile(hFile, &dw, sizeof(dw), &dwByteRead, NULL);
- return 0;
- }
- static int read_wav_frame(HANDLE hFile, DWORD dwFrameSize, unsigned char *buf)
- {
- DWORD dwByteRead;
- BOOL bRet;
- bRet = ReadFile(hFile, buf, dwFrameSize, &dwByteRead, NULL);
- if (!bRet || dwByteRead == 0) {
- return -1;
- }
- if (dwByteRead < dwFrameSize) {
- memset(buf+dwByteRead, 0, dwFrameSize-dwByteRead);
- }
- return 0;
- }
- static apr_status_t read_frame(void *self, audioframe_t *frame)
- {
- audiofile_t *audiofile = CONTAINING_RECORD(self, audiofile_t, base);
- audiowavfile_t *audiowavfile = CONTAINING_RECORD(audiofile, audiowavfile_t, base);
- if (audiofile->opt & AUDIO_FILE_OPT_PLAY) {
- int pcnt = FRAME_TIME * audiowavfile->clock / 1000 * (audiowavfile->samplebit / 8);
- if (read_wav_frame(audiofile->file_handle, pcnt, frame->buffer) != 0) {
- if (GetLastError() == 0 && (audiofile->opt&AUDIO_FILE_OPT_LOOP)) {
- SetFilePointer(audiofile->file_handle, 0, NULL, FILE_BEGIN);
- audiostream_raise_event(&audiofile->base, STREAM_EVT_FILE_REPLAY, 0, 0);
- if (read_wav_frame(audiofile->file_handle, pcnt, frame->buffer) != 0) {
- audiostream_raise_event(&audiofile->base, STREAM_EVT_FILE_IOERROR, GetLastError(), 0);
- memset(frame->buffer, 0, pcnt);
- }
- } else {
- audiostream_raise_event(&audiofile->base, STREAM_EVT_FILE_IOERROR, GetLastError(), 0);
- memset(frame->buffer, 0, pcnt);;
- }
- }
- if (audiowavfile->codec_pt == AUDIO_FILE_CODEC_PCM8) {
- unsigned char *src = frame->buffer;
- unsigned char *end_src = frame->buffer + pcnt;
- short *dst = (short*)frame->buffer+pcnt-1;
- while (src != end_src) {
- *dst = (short)(*src << 8) - 32768;
- ++src;
- --dst;
- }
- frame->size = 2 * pcnt;
- } else {
- frame->size = pcnt;
- }
- frame->dtmf = 0;
- } else {
- return APR_ENOTIMPL;
- }
- return APR_SUCCESS;
- }
- static apr_status_t write_frame(void *self, const audioframe_t *frame)
- {
- audiofile_t *audiofile = CONTAINING_RECORD(self, audiofile_t, base);
- audiowavfile_t *audiowavfile = CONTAINING_RECORD(audiofile, audiowavfile_t, base);
- if (audiofile->opt & AUDIO_FILE_OPT_RECORD) {
- if (audiowavfile->codec_pt == AUDIO_FILE_CODEC_PCM8) {
- unsigned char *buf = _alloca(frame->size/2);
- const short *src = (const short *)frame->buffer;
- int i;
- for (i = 0; i < (int)frame->size/2; ++i)
- buf[i] = (src[i] >> 8) + 128;
- if (write_wav_frame(audiofile->file_handle, buf, frame->size/2) != 0) {
- audiostream_raise_event(&audiofile->base, STREAM_EVT_FILE_IOERROR, GetLastError(), 0);
- }
- } else {
- if (write_wav_frame(audiofile->file_handle, frame->buffer, frame->size) != 0) {
- audiostream_raise_event(&audiofile->base, STREAM_EVT_FILE_IOERROR, GetLastError(), 0);
- }
- }
- } else {
- return APR_ENOTIMPL;
- }
- return APR_SUCCESS;
- }
- static audiostream_vtbl_t g_stream_vtbl = {
- &read_frame,
- &write_frame,
- };
- apr_status_t audiowavfile_create(apr_pool_t *pool,
- audioengine_t *engine,
- const char *file,
- int opt,
- int clock,
- int codec_pt, // one of AUDIO_FILE_CODEC_xxx
- audiowavfile_t **p_file)
- {
- apr_status_t status;
- audiowavfile_t *audiofile;
- audiofile = apr_palloc(pool, sizeof(audiowavfile_t));
- status = audiofile_init(pool, engine, file, opt, &audiofile->base);
- if (status != APR_SUCCESS) {
- return status;
- }
- audiofile->base.base.vtbl = &g_stream_vtbl;
- audiofile->clock = clock;
- audiofile->codec_pt = codec_pt;
- audiofile->samplebit = (codec_pt == AUDIO_FILE_CODEC_PCM16) ? 16 : 8;
- if (opt & AUDIO_FILE_OPT_RECORD) {
- if (write_wav_header(audiofile->base.file_handle, clock, codec_pt) != 0) {
- CloseHandle(audiofile->base.file_handle);
- apr_pool_destroy(pool);
- return APR_EGENERAL;
- }
- } else if (opt & AUDIO_FILE_OPT_PLAY) {
- if (read_wav_header(audiofile->base.file_handle, &clock, &audiofile->codec_pt) != 0) {
- CloseHandle(audiofile->base.file_handle);
- apr_pool_destroy(pool);
- return APR_EGENERAL;
- }
- }
- *p_file = audiofile;
- return APR_SUCCESS;
- }
- void audiowavfile_destroy(audiowavfile_t *audiofile)
- {
- if (audiofile->base.opt & AUDIO_FILE_OPT_RECORD) {
- write_wav_header_end(audiofile->base.file_handle, audiofile->codec_pt);
- }
- audiofile_term(&audiofile->base);
- }
|