Index: /pjproject/trunk/pjmedia/src/pjmedia/pasound.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/pasound.c	(revision 761)
+++ /pjproject/trunk/pjmedia/src/pjmedia/pasound.c	(revision 762)
@@ -51,5 +51,7 @@
     int			 channel_count;
 
-    PaStream		*stream;
+    PaStream		*rec_strm;
+    PaStream		*play_strm;
+
     void		*user_data;
     pjmedia_snd_rec_cb   rec_cb;
@@ -387,5 +389,5 @@
     paFrames = samples_per_frame / channel_count;
 
-    err = Pa_OpenStream( &stream->stream, &inputParam, NULL,
+    err = Pa_OpenStream( &stream->rec_strm, &inputParam, NULL,
 			 clock_rate, paFrames, 
 			 paClipOff, &PaRecorderCallback, stream );
@@ -395,5 +397,5 @@
     }
 
-    paSI = Pa_GetStreamInfo(stream->stream);
+    paSI = Pa_GetStreamInfo(stream->rec_strm);
     paRate = (unsigned)paSI->sampleRate;
     paLatency = (unsigned)(paSI->inputLatency * 1000);
@@ -483,5 +485,5 @@
     paFrames = samples_per_frame / channel_count;
 
-    err = Pa_OpenStream( &stream->stream, NULL, &outputParam,
+    err = Pa_OpenStream( &stream->play_strm, NULL, &outputParam,
 			 clock_rate,  paFrames, 
 			 paClipOff, &PaPlayerCallback, stream );
@@ -491,5 +493,5 @@
     }
 
-    paSI = Pa_GetStreamInfo(stream->stream);
+    paSI = Pa_GetStreamInfo(stream->play_strm);
     paRate = (unsigned)(paSI->sampleRate);
     paLatency = (unsigned)(paSI->outputLatency * 1000);
@@ -524,4 +526,5 @@
     pj_pool_t *pool;
     pjmedia_snd_stream *stream;
+    PaStream *paStream = NULL;
     PaStreamParameters inputParam;
     PaStreamParameters outputParam;
@@ -612,7 +615,38 @@
     paFrames = samples_per_frame / channel_count;
 
-    err = Pa_OpenStream( &stream->stream, &inputParam, &outputParam,
-			 clock_rate, paFrames, 
-			 paClipOff, &PaRecorderPlayerCallback, stream );
+    /* If both input and output are on the same device, open a single stream
+     * for both input and output.
+     */
+    if (rec_id == play_id) {
+	err = Pa_OpenStream( &paStream, &inputParam, &outputParam,
+			     clock_rate, paFrames, 
+			     paClipOff, &PaRecorderPlayerCallback, stream );
+	if (err == paNoError) {
+	    /* Set play stream and record stream to the same stream */
+	    stream->play_strm = stream->rec_strm = paStream;
+	}
+    } else {
+	err = -1;
+    }
+
+    /* .. otherwise if input and output are on the same device, OR if we're
+     * unable to open a bidirectional stream, then open two separate
+     * input and output stream.
+     */
+    if (paStream == NULL) {
+	/* Open input stream */
+	err = Pa_OpenStream( &stream->rec_strm, &inputParam, NULL,
+			     clock_rate, paFrames, 
+			     paClipOff, &PaRecorderCallback, stream );
+	if (err == paNoError) {
+	    /* Open output stream */
+	    err = Pa_OpenStream( &stream->play_strm, NULL, &outputParam,
+				 clock_rate, paFrames, 
+				 paClipOff, &PaPlayerCallback, stream );
+	    if (err != paNoError)
+		Pa_CloseStream(stream->rec_strm);
+	}
+    }
+
     if (err != paNoError) {
 	pj_pool_release(pool);
@@ -620,7 +654,8 @@
     }
 
-    paSI = Pa_GetStreamInfo(stream->stream);
+    paSI = Pa_GetStreamInfo(stream->rec_strm);
     paRate = (unsigned)(paSI->sampleRate);
     paInputLatency = (unsigned)(paSI->inputLatency * 1000);
