Index: pjproject/trunk/pjmedia/src/pjmedia/dsound.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/dsound.c	(revision 2287)
+++ pjproject/trunk/pjmedia/src/pjmedia/dsound.c	(revision 2288)
@@ -39,5 +39,4 @@
 
 
-
 #define THIS_FILE	    "dsound.c"
 #define BITS_PER_SAMPLE	    16
@@ -114,5 +113,5 @@
 
     pj_thread_t		   *thread;		/**< Thread handle.	    */
-    pj_bool_t		    thread_quit_flag;	/**< Quit signal to thread  */
+    HANDLE		    thread_quit_event;	/**< Quit signal to thread  */
 };
 
@@ -433,9 +432,8 @@
 }
 
-
-/*
- * Check if there are captured frames in DirectSound capture buffer.
- */
-static unsigned dsound_captured_size(struct dsound_stream *dsound_strm)
+/*
+ * Check if there is space in playing buffer.
+ */
+static unsigned dsound_play_empty_size(struct dsound_stream *dsound_strm)
 {
     HRESULT hr;
@@ -443,6 +441,31 @@
     DWORD writePos, readPos;
 
-    hr = IDirectSoundCaptureBuffer_GetCurrentPosition(dsound_strm->ds.capture.lpDsBuffer, 
-						      &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.
+ */
+static unsigned dsound_captured_size(struct dsound_stream *dsound_strm)
+{
+    HRESULT hr;
+    long size_available;
+    DWORD writePos, readPos;
+
+    hr = IDirectSoundCaptureBuffer_GetCurrentPosition(
+					dsound_strm->ds.capture.lpDsBuffer, 
+					&writePos, &readPos);
     if FAILED(hr)
 	return PJ_FALSE;
@@ -463,5 +486,5 @@
 {
     pjmedia_snd_stream *strm = arg;
-    HANDLE events[2];
+    HANDLE events[3];
     unsigned eventCount;
     unsigned bytes_per_frame;
@@ -470,4 +493,5 @@
 
     eventCount = 0;
+    events[eventCount++] = strm->thread_quit_event;
     if (strm->dir & PJMEDIA_DIR_PLAYBACK)
 	events[eventCount++] = strm->play_strm.hEvent;
@@ -479,5 +503,5 @@
      * system activity.
      */
-    //SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+    SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
 
     /* Calculate bytes per frame */
@@ -488,25 +512,26 @@
      * 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;
 	}
 
@@ -524,23 +549,25 @@
 	    status = PJ_SUCCESS;
 
-	    /* Get frame from application. */
-	    status = (*strm->play_cb)(strm->user_data, 
-				      dsound_strm->timestamp.u32.lo,
-				      strm->buffer,
+	    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);
-	    if (status != PJ_SUCCESS)
-		break;
-
-	    /* 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 {
@@ -555,5 +582,7 @@
 	    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, 
@@ -561,5 +590,5 @@
 					   (LPBYTE)strm->buffer, 
 					   bytes_per_frame);
-		
+        	
 		if (!rc) {
 		    pj_bzero(strm->buffer, bytes_per_frame);
@@ -582,8 +611,5 @@
 		    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);
-
+	    }
 	}
     }
@@ -628,5 +654,6 @@
 
 #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);
@@ -768,4 +795,14 @@
     }
 
+    /*
+     * 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) {
@@ -900,6 +937,8 @@
     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;
@@ -914,7 +953,12 @@
     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);
@@ -925,6 +969,13 @@
     
     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);
@@ -966,8 +1017,14 @@
 
     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;
     }
 
