summaryrefslogtreecommitdiff
path: root/pjmedia
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2008-09-17 11:56:44 +0000
committerBenny Prijono <bennylp@teluu.com>2008-09-17 11:56:44 +0000
commitc3cc93840c5c0b98493f3aad01060fb3e159e8dc (patch)
treefcefefe7bee0fd42452137b0bc3de2e6bbc0fa53 /pjmedia
parent6538d8f5e25159ed70fd6c6cd3cd4a5e83a7564d (diff)
Ticket #633: Updated DirectSound implementation:
- Fixed issue on start/stop without close/reopen. - Fixed possibility of buffer overrun whe 10ms samples used. - Fixed latency unit of sound stream info, from ms to samples. - Updated playback buffer to fill the whole playback buffer in each notification in order to increase samples data availability. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2288 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia')
-rw-r--r--pjmedia/src/pjmedia/dsound.c151
1 files changed, 104 insertions, 47 deletions
diff --git a/pjmedia/src/pjmedia/dsound.c b/pjmedia/src/pjmedia/dsound.c
index 56dd97af..5abdb1c8 100644
--- a/pjmedia/src/pjmedia/dsound.c
+++ b/pjmedia/src/pjmedia/dsound.c
@@ -38,7 +38,6 @@
#endif
-
#define THIS_FILE "dsound.c"
#define BITS_PER_SAMPLE 16
#define BYTES_PER_SAMPLE (BITS_PER_SAMPLE/8)
@@ -113,7 +112,7 @@ struct pjmedia_snd_stream
unsigned channel_count; /**< Channel count. */
pj_thread_t *thread; /**< Thread handle. */
- pj_bool_t thread_quit_flag; /**< Quit signal to thread */
+ HANDLE thread_quit_event; /**< Quit signal to thread */
};
@@ -432,6 +431,29 @@ static BOOL AppWriteDataToBuffer(LPDIRECTSOUNDBUFFER lpDsb, // The buffer.
return FALSE;
}
+/*
+ * Check if there is space in playing buffer.
+ */
+static unsigned dsound_play_empty_size(struct dsound_stream *dsound_strm)
+{
+ HRESULT hr;
+ long size_available;
+ DWORD writePos, readPos;
+
+ hr = IDirectSoundBuffer_GetCurrentPosition(dsound_strm->ds.play.lpDsBuffer,
+ &readPos, &writePos);
+ if FAILED(hr)
+ return PJ_FALSE;
+
+ if (readPos < dsound_strm->dwBytePos)
+ size_available = readPos + dsound_strm->dwDsBufferSize -
+ dsound_strm->dwBytePos;
+ else
+ size_available = readPos - dsound_strm->dwBytePos;
+
+ return size_available;
+}
+
/*
* Check if there are captured frames in DirectSound capture buffer.
@@ -442,8 +464,9 @@ static unsigned dsound_captured_size(struct dsound_stream *dsound_strm)
long size_available;
DWORD writePos, readPos;
- hr = IDirectSoundCaptureBuffer_GetCurrentPosition(dsound_strm->ds.capture.lpDsBuffer,
- &writePos, &readPos);
+ hr = IDirectSoundCaptureBuffer_GetCurrentPosition(
+ dsound_strm->ds.capture.lpDsBuffer,
+ &writePos, &readPos);
if FAILED(hr)
return PJ_FALSE;
@@ -462,13 +485,14 @@ static unsigned dsound_captured_size(struct dsound_stream *dsound_strm)
static int dsound_dev_thread(void *arg)
{
pjmedia_snd_stream *strm = arg;
- HANDLE events[2];
+ HANDLE events[3];
unsigned eventCount;
unsigned bytes_per_frame;
pj_status_t status;
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)
@@ -478,7 +502,7 @@ static int dsound_dev_thread(void *arg)
/* Raise self priority. We don't want the audio to be distorted by
* system activity.
*/
- //SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+ SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
/* Calculate bytes per frame */
bytes_per_frame = strm->samples_per_frame * BYTES_PER_SAMPLE;
@@ -487,27 +511,28 @@ static int dsound_dev_thread(void *arg)
* Loop while not signalled to quit, wait for event objects to be
* signalled by DirectSound capture and play buffer.
*/
- while (!strm->thread_quit_flag) {
+ while (PJ_TRUE) {
DWORD rc;
pjmedia_dir signalled_dir;
- rc = WaitForMultipleObjects(eventCount, events, FALSE,
- 100);
+ rc = WaitForMultipleObjects(eventCount, events, FALSE, INFINITE);
if (rc < WAIT_OBJECT_0 || rc >= WAIT_OBJECT_0+eventCount)
continue;
- if (rc == WAIT_OBJECT_0) {
- if (events[0] == strm->play_strm.hEvent)
- signalled_dir = PJMEDIA_DIR_PLAYBACK;
+ 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;
+ signalled_dir = PJMEDIA_DIR_CAPTURE;
} else {
- if (events[1] == strm->play_strm.hEvent)
- signalled_dir = PJMEDIA_DIR_PLAYBACK;
+ if (events[2] == strm->play_strm.hEvent)
+ signalled_dir = PJMEDIA_DIR_PLAYBACK;
else
- signalled_dir = PJMEDIA_DIR_CAPTURE;
+ signalled_dir = PJMEDIA_DIR_CAPTURE;
}
@@ -523,25 +548,27 @@ static int dsound_dev_thread(void *arg)
dsound_strm = &strm->play_strm;
status = PJ_SUCCESS;
- /* Get frame from application. */
- status = (*strm->play_cb)(strm->user_data,
- dsound_strm->timestamp.u32.lo,
- strm->buffer,
- bytes_per_frame);
- if (status != PJ_SUCCESS)
- break;
+ while (dsound_play_empty_size(dsound_strm) > bytes_per_frame) {
+ /* Get frame from application. */
+ status = (*strm->play_cb)(strm->user_data,
+ dsound_strm->timestamp.u32.lo,
+ strm->buffer,
+ bytes_per_frame);
+ if (status != PJ_SUCCESS)
+ break;
- /* Write to DirectSound buffer. */
- AppWriteDataToBuffer( dsound_strm->ds.play.lpDsBuffer,
- dsound_strm->dwBytePos,
- (LPBYTE)strm->buffer,
- bytes_per_frame);
+ /* Write to DirectSound buffer. */
+ AppWriteDataToBuffer( dsound_strm->ds.play.lpDsBuffer,
+ dsound_strm->dwBytePos,
+ (LPBYTE)strm->buffer,
+ bytes_per_frame);
- /* Increment position. */
- dsound_strm->dwBytePos += bytes_per_frame;
- if (dsound_strm->dwBytePos >= dsound_strm->dwDsBufferSize)
- dsound_strm->dwBytePos -= dsound_strm->dwDsBufferSize;
- dsound_strm->timestamp.u64 += strm->samples_per_frame;
+ /* Increment position. */
+ dsound_strm->dwBytePos += bytes_per_frame;
+ if (dsound_strm->dwBytePos >= dsound_strm->dwDsBufferSize)
+ dsound_strm->dwBytePos -= dsound_strm->dwDsBufferSize;
+ dsound_strm->timestamp.u64 += strm->samples_per_frame;
+ }
} else {
/*
@@ -554,13 +581,15 @@ static int dsound_dev_thread(void *arg)
dsound_strm = &strm->rec_strm;
- do {
+ /* Fetch while we have more than 1 frame */
+ while (dsound_captured_size(dsound_strm) > bytes_per_frame) {
+
/* Capture from DirectSound buffer. */
rc = AppReadDataFromBuffer(dsound_strm->ds.capture.lpDsBuffer,
dsound_strm->dwBytePos,
(LPBYTE)strm->buffer,
bytes_per_frame);
-
+
if (!rc) {
pj_bzero(strm->buffer, bytes_per_frame);
}
@@ -581,10 +610,7 @@ static int dsound_dev_thread(void *arg)
if (dsound_strm->dwBytePos >= dsound_strm->dwDsBufferSize)
dsound_strm->dwBytePos -= dsound_strm->dwDsBufferSize;
dsound_strm->timestamp.u64 += strm->samples_per_frame;
-
- /* Fetch while we have more than 1 frame */
- } while (dsound_captured_size(dsound_strm) > bytes_per_frame);
-
+ }
}
}
@@ -627,7 +653,8 @@ static BOOL CALLBACK DSEnumCallback( LPGUID lpGuid, LPCTSTR lpcstrDescription,
}
#ifdef UNICODE
- WideCharToMultiByte(CP_ACP, 0, lpcstrDescription, wcslen(lpcstrDescription), dev_info[index].info.name, max, NULL, NULL);
+ WideCharToMultiByte(CP_ACP, 0, lpcstrDescription, wcslen(lpcstrDescription),
+ dev_info[index].info.name, max, NULL, NULL);
#else
strncpy(dev_info[index].info.name, lpcstrDescription, max);
#endif
@@ -767,6 +794,16 @@ static pj_status_t open_stream( pjmedia_dir dir,
return PJ_ENOMEM;
}
+ /*
+ * Create event for stopping the worker thread.
+ */
+ strm->thread_quit_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (strm->thread_quit_event == NULL) {
+ status = pj_get_os_error();
+ pj_pool_release(pool);
+ return status;
+ }
+
/* Create player stream */
if (dir & PJMEDIA_DIR_PLAYBACK) {
unsigned buffer_count;
@@ -899,8 +936,10 @@ PJ_DEF(pj_status_t) pjmedia_snd_stream_get_info(pjmedia_snd_stream *strm,
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 = strm->rec_strm.latency;
- pi->play_latency = strm->play_strm.latency;
+ pi->rec_latency = strm->rec_strm.latency * strm->clock_rate *
+ strm->channel_count/ 1000;
+ pi->play_latency = strm->play_strm.latency * strm->clock_rate *
+ strm->channel_count/ 1000;
return PJ_SUCCESS;
}
@@ -913,9 +952,14 @@ PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream)
{
HRESULT hr;
- PJ_UNUSED_ARG(stream);
-
if (stream->play_strm.ds.play.lpDsBuffer) {
+ hr = IDirectSoundBuffer_SetCurrentPosition(
+ stream->play_strm.ds.play.lpDsBuffer, 0);
+ if (FAILED(hr))
+ return PJ_RETURN_OS_ERROR(hr);
+
+ stream->play_strm.dwBytePos = 0;
+
hr = IDirectSoundBuffer_Play(stream->play_strm.ds.play.lpDsBuffer,
0, 0, DSBPLAY_LOOPING);
if (FAILED(hr))
@@ -924,8 +968,15 @@ PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream)
}
if (stream->rec_strm.ds.capture.lpDsBuffer) {
- hr = IDirectSoundCaptureBuffer_Start(stream->rec_strm.ds.capture.lpDsBuffer,
- DSCBSTART_LOOPING );
+ hr = IDirectSoundCaptureBuffer_GetCurrentPosition(
+ stream->rec_strm.ds.capture.lpDsBuffer,
+ NULL, &stream->rec_strm.dwBytePos );
+ if (FAILED(hr))
+ return PJ_RETURN_OS_ERROR(hr);
+
+ hr = IDirectSoundCaptureBuffer_Start(
+ stream->rec_strm.ds.capture.lpDsBuffer,
+ DSCBSTART_LOOPING );
if (FAILED(hr))
return PJ_RETURN_OS_ERROR(hr);
PJ_LOG(5,(THIS_FILE, "DirectSound capture stream started"));
@@ -965,12 +1016,18 @@ PJ_DEF(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream)
pjmedia_snd_stream_stop(stream);
if (stream->thread) {
- stream->thread_quit_flag = 1;
+ pj_assert(stream->thread_quit_event);
+ SetEvent(stream->thread_quit_event);
pj_thread_join(stream->thread);
pj_thread_destroy(stream->thread);
stream->thread = NULL;
}
+ if (stream->thread_quit_event) {
+ CloseHandle(stream->thread_quit_event);
+ stream->thread_quit_event = NULL;
+ }
+
if (stream->play_strm.lpDsNotify) {
IDirectSoundNotify_Release( stream->play_strm.lpDsNotify );
stream->play_strm.lpDsNotify = NULL;