+    paSI = Pa_GetStreamInfo(stream->play_strm);
     paOutputLatency = (unsigned)(paSI->outputLatency * 1000);
 
@@ -648,10 +683,15 @@
 						pjmedia_snd_stream_info *pi)
 {
-    const PaStreamInfo *paSI;
+    const PaStreamInfo *paPlaySI = NULL, *paRecSI = NULL;
 
     PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
-    PJ_ASSERT_RETURN(strm->stream, PJ_EINVALIDOP);
-
-    paSI = Pa_GetStreamInfo(strm->stream);
+    PJ_ASSERT_RETURN(strm->play_strm || strm->rec_strm, PJ_EINVALIDOP);
+
+    if (strm->play_strm) {
+	paPlaySI = Pa_GetStreamInfo(strm->play_strm);
+    }
+    if (strm->rec_strm) {
+	paRecSI = Pa_GetStreamInfo(strm->rec_strm);
+    }
 
     pj_bzero(pi, sizeof(*pi));
@@ -659,10 +699,13 @@
     pi->play_id = strm->play_id;
     pi->rec_id = strm->rec_id;
-    pi->clock_rate = (unsigned)(paSI->sampleRate);
+    pi->clock_rate = (unsigned)(paPlaySI ? paPlaySI->sampleRate : 
+				paRecSI->sampleRate);
     pi->channel_count = strm->channel_count;
     pi->samples_per_frame = strm->samples_per_frame;
     pi->bits_per_sample = strm->bytes_per_sample * 8;
-    pi->rec_latency = (unsigned)(paSI->inputLatency * paSI->sampleRate);
-    pi->play_latency = (unsigned)(paSI->outputLatency * paSI->sampleRate);
+    pi->rec_latency = (unsigned)(paRecSI ? paRecSI->inputLatency * 
+					   paRecSI->sampleRate : 0);
+    pi->play_latency = (unsigned)(paPlaySI ? paPlaySI->outputLatency * 
+					     paPlaySI->sampleRate : 0);
 
     return PJ_SUCCESS;
@@ -675,9 +718,16 @@
 PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream)
 {
-    pj_status_t err;
+    int err = 0;
 
     PJ_LOG(5,(THIS_FILE, "Starting %s stream..", stream->name.ptr));
 
-    err = Pa_StartStream(stream->stream);
+    if (stream->play_strm)
+	err = Pa_StartStream(stream->play_strm);
+
+    if (err==0 && stream->rec_strm && stream->rec_strm != stream->play_strm) {
+	err = Pa_StartStream(stream->rec_strm);
+	if (err != 0)
+	    Pa_StopStream(stream->play_strm);
+    }
 
     PJ_LOG(5,(THIS_FILE, "Done, status=%d", err));
@@ -691,5 +741,5 @@
 PJ_DEF(pj_status_t) pjmedia_snd_stream_stop(pjmedia_snd_stream *stream)
 {
-    int i, err;
+    int i, err = 0;
 
     stream->quit_flag = 1;
@@ -701,5 +751,9 @@
     PJ_LOG(5,(THIS_FILE, "Stopping stream.."));
 
-    err = Pa_StopStream(stream->stream);
+    if (stream->play_strm)
+	err = Pa_StopStream(stream->play_strm);
+
+    if (stream->rec_strm && stream->rec_strm != stream->play_strm)
+	err = Pa_StopStream(stream->rec_strm);
 
     PJ_LOG(5,(THIS_FILE, "Done, status=%d", err));
@@ -713,5 +767,5 @@
 PJ_DEF(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream)
 {
-    int i, err;
+    int i, err = 0;
 
     stream->quit_flag = 1;
@@ -725,5 +779,10 @@
 			 stream->underflow, stream->overflow));
 
-    err = Pa_CloseStream(stream->stream);
+    if (stream->play_strm)
+	err = Pa_CloseStream(stream->play_strm);
+
+    if (stream->rec_strm && stream->rec_strm != stream->play_strm)
+	err = Pa_CloseStream(stream->rec_strm);
+
     pj_pool_release(stream->pool);
 
