diff options
author | Benny Prijono <bennylp@teluu.com> | 2009-03-12 18:11:37 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2009-03-12 18:11:37 +0000 |
commit | 1dacdee696b7591a6dcc0b3c1d0f41573e473168 (patch) | |
tree | 302b09dcd989c0c05cf09f6aebaa63d870b421b9 /pjmedia/src/pjmedia/wmme_sound.c | |
parent | ba9d8ca28eb209571c0bd6a080a8bb03d0fa2d33 (diff) |
(Major) Task #737 and #738: integration of APS-Direct and Audiodev from aps-direct branch to trunk.
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2506 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia/src/pjmedia/wmme_sound.c')
-rw-r--r-- | pjmedia/src/pjmedia/wmme_sound.c | 1008 |
1 files changed, 0 insertions, 1008 deletions
diff --git a/pjmedia/src/pjmedia/wmme_sound.c b/pjmedia/src/pjmedia/wmme_sound.c deleted file mode 100644 index 8f94660c..00000000 --- a/pjmedia/src/pjmedia/wmme_sound.c +++ /dev/null @@ -1,1008 +0,0 @@ -#include <pjmedia/sound.h> -#include <pjmedia/errno.h> -#include <pj/assert.h> -#include <pj/log.h> -#include <pj/os.h> -#include <pj/string.h> - -#if PJMEDIA_SOUND_IMPLEMENTATION == PJMEDIA_SOUND_WIN32_MME_SOUND - -#ifdef _MSC_VER -# pragma warning(push, 3) -#endif - -#include <windows.h> -#include <mmsystem.h> - -#ifdef _MSC_VER -# pragma warning(pop) -#endif - -#if defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0 -# pragma comment(lib, "Coredll.lib") -#elif defined(_MSC_VER) -# pragma comment(lib, "winmm.lib") -#endif - - -#define THIS_FILE "wmme_sound.c" -#define BITS_PER_SAMPLE 16 -#define BYTES_PER_SAMPLE (BITS_PER_SAMPLE/8) - -#define MAX_PACKET_BUFFER_COUNT 32 -#define MAX_HARDWARE 16 - -struct wmme_dev_info -{ - pjmedia_snd_dev_info info; - unsigned deviceId; -}; - -static unsigned dev_count; -static struct wmme_dev_info dev_info[MAX_HARDWARE]; -static pj_bool_t snd_initialized = PJ_FALSE; - -/* Latency settings */ -static unsigned snd_input_latency = PJMEDIA_SND_DEFAULT_REC_LATENCY; -static unsigned snd_output_latency = PJMEDIA_SND_DEFAULT_PLAY_LATENCY; - - -/* Individual WMME capture/playback stream descriptor */ -struct wmme_stream -{ - union - { - HWAVEIN In; - HWAVEOUT Out; - } hWave; - - WAVEHDR *WaveHdr; - HANDLE hEvent; - DWORD dwBufIdx; - DWORD dwMaxBufIdx; - pj_timestamp timestamp; -}; - - -/* Sound stream. */ -struct pjmedia_snd_stream -{ - pjmedia_dir dir; /**< Sound direction. */ - int play_id; /**< Playback dev id. */ - int rec_id; /**< Recording dev id. */ - pj_pool_t *pool; /**< Memory pool. */ - - pjmedia_snd_rec_cb rec_cb; /**< Capture callback. */ - pjmedia_snd_play_cb play_cb; /**< Playback callback. */ - void *user_data; /**< Application data. */ - - struct wmme_stream play_strm; /**< Playback stream. */ - struct wmme_stream rec_strm; /**< Capture stream. */ - - void *buffer; /**< Temp. frame buffer. */ - unsigned clock_rate; /**< Clock rate. */ - unsigned samples_per_frame; /**< Samples per frame. */ - unsigned bits_per_sample; /**< Bits per sample. */ - unsigned channel_count; /**< Channel count. */ - - pj_thread_t *thread; /**< Thread handle. */ - HANDLE thread_quit_event; /**< Quit signal to thread */ -}; - - -static pj_pool_factory *pool_factory; - -static void init_waveformatex (LPWAVEFORMATEX pcmwf, - unsigned clock_rate, - unsigned channel_count) -{ - pj_bzero(pcmwf, sizeof(PCMWAVEFORMAT)); - pcmwf->wFormatTag = WAVE_FORMAT_PCM; - pcmwf->nChannels = (pj_uint16_t)channel_count; - pcmwf->nSamplesPerSec = clock_rate; - pcmwf->nBlockAlign = (pj_uint16_t)(channel_count * BYTES_PER_SAMPLE); - pcmwf->nAvgBytesPerSec = clock_rate * channel_count * BYTES_PER_SAMPLE; - pcmwf->wBitsPerSample = BITS_PER_SAMPLE; -} - - -/* - * Initialize WMME player device. - */ -static pj_status_t init_player_stream( pj_pool_t *pool, - struct wmme_stream *wmme_strm, - int dev_id, - unsigned clock_rate, - unsigned channel_count, - unsigned samples_per_frame, - unsigned buffer_count) -{ - MMRESULT mr; - WAVEFORMATEX pcmwf; - unsigned bytes_per_frame; - unsigned i; - - PJ_ASSERT_RETURN(buffer_count <= MAX_PACKET_BUFFER_COUNT, PJ_EINVAL); - - /* Check device ID */ - if (dev_id == -1) - dev_id = 0; - - PJ_ASSERT_RETURN(dev_id >= 0 && dev_id < (int)dev_count, PJ_EINVAL); - - /* - * Create a wait event. - */ - wmme_strm->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - if (NULL == wmme_strm->hEvent) - return pj_get_os_error(); - - /* - * Set up wave format structure for opening the device. - */ - init_waveformatex(&pcmwf, clock_rate, channel_count); - bytes_per_frame = samples_per_frame * BYTES_PER_SAMPLE; - - /* - * Open wave device. - */ - mr = waveOutOpen(&wmme_strm->hWave.Out, dev_info[dev_id].deviceId, &pcmwf, - (DWORD)wmme_strm->hEvent, 0, CALLBACK_EVENT); - if (mr != MMSYSERR_NOERROR) - /* TODO: This is for HRESULT/GetLastError() */ - PJ_RETURN_OS_ERROR(mr); - - /* Pause the wave out device */ - mr = waveOutPause(wmme_strm->hWave.Out); - if (mr != MMSYSERR_NOERROR) - /* TODO: This is for HRESULT/GetLastError() */ - PJ_RETURN_OS_ERROR(mr); - - /* - * Create the buffers. - */ - wmme_strm->WaveHdr = pj_pool_zalloc(pool, sizeof(WAVEHDR) * buffer_count); - for (i = 0; i < buffer_count; ++i) - { - wmme_strm->WaveHdr[i].lpData = pj_pool_zalloc(pool, bytes_per_frame); - wmme_strm->WaveHdr[i].dwBufferLength = bytes_per_frame; - mr = waveOutPrepareHeader(wmme_strm->hWave.Out, - &(wmme_strm->WaveHdr[i]), - sizeof(WAVEHDR)); - if (mr != MMSYSERR_NOERROR) - /* TODO: This is for HRESULT/GetLastError() */ - PJ_RETURN_OS_ERROR(mr); - mr = waveOutWrite(wmme_strm->hWave.Out, &(wmme_strm->WaveHdr[i]), - sizeof(WAVEHDR)); - if (mr != MMSYSERR_NOERROR) - /* TODO: This is for HRESULT/GetLastError() */ - PJ_RETURN_OS_ERROR(mr); - } - - wmme_strm->dwBufIdx = 0; - wmme_strm->dwMaxBufIdx = buffer_count; - wmme_strm->timestamp.u64 = 0; - - /* Done setting up play device. */ - PJ_LOG(5, (THIS_FILE, - " WaveAPI Sound player \"%s\" initialized (clock_rate=%d, " - "channel_count=%d, samples_per_frame=%d (%dms))", - dev_info[dev_id].info.name, - clock_rate, channel_count, samples_per_frame, - samples_per_frame * 1000 / clock_rate)); - - return PJ_SUCCESS; -} - - -/* - * Initialize Windows Multimedia recorder device - */ -static pj_status_t init_capture_stream( pj_pool_t *pool, - struct wmme_stream *wmme_strm, - int dev_id, - unsigned clock_rate, - unsigned channel_count, - unsigned samples_per_frame, - unsigned buffer_count) -{ - MMRESULT mr; - WAVEFORMATEX pcmwf; - unsigned bytes_per_frame; - unsigned i; - - PJ_ASSERT_RETURN(buffer_count <= MAX_PACKET_BUFFER_COUNT, PJ_EINVAL); - - /* Check device ID */ - if (dev_id == -1) - dev_id = 0; - - PJ_ASSERT_RETURN(dev_id >= 0 && dev_id < (int)dev_count, PJ_EINVAL); - - /* - * Create a wait event. - */ - wmme_strm->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - if (NULL == wmme_strm->hEvent) - return pj_get_os_error(); - - /* - * Set up wave format structure for opening the device. - */ - init_waveformatex(&pcmwf, clock_rate, channel_count); - bytes_per_frame = samples_per_frame * BYTES_PER_SAMPLE; - - /* - * Open wave device. - */ - mr = waveInOpen(&wmme_strm->hWave.In, dev_info[dev_id].deviceId, &pcmwf, - (DWORD)wmme_strm->hEvent, 0, CALLBACK_EVENT); - if (mr != MMSYSERR_NOERROR) - /* TODO: This is for HRESULT/GetLastError() */ - PJ_RETURN_OS_ERROR(mr); - - /* - * Create the buffers. - */ - wmme_strm->WaveHdr = pj_pool_zalloc(pool, sizeof(WAVEHDR) * buffer_count); - for (i = 0; i < buffer_count; ++i) - { - wmme_strm->WaveHdr[i].lpData = pj_pool_zalloc(pool, bytes_per_frame); - wmme_strm->WaveHdr[i].dwBufferLength = bytes_per_frame; - mr = waveInPrepareHeader(wmme_strm->hWave.In, &(wmme_strm->WaveHdr[i]), - sizeof(WAVEHDR)); - if (mr != MMSYSERR_NOERROR) - /* TODO: This is for HRESULT/GetLastError() */ - PJ_RETURN_OS_ERROR(mr); - mr = waveInAddBuffer(wmme_strm->hWave.In, &(wmme_strm->WaveHdr[i]), - sizeof(WAVEHDR)); - if (mr != MMSYSERR_NOERROR) - /* TODO: This is for HRESULT/GetLastError() */ - PJ_RETURN_OS_ERROR(mr); - } - - wmme_strm->dwBufIdx = 0; - wmme_strm->dwMaxBufIdx = buffer_count; - wmme_strm->timestamp.u64 = 0; - - /* Done setting up play device. */ - PJ_LOG(5,(THIS_FILE, - " WaveAPI Sound recorder \"%s\" initialized (clock_rate=%d, " - "channel_count=%d, samples_per_frame=%d (%dms))", - dev_info[dev_id].info.name, - clock_rate, channel_count, samples_per_frame, - samples_per_frame * 1000 / clock_rate)); - - return PJ_SUCCESS; -} - - - -/* -* WMME capture and playback thread. -*/ -static int PJ_THREAD_FUNC wmme_dev_thread(void *arg) -{ - pjmedia_snd_stream *strm = arg; - HANDLE events[3]; - unsigned eventCount; - unsigned bytes_per_frame; - pj_status_t status = PJ_SUCCESS; - - - eventCount = 0; - events[eventCount++] = strm->thread_quit_event; - if (strm->dir & PJMEDIA_DIR_PLAYBACK) - events[eventCount++] = strm->play_strm.hEvent; - if (strm->dir & PJMEDIA_DIR_CAPTURE) - events[eventCount++] = strm->rec_strm.hEvent; - - - /* Raise self priority. We don't want the audio to be distorted by - * system activity. - */ -#if defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE != 0 - if (strm->dir & PJMEDIA_DIR_PLAYBACK) - CeSetThreadPriority(GetCurrentThread(), 153); - else - CeSetThreadPriority(GetCurrentThread(), 247); -#else - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); -#endif - - /* Calculate bytes per frame */ - bytes_per_frame = strm->samples_per_frame * BYTES_PER_SAMPLE; - - /* - * Loop while not signalled to quit, wait for event objects to be - * signalled by WMME capture and play buffer. - */ - while (status == PJ_SUCCESS) - { - - DWORD rc; - pjmedia_dir signalled_dir; - - rc = WaitForMultipleObjects(eventCount, events, FALSE, INFINITE); - if (rc < WAIT_OBJECT_0 || rc >= WAIT_OBJECT_0 + eventCount) - continue; - - if (rc == WAIT_OBJECT_0) - break; - - if (rc == (WAIT_OBJECT_0 + 1)) - { - if (events[1] == strm->play_strm.hEvent) - signalled_dir = PJMEDIA_DIR_PLAYBACK; - else - signalled_dir = PJMEDIA_DIR_CAPTURE; - } - else - { - if (events[2] == strm->play_strm.hEvent) - signalled_dir = PJMEDIA_DIR_PLAYBACK; - else - signalled_dir = PJMEDIA_DIR_CAPTURE; - } - - - if (signalled_dir == PJMEDIA_DIR_PLAYBACK) - { - struct wmme_stream *wmme_strm = &strm->play_strm; - MMRESULT mr = MMSYSERR_NOERROR; - status = PJ_SUCCESS; - - /* - * Windows Multimedia has requested us to feed some frames to - * playback buffer. - */ - - while (wmme_strm->WaveHdr[wmme_strm->dwBufIdx].dwFlags & WHDR_DONE) - { - void* buffer = wmme_strm->WaveHdr[wmme_strm->dwBufIdx].lpData; - - PJ_LOG(5,(THIS_FILE, "Finished writing buffer %d", - wmme_strm->dwBufIdx)); - - /* Get frame from application. */ - status = (*strm->play_cb)(strm->user_data, - wmme_strm->timestamp.u32.lo, - buffer, - bytes_per_frame); - - if (status != PJ_SUCCESS) - break; - - /* Write to the device. */ - mr = waveOutWrite(wmme_strm->hWave.Out, - &(wmme_strm->WaveHdr[wmme_strm->dwBufIdx]), - sizeof(WAVEHDR)); - if (mr != MMSYSERR_NOERROR) - { - status = PJ_STATUS_FROM_OS(mr); - break; - } - - /* Increment position. */ - if (++wmme_strm->dwBufIdx >= wmme_strm->dwMaxBufIdx) - wmme_strm->dwBufIdx = 0; - wmme_strm->timestamp.u64 += strm->samples_per_frame / - strm->channel_count; - } - } - else - { - struct wmme_stream *wmme_strm = &strm->rec_strm; - MMRESULT mr = MMSYSERR_NOERROR; - status = PJ_SUCCESS; - - /* - * Windows Multimedia has indicated that it has some frames ready - * in the capture buffer. Get as much frames as possible to - * prevent overflows. - */ -#if 0 - { - static DWORD tc = 0; - DWORD now = GetTickCount(); - DWORD i = 0; - DWORD bits = 0; - - if (tc == 0) tc = now; - - for (i = 0; i < wmme_strm->dwMaxBufIdx; ++i) - { - bits = bits << 4; - bits |= wmme_strm->WaveHdr[i].dwFlags & WHDR_DONE; - } - PJ_LOG(5,(THIS_FILE, "Record Signal> Index: %d, Delta: %4.4d, " - "Flags: %6.6x\n", - wmme_strm->dwBufIdx, - now - tc, - bits)); - tc = now; - } -#endif - - while (wmme_strm->WaveHdr[wmme_strm->dwBufIdx].dwFlags & WHDR_DONE) - { - char* buffer = (char*) - wmme_strm->WaveHdr[wmme_strm->dwBufIdx].lpData; - unsigned cap_len = - wmme_strm->WaveHdr[wmme_strm->dwBufIdx].dwBytesRecorded; - - /* - PJ_LOG(5,(THIS_FILE, "Read %d bytes from buffer %d", cap_len, - wmme_strm->dwBufIdx)); - */ - - if (cap_len < bytes_per_frame) - pj_bzero(buffer + cap_len, bytes_per_frame - cap_len); - - /* Copy the audio data out of the wave buffer. */ - pj_memcpy(strm->buffer, buffer, bytes_per_frame); - - /* Re-add the buffer to the device. */ - mr = waveInAddBuffer(wmme_strm->hWave.In, - &(wmme_strm->WaveHdr[wmme_strm->dwBufIdx]), - sizeof(WAVEHDR)); - if (mr != MMSYSERR_NOERROR) { - status = PJ_STATUS_FROM_OS(mr); - break; - } - - /* Call callback */ - status = (*strm->rec_cb)(strm->user_data, - wmme_strm->timestamp.u32.lo, - strm->buffer, - bytes_per_frame); - - if (status != PJ_SUCCESS) - break; - - /* Increment position. */ - if (++wmme_strm->dwBufIdx >= wmme_strm->dwMaxBufIdx) - wmme_strm->dwBufIdx = 0; - wmme_strm->timestamp.u64 += strm->samples_per_frame / - strm->channel_count; - } - } - } - - PJ_LOG(5,(THIS_FILE, "WMME: thread stopping..")); - return 0; -} - - -/* -* Init sound library. -*/ -PJ_DEF(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory) -{ - unsigned c; - int i; - int inputDeviceCount, outputDeviceCount, maximumPossibleDeviceCount; - - if (snd_initialized) - return PJ_SUCCESS; - - pj_bzero(&dev_info, sizeof(dev_info)); - - dev_count = 0; - pool_factory = factory; - - /* Enumerate sound playback devices */ - maximumPossibleDeviceCount = 0; - - inputDeviceCount = waveInGetNumDevs(); - if (inputDeviceCount > 0) - /* assume there is a WAVE_MAPPER */ - maximumPossibleDeviceCount += inputDeviceCount + 1; - - outputDeviceCount = waveOutGetNumDevs(); - if (outputDeviceCount > 0) - /* assume there is a WAVE_MAPPER */ - maximumPossibleDeviceCount += outputDeviceCount + 1; - - if (maximumPossibleDeviceCount >= MAX_HARDWARE) - { - pj_assert(!"Too many hardware found"); - PJ_LOG(3,(THIS_FILE, "Too many hardware found, " - "some devices will not be listed")); - } - - if (inputDeviceCount > 0) - { - /* -1 is the WAVE_MAPPER */ - for (i = -1; i < inputDeviceCount && dev_count < MAX_HARDWARE; ++i) - { - UINT uDeviceID = (UINT)((i==-1) ? WAVE_MAPPER : i); - WAVEINCAPS wic; - MMRESULT mr; - - pj_bzero(&wic, sizeof(WAVEINCAPS)); - - mr = waveInGetDevCaps(uDeviceID, &wic, sizeof(WAVEINCAPS)); - - if (mr == MMSYSERR_NOMEM) - return PJ_ENOMEM; - - if (mr != MMSYSERR_NOERROR) - continue; - -#ifdef UNICODE - WideCharToMultiByte(CP_ACP, 0, wic.szPname, wcslen(wic.szPname), - dev_info[dev_count].info.name, 64, NULL, NULL); -#else - strncpy(dev_info[dev_count].info.name, wic.szPname, MAXPNAMELEN); -#endif - if (uDeviceID == WAVE_MAPPER) - strcat(dev_info[dev_count].info.name, " - Input"); - - dev_info[dev_count].info.input_count = wic.wChannels; - dev_info[dev_count].info.output_count = 0; - dev_info[dev_count].info.default_samples_per_sec = 44100; - dev_info[dev_count].deviceId = uDeviceID; - - /* Sometimes a device can return a rediculously large number of - * channels. This happened with an SBLive card on a Windows ME box. - * It also happens on Win XP! - */ - if ((dev_info[dev_count].info.input_count < 1) || - (dev_info[dev_count].info.input_count > 256)) - dev_info[dev_count].info.input_count = 2; - - ++dev_count; - } - } - - if( outputDeviceCount > 0 ) - { - /* -1 is the WAVE_MAPPER */ - for (i = -1; i < outputDeviceCount && dev_count < MAX_HARDWARE; ++i) - { - UINT uDeviceID = (UINT)((i==-1) ? WAVE_MAPPER : i); - WAVEOUTCAPS woc; - MMRESULT mr; - - pj_bzero(&woc, sizeof(WAVEOUTCAPS)); - - mr = waveOutGetDevCaps(uDeviceID, &woc, sizeof(WAVEOUTCAPS)); - - if (mr == MMSYSERR_NOMEM) - return PJ_ENOMEM; - - if (mr != MMSYSERR_NOERROR) - continue; - -#ifdef UNICODE - WideCharToMultiByte(CP_ACP, 0, woc.szPname, wcslen(woc.szPname), - dev_info[dev_count].info.name, 64, NULL, NULL); -#else - strncpy(dev_info[dev_count].info.name, woc.szPname, MAXPNAMELEN); -#endif - if (uDeviceID == WAVE_MAPPER) - strcat(dev_info[dev_count].info.name, " - Output"); - - dev_info[dev_count].info.output_count = woc.wChannels; - dev_info[dev_count].info.input_count = 0; - dev_info[dev_count].deviceId = uDeviceID; - /* TODO: Perform a search! */ - dev_info[dev_count].info.default_samples_per_sec = 44100; - - /* Sometimes a device can return a rediculously large number of channels. - * This happened with an SBLive card on a Windows ME box. - * It also happens on Win XP! - */ - if ((dev_info[dev_count].info.output_count < 1) || - (dev_info[dev_count].info.output_count > 256)) - dev_info[dev_count].info.output_count = 2; - - ++dev_count; - } - } - - PJ_LOG(4, (THIS_FILE, "WMME initialized, found %d devices:", dev_count)); - for (c = 0; c < dev_count; ++c) - { - PJ_LOG(4, (THIS_FILE, " dev_id %d: %s (in=%d, out=%d)", - c, - dev_info[c].info.name, - dev_info[c].info.input_count, - dev_info[c].info.output_count)); - } - return PJ_SUCCESS; -} - -/* - * Deinitialize sound library. - */ -PJ_DEF(pj_status_t) pjmedia_snd_deinit(void) -{ - snd_initialized = PJ_FALSE; - return PJ_SUCCESS; -} - -/* - * Get device count. - */ -PJ_DEF(int) pjmedia_snd_get_dev_count(void) -{ - return dev_count; -} - -/* - * Get device info. - */ -PJ_DEF(const pjmedia_snd_dev_info*) pjmedia_snd_get_dev_info(unsigned index) -{ - if (index == (unsigned)-1) - index = 0; - - PJ_ASSERT_RETURN(index < dev_count, NULL); - - return &dev_info[index].info; -} - - -/* - * Open stream. - */ -static pj_status_t open_stream(pjmedia_dir dir, - int rec_id, - int play_id, - unsigned clock_rate, - unsigned channel_count, - unsigned samples_per_frame, - unsigned bits_per_sample, - pjmedia_snd_rec_cb rec_cb, - pjmedia_snd_play_cb play_cb, - void *user_data, - pjmedia_snd_stream **p_snd_strm) -{ - pj_pool_t *pool; - pjmedia_snd_stream *strm; - pj_status_t status; - - - /* Make sure sound subsystem has been initialized with - * pjmedia_snd_init() - */ - PJ_ASSERT_RETURN(pool_factory != NULL, PJ_EINVALIDOP); - - - /* Can only support 16bits per sample */ - PJ_ASSERT_RETURN(bits_per_sample == BITS_PER_SAMPLE, PJ_EINVAL); - - /* Create and Initialize stream descriptor */ - pool = pj_pool_create(pool_factory, "wmme-dev", 1000, 1000, NULL); - PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM); - - strm = pj_pool_zalloc(pool, sizeof(pjmedia_snd_stream)); - strm->dir = dir; - strm->play_id = play_id; - strm->rec_id = rec_id; - strm->pool = pool; - strm->rec_cb = rec_cb; - strm->play_cb = play_cb; - strm->user_data = user_data; - strm->clock_rate = clock_rate; - strm->samples_per_frame = samples_per_frame; - strm->bits_per_sample = bits_per_sample; - strm->channel_count = channel_count; - strm->buffer = pj_pool_alloc(pool, samples_per_frame * BYTES_PER_SAMPLE); - if (!strm->buffer) - { - pj_pool_release(pool); - return PJ_ENOMEM; - } - - /* Create player stream */ - if (dir & PJMEDIA_DIR_PLAYBACK) - { - unsigned buf_count; - - buf_count = snd_output_latency * clock_rate * channel_count / - samples_per_frame / 1000; - - status = init_player_stream(strm->pool, - &strm->play_strm, - play_id, - clock_rate, - channel_count, - samples_per_frame, - buf_count); - - if (status != PJ_SUCCESS) - { - pjmedia_snd_stream_close(strm); - return status; - } - } - - /* Create capture stream */ - if (dir & PJMEDIA_DIR_CAPTURE) - { - unsigned buf_count; - - buf_count = snd_input_latency * clock_rate * channel_count / - samples_per_frame / 1000; - - status = init_capture_stream(strm->pool, - &strm->rec_strm, - rec_id, - clock_rate, - channel_count, - samples_per_frame, - buf_count); - - if (status != PJ_SUCCESS) - { - pjmedia_snd_stream_close(strm); - return status; - } - } - - /* Create the stop event */ - strm->thread_quit_event = CreateEvent(NULL, FALSE, FALSE, NULL); - if (strm->thread_quit_event == NULL) - return pj_get_os_error(); - - /* Create and start the thread */ - status = pj_thread_create(pool, "wmme", &wmme_dev_thread, strm, 0, 0, - &strm->thread); - if (status != PJ_SUCCESS) - { - pjmedia_snd_stream_close(strm); - return status; - } - - *p_snd_strm = strm; - - return PJ_SUCCESS; -} - -/* - * Open stream. - */ -PJ_DEF(pj_status_t) pjmedia_snd_open_rec(int index, - unsigned clock_rate, - unsigned channel_count, - unsigned samples_per_frame, - unsigned bits_per_sample, - pjmedia_snd_rec_cb rec_cb, - void *user_data, - pjmedia_snd_stream **p_snd_strm) -{ - PJ_ASSERT_RETURN(rec_cb && p_snd_strm, PJ_EINVAL); - - return open_stream( PJMEDIA_DIR_CAPTURE, - index, - -1, - clock_rate, - channel_count, - samples_per_frame, - bits_per_sample, - rec_cb, - NULL, - user_data, - p_snd_strm); -} - -PJ_DEF(pj_status_t) pjmedia_snd_open_player(int index, - unsigned clock_rate, - unsigned channel_count, - unsigned samples_per_frame, - unsigned bits_per_sample, - pjmedia_snd_play_cb play_cb, - void *user_data, - pjmedia_snd_stream **p_snd_strm) -{ - PJ_ASSERT_RETURN(play_cb && p_snd_strm, PJ_EINVAL); - - return open_stream( PJMEDIA_DIR_PLAYBACK, - -1, - index, - clock_rate, - channel_count, - samples_per_frame, - bits_per_sample, - NULL, - play_cb, - user_data, - p_snd_strm); -} - -/* - * Open both player and recorder. - */ -PJ_DEF(pj_status_t) pjmedia_snd_open(int rec_id, - int play_id, - unsigned clock_rate, - unsigned channel_count, - unsigned samples_per_frame, - unsigned bits_per_sample, - pjmedia_snd_rec_cb rec_cb, - pjmedia_snd_play_cb play_cb, - void *user_data, - pjmedia_snd_stream **p_snd_strm) -{ - PJ_ASSERT_RETURN(rec_cb && play_cb && p_snd_strm, PJ_EINVAL); - - return open_stream( PJMEDIA_DIR_CAPTURE_PLAYBACK, - rec_id, - play_id, - clock_rate, - channel_count, - samples_per_frame, - bits_per_sample, - rec_cb, - play_cb, - user_data, - p_snd_strm); -} - -/* - * Get stream info. - */ -PJ_DEF(pj_status_t) pjmedia_snd_stream_get_info(pjmedia_snd_stream *strm, - pjmedia_snd_stream_info *pi) -{ - PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL); - - pj_bzero(pi, sizeof(*pi)); - pi->dir = strm->dir; - pi->play_id = strm->play_id; - pi->rec_id = strm->rec_id; - pi->clock_rate = strm->clock_rate; - pi->channel_count = strm->channel_count; - pi->samples_per_frame = strm->samples_per_frame; - pi->bits_per_sample = strm->bits_per_sample; - pi->rec_latency = snd_input_latency * strm->clock_rate * - strm->channel_count / 1000; - pi->play_latency = snd_output_latency * strm->clock_rate * - strm->channel_count / 1000; - - return PJ_SUCCESS; -} - - -/* -* Start stream. -*/ -PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream) -{ - MMRESULT mr; - - PJ_UNUSED_ARG(stream); - - if (stream->play_strm.hWave.Out != NULL) - { - mr = waveOutRestart(stream->play_strm.hWave.Out); - if (mr != MMSYSERR_NOERROR) - /* TODO: This macro is supposed to be used for HRESULT, fix. */ - PJ_RETURN_OS_ERROR(mr); - PJ_LOG(5,(THIS_FILE, "WMME playback stream started")); - } - - if (stream->rec_strm.hWave.In != NULL) - { - mr = waveInStart(stream->rec_strm.hWave.In); - if (mr != MMSYSERR_NOERROR) - /* TODO: This macro is supposed to be used for HRESULT, fix. */ - PJ_RETURN_OS_ERROR(mr); - PJ_LOG(5,(THIS_FILE, "WMME capture stream started")); - } - - return PJ_SUCCESS; -} - -/* - * Stop stream. - */ -PJ_DEF(pj_status_t) pjmedia_snd_stream_stop(pjmedia_snd_stream *stream) -{ - MMRESULT mr; - - PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL); - - if (stream->play_strm.hWave.Out != NULL) - { - mr = waveOutPause(stream->play_strm.hWave.Out); - if (mr != MMSYSERR_NOERROR) - /* TODO: This macro is supposed to be used for HRESULT, fix. */ - PJ_RETURN_OS_ERROR(mr); - PJ_LOG(5,(THIS_FILE, "Stopped WMME playback stream")); - } - - if (stream->rec_strm.hWave.In != NULL) - { - mr = waveInStop(stream->rec_strm.hWave.In); - if (mr != MMSYSERR_NOERROR) - /* TODO: This macro is supposed to be used for HRESULT, fix. */ - PJ_RETURN_OS_ERROR(mr); - PJ_LOG(5,(THIS_FILE, "Stopped WMME capture stream")); - } - - return PJ_SUCCESS; -} - - -/* - * Destroy stream. - */ -PJ_DEF(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream) -{ - unsigned i; - - PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL); - - pjmedia_snd_stream_stop(stream); - - if (stream->thread) - { - SetEvent(stream->thread_quit_event); - pj_thread_join(stream->thread); - pj_thread_destroy(stream->thread); - stream->thread = NULL; - } - - /* Unprepare the headers and close the play device */ - if (stream->play_strm.hWave.Out) - { - waveOutReset(stream->play_strm.hWave.Out); - for (i = 0; i < stream->play_strm.dwMaxBufIdx; ++i) - waveOutUnprepareHeader(stream->play_strm.hWave.Out, - &(stream->play_strm.WaveHdr[i]), - sizeof(WAVEHDR)); - waveOutClose(stream->play_strm.hWave.Out); - stream->play_strm.hWave.Out = NULL; - } - - /* Close the play event */ - if (stream->play_strm.hEvent) - { - CloseHandle(stream->play_strm.hEvent); - stream->play_strm.hEvent = NULL; - } - - /* Unprepare the headers and close the record device */ - if (stream->rec_strm.hWave.In) - { - waveInReset(stream->rec_strm.hWave.In); - for (i = 0; i < stream->play_strm.dwMaxBufIdx; ++i) - waveInUnprepareHeader(stream->rec_strm.hWave.In, - &(stream->rec_strm.WaveHdr[i]), - sizeof(WAVEHDR)); - waveInClose(stream->rec_strm.hWave.In); - stream->rec_strm.hWave.In = NULL; - } - - /* Close the record event */ - if (stream->rec_strm.hEvent) - { - CloseHandle(stream->rec_strm.hEvent); - stream->rec_strm.hEvent = NULL; - } - - pj_pool_release(stream->pool); - - return PJ_SUCCESS; -} - -/* - * Set sound latency. - */ -PJ_DEF(pj_status_t) pjmedia_snd_set_latency(unsigned input_latency, - unsigned output_latency) -{ - snd_input_latency = (input_latency == 0)? - PJMEDIA_SND_DEFAULT_REC_LATENCY : input_latency; - snd_output_latency = (output_latency == 0)? - PJMEDIA_SND_DEFAULT_PLAY_LATENCY : output_latency; - - return PJ_SUCCESS; -} - -#endif /* PJMEDIA_SOUND_IMPLEMENTATION */ - |