summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pjmedia/build/pjmedia.dsp10
-rw-r--r--pjmedia/include/pjmedia/config.h19
-rw-r--r--pjmedia/include/pjmedia/errno.h1
-rw-r--r--pjmedia/src/pjmedia/dsound.c1080
-rw-r--r--pjmedia/src/pjmedia/errno.c4
-rw-r--r--pjmedia/src/pjmedia/nullsound.c4
-rw-r--r--pjmedia/src/pjmedia/pasound.c16
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_win_hostapis.c8
-rw-r--r--pjsip-apps/build/sample_debug.dsp2
-rw-r--r--pjsip-apps/src/samples/debug.c2
-rw-r--r--pjsip-apps/src/samples/sndinfo.c41
11 files changed, 578 insertions, 609 deletions
diff --git a/pjmedia/build/pjmedia.dsp b/pjmedia/build/pjmedia.dsp
index 43d09f7c..519678c0 100644
--- a/pjmedia/build/pjmedia.dsp
+++ b/pjmedia/build/pjmedia.dsp
@@ -65,7 +65,7 @@ LIB32=link.exe -lib
# PROP Intermediate_Dir ".\output\pjmedia-i386-win32-vc6-debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../src/pjmedia/portaudio" /D "_DEBUG" /D "PA_NO_ASIO" /D "PA_NO_DS" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /GZ /c
+# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../src/pjmedia/portaudio" /D "_DEBUG" /D "PA_NO_ASIO" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
@@ -96,7 +96,6 @@ SOURCE=..\src\pjmedia\conference.c
# Begin Source File
SOURCE=..\src\pjmedia\dsound.c
-# PROP Exclude_From_Build 1
# End Source File
# Begin Source File
@@ -133,6 +132,13 @@ SOURCE=..\src\pjmedia\nullsound.c
# Begin Source File
SOURCE=..\src\pjmedia\pasound.c
+
+!IF "$(CFG)" == "pjmedia - Win32 Release"
+
+!ELSEIF "$(CFG)" == "pjmedia - Win32 Debug"
+
+!ENDIF
+
# End Source File
# Begin Source File
diff --git a/pjmedia/include/pjmedia/config.h b/pjmedia/include/pjmedia/config.h
index 8e111045..a0c8bcf2 100644
--- a/pjmedia/include/pjmedia/config.h
+++ b/pjmedia/include/pjmedia/config.h
@@ -21,21 +21,20 @@
#include <pj/config.h>
-/**
- * Unless specified otherwise, PortAudio is enabled by default.
+/*
+ * Types of sound stream backends.
*/
-#ifndef PJMEDIA_HAS_PORTAUDIO_SOUND
-# define PJMEDIA_HAS_PORTAUDIO_SOUND 1
-#endif
+#define PJMEDIA_SOUND_NULL_SOUND 0
+#define PJMEDIA_SOUND_PORTAUDIO_SOUND 1
+#define PJMEDIA_SOUND_WIN32_DIRECT_SOUND 2
/**
- * Unless specified otherwise, Null sound is disabled.
- * This option is mutually exclusive with PortAudio sound, or otherwise
- * duplicate symbols error will occur.
+ * Unless specified otherwise, sound device uses PortAudio implementation
+ * by default.
*/
-#ifndef PJMEDIA_HAS_NULL_SOUND
-# define PJMEDIA_HAS_NULL_SOUND 0
+#ifndef PJMEDIA_SOUND_IMPLEMENTATION
+# define PJMEDIA_SOUND_IMPLEMENTATION PJMEDIA_SOUND_PORTAUDIO_SOUND
#endif
diff --git a/pjmedia/include/pjmedia/errno.h b/pjmedia/include/pjmedia/errno.h
index 59e665d8..213b90a9 100644
--- a/pjmedia/include/pjmedia/errno.h
+++ b/pjmedia/include/pjmedia/errno.h
@@ -19,6 +19,7 @@
#ifndef __PJMEDIA_ERRNO_H__
#define __PJMEDIA_ERRNO_H__
+#include <pjmedia/types.h>
#include <pj/errno.h>
PJ_BEGIN_DECL
diff --git a/pjmedia/src/pjmedia/dsound.c b/pjmedia/src/pjmedia/dsound.c
index 55aeef83..352ad3e5 100644
--- a/pjmedia/src/pjmedia/dsound.c
+++ b/pjmedia/src/pjmedia/dsound.c
@@ -16,498 +16,300 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#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_DIRECT_SOUND
+
#ifdef _MSC_VER
-//# pragma warning(disable: 4201) // non-standard extension: nameless struct/union
-# pragma warning(push, 3)
+# pragma warning(push, 3)
#endif
-#include <pj/config.h>
-#include <pj/os.h>
-#include <pj/log.h>
+#include <windows.h>
+#include <mmsystem.h>
#include <dsound.h>
-#include <stdio.h>
-#include <assert.h>
-#include <pjmedia/sound.h>
-#define THIS_FILE "dsound.c"
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
-/*
- * Constants
- */
-#define PACKET_BUFFER_COUNT 4
-typedef struct PJ_Direct_Sound_Device PJ_Direct_Sound_Device;
+#define THIS_FILE "dsound.c"
+#define BITS_PER_SAMPLE 16
+#define BYTES_PER_SAMPLE (BITS_PER_SAMPLE/8)
-/*
- * DirectSound Factory Operations
- */
-static pj_status_t dsound_init(void);
-static const char *dsound_get_name(void);
-static pj_status_t dsound_destroy(void);
-static pj_status_t dsound_enum_devices(int *count, char *dev_names[]);
-static pj_status_t dsound_create_dev(const char *dev_name, pj_snd_dev *dev);
-static pj_status_t dsound_destroy_dev(pj_snd_dev *dev);
+#define MAX_PACKET_BUFFER_COUNT 32
+#define DEFAULT_BUFFER_COUNT 5
-/*
- * DirectSound Device Operations
- */
-static pj_status_t dsound_dev_open( pj_snd_dev *dev, pj_snd_role_t role );
-static pj_status_t dsound_dev_close( pj_snd_dev *dev );
-static pj_status_t dsound_dev_play( pj_snd_dev *dev );
-static pj_status_t dsound_dev_record( pj_snd_dev *dev );
-/*
- * Utils.
- */
-static pj_status_t dsound_destroy_dsound_dev( PJ_Direct_Sound_Device *dsDev );
-
-
-static pj_snd_dev_factory dsound_factory =
+/* Individual DirectSound capture/playback stream descriptor */
+struct dsound_stream
{
- &dsound_init,
- &dsound_get_name,
- &dsound_destroy,
- &dsound_enum_devices,
- &dsound_create_dev,
- &dsound_destroy_dev
-};
+ union
+ {
+ struct
+ {
+ LPDIRECTSOUND lpDs;
+ LPDIRECTSOUNDBUFFER lpDsBuffer;
+ } play;
-static struct pj_snd_dev_op dsound_dev_op =
-{
- &dsound_dev_open,
- &dsound_dev_close,
- &dsound_dev_play,
- &dsound_dev_record
+ struct
+ {
+ LPDIRECTSOUNDCAPTURE lpDs;
+ LPDIRECTSOUNDCAPTUREBUFFER lpDsBuffer;
+ } capture;
+ } ds;
+
+ HANDLE hEvent;
+ LPDIRECTSOUNDNOTIFY lpDsNotify;
+ DWORD dwBytePos;
+ DWORD dwDsBufferSize;
+ pj_timestamp timestamp;
};
-#define DSOUND_TYPE_PLAYER 1
-#define DSOUND_TYPE_RECORDER 2
-typedef struct Direct_Sound_Descriptor
+/* Sound stream. */
+struct pjmedia_snd_stream
{
- int type;
-
- LPDIRECTSOUND lpDsPlay;
- LPDIRECTSOUNDBUFFER lpDsPlayBuffer;
+ pjmedia_dir dir; /**< Sound direction. */
+ 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. */
- LPDIRECTSOUNDCAPTURE lpDsCapture;
- LPDIRECTSOUNDCAPTUREBUFFER lpDsCaptureBuffer;
+ struct dsound_stream play_strm; /**< Playback stream. */
+ struct dsound_stream rec_strm; /**< Capture stream. */
- LPDIRECTSOUNDNOTIFY lpDsNotify;
- HANDLE hEvent;
- HANDLE hThread;
- HANDLE hStartEvent;
- DWORD dwThreadQuitFlag;
- pj_thread_desc thread_desc;
- pj_thread_t *thread;
-} Direct_Sound_Descriptor;
+ void *buffer; /**< Temp. frame buffer. */
+ unsigned samples_per_frame; /**< Samples per frame. */
-struct PJ_Direct_Sound_Device
-{
- Direct_Sound_Descriptor playDesc;
- Direct_Sound_Descriptor recDesc;
+ pj_thread_t *thread; /**< Thread handle. */
+ pj_bool_t thread_quit_flag; /**< Quit signal to thread */
};
-struct Thread_Param
-{
- pj_snd_dev *dev;
- Direct_Sound_Descriptor *desc;
-};
-
-PJ_DEF(pj_snd_dev_factory*) pj_dsound_get_factory()
-{
- return &dsound_factory;
-}
-
-/*
- * Init DirectSound.
- */
-static pj_status_t dsound_init(void)
-{
- /* Nothing to do. */
- return 0;
-}
-
-/*
- * Get the name of the factory.
- */
-static const char *dsound_get_name(void)
-{
- return "DirectSound";
-}
-
-/*
- * Destroy DirectSound.
- */
-static pj_status_t dsound_destroy(void)
-{
- /* TODO: clean up devices in case application haven't done it. */
- return 0;
-}
-/*
- * Enum devices in the system.
- */
-static pj_status_t dsound_enum_devices(int *count, char *dev_names[])
-{
- dev_names[0] = "DirectSound Default Device";
- *count = 1;
- return 0;
-}
+static pj_pool_factory *pool_factory;
-/*
- * Create DirectSound device.
- */
-static pj_status_t dsound_create_dev(const char *dev_name, pj_snd_dev *dev)
-{
- PJ_Direct_Sound_Device *dsDev;
-
- /* TODO: create based on the name. */
- PJ_TODO(DSOUND_CREATE_DEVICE_BY_NAME);
-
- /* Create DirectSound structure. */
- dsDev = malloc(sizeof(*dsDev));
- if (!dsDev) {
- PJ_LOG(1,(THIS_FILE, "No memory to allocate device!"));
- return -1;
- }
- memset(dsDev, 0, sizeof(*dsDev));
-
- /* Associate DirectSound device with device. */
- dev->device = dsDev;
- dev->op = &dsound_dev_op;
-
- return 0;
-}
-
-/*
- * Destroy DirectSound device.
- */
-static pj_status_t dsound_destroy_dev( pj_snd_dev *dev )
-{
- if (dev->device) {
- free(dev->device);
- dev->device = NULL;
- }
- return 0;
-}
-static void dsound_release_descriptor(Direct_Sound_Descriptor *desc)
+static void init_waveformatex (PCMWAVEFORMAT *pcmwf,
+ unsigned clock_rate,
+ unsigned channel_count)
{
- if (desc->lpDsNotify)
- IDirectSoundNotify_Release( desc->lpDsNotify );
-
- if (desc->hEvent)
- CloseHandle(desc->hEvent);
-
- if (desc->lpDsPlayBuffer)
- IDirectSoundBuffer_Release( desc->lpDsPlayBuffer );
-
- if (desc->lpDsPlay)
- IDirectSound_Release( desc->lpDsPlay );
-
- if (desc->lpDsCaptureBuffer)
- IDirectSoundCaptureBuffer_Release(desc->lpDsCaptureBuffer);
-
- if (desc->lpDsCapture)
- IDirectSoundCapture_Release(desc->lpDsCapture);
-}
-
-/*
- * Destroy DirectSound resources.
- */
-static pj_status_t dsound_destroy_dsound_dev( PJ_Direct_Sound_Device *dsDev )
-{
- dsound_release_descriptor( &dsDev->playDesc );
- dsound_release_descriptor( &dsDev->recDesc );
- memset(dsDev, 0, sizeof(*dsDev));
- return 0;
-}
-
-static void init_waveformatex (PCMWAVEFORMAT *pcmwf, pj_snd_dev *dev)
-{
- memset(pcmwf, 0, sizeof(PCMWAVEFORMAT));
+ pj_memset(pcmwf, 0, sizeof(PCMWAVEFORMAT));
pcmwf->wf.wFormatTag = WAVE_FORMAT_PCM;
- pcmwf->wf.nChannels = 1;
- pcmwf->wf.nSamplesPerSec = dev->param.samples_per_sec;
- pcmwf->wf.nBlockAlign = dev->param.bytes_per_frame;
- pcmwf->wf.nAvgBytesPerSec =
- dev->param.samples_per_sec * dev->param.bytes_per_frame;
- pcmwf->wBitsPerSample = dev->param.bits_per_sample;
+ pcmwf->wf.nChannels = (pj_uint16_t)channel_count;
+ pcmwf->wf.nSamplesPerSec = clock_rate;
+ pcmwf->wf.nBlockAlign = (pj_uint16_t)(channel_count * BYTES_PER_SAMPLE);
+ pcmwf->wf.nAvgBytesPerSec = clock_rate * channel_count * BYTES_PER_SAMPLE;
+ pcmwf->wBitsPerSample = BITS_PER_SAMPLE;
}
+
/*
* Initialize DirectSound player device.
*/
-static pj_status_t dsound_init_player (pj_snd_dev *dev)
+static pj_status_t init_player_stream( struct dsound_stream *ds_strm,
+ unsigned clock_rate,
+ unsigned channel_count,
+ unsigned samples_per_frame,
+ unsigned buffer_count)
{
HRESULT hr;
HWND hwnd;
PCMWAVEFORMAT pcmwf;
DSBUFFERDESC dsbdesc;
- DSBPOSITIONNOTIFY dsPosNotify[PACKET_BUFFER_COUNT];
+ DSBPOSITIONNOTIFY dsPosNotify[MAX_PACKET_BUFFER_COUNT];
+ unsigned bytes_per_frame;
unsigned i;
- PJ_Direct_Sound_Device *dsDev = dev->device;
- /*
- * Check parameters.
- */
- if (dev->play_cb == NULL) {
- assert(0);
- return -1;
- }
- if (dev->device == NULL) {
- assert(0);
- return -1;
- }
- PJ_LOG(4,(THIS_FILE, "Creating DirectSound player device"));
+ PJ_ASSERT_RETURN(buffer_count <= MAX_PACKET_BUFFER_COUNT, PJ_EINVAL);
/*
* Create DirectSound device.
*/
- hr = DirectSoundCreate(NULL, &dsDev->playDesc.lpDsPlay, NULL);
+ hr = DirectSoundCreate(NULL, &ds_strm->ds.play.lpDs, NULL);
if (FAILED(hr))
- goto on_error;
+ return PJ_RETURN_OS_ERROR(hr);
hwnd = GetForegroundWindow();
if (hwnd == NULL) {
hwnd = GetDesktopWindow();
}
- hr = IDirectSound_SetCooperativeLevel( dsDev->playDesc.lpDsPlay, hwnd,
+ hr = IDirectSound_SetCooperativeLevel( ds_strm->ds.play.lpDs, hwnd,
DSSCL_PRIORITY);
if FAILED(hr)
- goto on_error;
+ return PJ_RETURN_OS_ERROR(hr);
/*
- * Create DirectSound play buffer.
- */
- // Set up wave format structure.
- init_waveformatex (&pcmwf, dev);
+ * Set up wave format structure for initialize DirectSound play
+ * buffer.
+ */
+ init_waveformatex(&pcmwf, clock_rate, channel_count);
+ bytes_per_frame = samples_per_frame * BYTES_PER_SAMPLE;
- // Set up DSBUFFERDESC structure.
- memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
+ /* Set up DSBUFFERDESC structure. */
+ pj_memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
- dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY |
- DSBCAPS_GETCURRENTPOSITION2;
+ dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY;
+ /* DSBCAPS_GETCURRENTPOSITION2 */
- dsbdesc.dwBufferBytes =
- (PACKET_BUFFER_COUNT * dev->param.bytes_per_frame *
- dev->param.frames_per_packet);
+ dsbdesc.dwBufferBytes = buffer_count * bytes_per_frame;
dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf;
- // Create buffer.
- hr = IDirectSound_CreateSoundBuffer(dsDev->playDesc.lpDsPlay, &dsbdesc,
- &dsDev->playDesc.lpDsPlayBuffer, NULL);
+ /*
+ * Create DirectSound playback buffer.
+ */
+ hr = IDirectSound_CreateSoundBuffer(ds_strm->ds.play.lpDs, &dsbdesc,
+ &ds_strm->ds.play.lpDsBuffer, NULL);
if (FAILED(hr) )
- goto on_error;
+ return PJ_RETURN_OS_ERROR(hr);
/*
* Create event for play notification.
*/
- dsDev->playDesc.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL);
- if (dsDev->playDesc.hEvent == NULL)
- goto on_error;
+ ds_strm->hEvent = CreateEvent( NULL, FALSE, FALSE, NULL);
+ if (ds_strm->hEvent == NULL)
+ return pj_get_os_error();
/*
* Setup notification for play.
*/
- hr = IDirectSoundBuffer_QueryInterface( dsDev->playDesc.lpDsPlayBuffer,
+ hr = IDirectSoundBuffer_QueryInterface( ds_strm->ds.play.lpDsBuffer,
&IID_IDirectSoundNotify,
- (LPVOID *)&dsDev->playDesc.lpDsNotify);
+ (LPVOID *)&ds_strm->lpDsNotify);
if (FAILED(hr))
- goto on_error;
+ return PJ_RETURN_OS_ERROR(hr);
- for (i=0; i<PACKET_BUFFER_COUNT; ++i) {
- dsPosNotify[i].dwOffset = i * dev->param.bytes_per_frame *
- dev->param.frames_per_packet;
- dsPosNotify[i].hEventNotify = dsDev->playDesc.hEvent;
+ for (i=0; i<buffer_count; ++i) {
+ dsPosNotify[i].dwOffset = i * bytes_per_frame;
+ dsPosNotify[i].hEventNotify = ds_strm->hEvent;
}
- hr = IDirectSoundNotify_SetNotificationPositions( dsDev->playDesc.lpDsNotify,
- PACKET_BUFFER_COUNT,
+ hr = IDirectSoundNotify_SetNotificationPositions( ds_strm->lpDsNotify,
+ buffer_count,
dsPosNotify);
if (FAILED(hr))
- goto on_error;
+ return PJ_RETURN_OS_ERROR(hr);
- /* Done setting up play device. */
- PJ_LOG(4,(THIS_FILE, "DirectSound player device created"));
- return 0;
+ hr = IDirectSoundBuffer_SetCurrentPosition(ds_strm->ds.play.lpDsBuffer, 0);
+ if (FAILED(hr))
+ return PJ_RETURN_OS_ERROR(hr);
+
+
+ ds_strm->dwBytePos = 0;
+ ds_strm->dwDsBufferSize = buffer_count * bytes_per_frame;
+ ds_strm->timestamp.u64 = 0;
-on_error:
- PJ_LOG(2,(THIS_FILE, "Error creating player device, hresult=0x%x", hr));
- dsound_destroy_dsound_dev(dsDev);
- return -1;
+
+ /* Done setting up play device. */
+ PJ_LOG(5,(THIS_FILE, " DirectSound player stream initialized"));
+
+ return PJ_SUCCESS;
}
+
/*
* Initialize DirectSound recorder device
*/
-static pj_status_t dsound_init_recorder (pj_snd_dev *dev)
+static pj_status_t init_capture_stream( struct dsound_stream *ds_strm,
+ unsigned clock_rate,
+ unsigned channel_count,
+ unsigned samples_per_frame,
+ unsigned buffer_count)
{
HRESULT hr;
PCMWAVEFORMAT pcmwf;
DSCBUFFERDESC dscbdesc;
- DSBPOSITIONNOTIFY dsPosNotify[PACKET_BUFFER_COUNT];
+ DSBPOSITIONNOTIFY dsPosNotify[MAX_PACKET_BUFFER_COUNT];
+ unsigned bytes_per_frame;
unsigned i;
- PJ_Direct_Sound_Device *dsDev = dev->device;
- /*
- * Check parameters.
- */
- if (dev->rec_cb == NULL) {
- assert(0);
- return -1;
- }
- if (dev->device == NULL) {
- assert(0);
- return -1;
- }
- PJ_LOG(4,(THIS_FILE, "Creating DirectSound recorder device"));
+ PJ_ASSERT_RETURN(buffer_count <= MAX_PACKET_BUFFER_COUNT, PJ_EINVAL);
+
/*
* Creating recorder device.
*/
- hr = DirectSoundCaptureCreate(NULL, &dsDev->recDesc.lpDsCapture, NULL);
+ hr = DirectSoundCaptureCreate(NULL, &ds_strm->ds.capture.lpDs, NULL);
if (FAILED(hr))
- goto on_error;
+ return PJ_RETURN_OS_ERROR(hr);
+
- /* Init wave format */
- init_waveformatex (&pcmwf, dev);
+ /* Init wave format to initialize buffer */
+ init_waveformatex( &pcmwf, clock_rate, channel_count);
+ bytes_per_frame = samples_per_frame * BYTES_PER_SAMPLE;
/*
* Setup capture buffer using sound buffer structure that was passed
* to play buffer creation earlier.
*/
- memset(&dscbdesc, 0, sizeof(DSCBUFFERDESC));
+ pj_memset(&dscbdesc, 0, sizeof(DSCBUFFERDESC));
dscbdesc.dwSize = sizeof(DSCBUFFERDESC);
dscbdesc.dwFlags = DSCBCAPS_WAVEMAPPED ;
- dscbdesc.dwBufferBytes =
- (PACKET_BUFFER_COUNT * dev->param.bytes_per_frame *
- dev->param.frames_per_packet);
+ dscbdesc.dwBufferBytes = buffer_count * bytes_per_frame;
dscbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf;
- hr = IDirectSoundCapture_CreateCaptureBuffer( dsDev->recDesc.lpDsCapture,
+ hr = IDirectSoundCapture_CreateCaptureBuffer( ds_strm->ds.capture.lpDs,
&dscbdesc,
- &dsDev->recDesc.lpDsCaptureBuffer,
+ &ds_strm->ds.capture.lpDsBuffer,
NULL);
if (FAILED(hr))
- goto on_error;
+ return PJ_RETURN_OS_ERROR(hr);
/*
* Create event for play notification.
*/
- dsDev->recDesc.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL);
- if (dsDev->recDesc.hEvent == NULL)
- goto on_error;
+ ds_strm->hEvent = CreateEvent( NULL, FALSE, FALSE, NULL);
+ if (ds_strm->hEvent == NULL)
+ return pj_get_os_error();
/*
* Setup notifications for recording.
*/
- hr = IDirectSoundCaptureBuffer_QueryInterface( dsDev->recDesc.lpDsCaptureBuffer,
+ hr = IDirectSoundCaptureBuffer_QueryInterface( ds_strm->ds.capture.lpDsBuffer,
&IID_IDirectSoundNotify,
- (LPVOID *)&dsDev->recDesc.lpDsNotify);
+ (LPVOID *)&ds_strm->lpDsNotify);
if (FAILED(hr))
- goto on_error;
+ return PJ_RETURN_OS_ERROR(hr);
- for (i=0; i<PACKET_BUFFER_COUNT; ++i) {
- dsPosNotify[i].dwOffset = i * dev->param.bytes_per_frame *
- dev->param.frames_per_packet;
- dsPosNotify[i].hEventNotify = dsDev->recDesc.hEvent;
+ for (i=0; i<buffer_count; ++i) {
+ dsPosNotify[i].dwOffset = i * bytes_per_frame;
+ dsPosNotify[i].hEventNotify = ds_strm->hEvent;
}
- hr = IDirectSoundNotify_SetNotificationPositions( dsDev->recDesc.lpDsNotify,
- PACKET_BUFFER_COUNT,
+ hr = IDirectSoundNotify_SetNotificationPositions( ds_strm->lpDsNotify,
+ buffer_count,
dsPosNotify);
if (FAILED(hr))
- goto on_error;
+ return PJ_RETURN_OS_ERROR(hr);
- /* Done setting up recorder device. */
- PJ_LOG(4,(THIS_FILE, "DirectSound recorder device created"));
-
- return 0;
-
-on_error:
- PJ_LOG(4,(THIS_FILE, "Error creating device, hresult=%d", hr));
- dsound_destroy_dsound_dev(dsDev);
- return -1;
-}
-
-/*
- * Initialize DirectSound device.
- */
-static pj_status_t dsound_dev_open( pj_snd_dev *dev, pj_snd_role_t role )
-{
- PJ_Direct_Sound_Device *dsDev = dev->device;
- pj_status_t status;
-
- dsDev->playDesc.type = DSOUND_TYPE_PLAYER;
- dsDev->recDesc.type = DSOUND_TYPE_RECORDER;
+ hr = IDirectSoundCaptureBuffer_GetCurrentPosition( ds_strm->ds.capture.lpDsBuffer,
+ NULL, &ds_strm->dwBytePos );
+ if (FAILED(hr))
+ return PJ_RETURN_OS_ERROR(hr);
- if (role & PJ_SOUND_PLAYER) {
- status = dsound_init_player (dev);
- if (status != 0)
- return status;
- }
+ ds_strm->timestamp.u64 = 0;
+ ds_strm->dwDsBufferSize = buffer_count * bytes_per_frame;
- if (role & PJ_SOUND_RECORDER) {
- status = dsound_init_recorder (dev);
- if (status != 0)
- return status;
- }
+ /* Done setting up recorder device. */
+ PJ_LOG(5,(THIS_FILE, " DirectSound capture stream initialized"));
- return 0;
+ return PJ_SUCCESS;
}
-/*
- * Close DirectSound device.
- */
-static pj_status_t dsound_dev_close( pj_snd_dev *dev )
-{
- PJ_LOG(4,(THIS_FILE, "Closing DirectSound device"));
-
- if (dev->device) {
- PJ_Direct_Sound_Device *dsDev = dev->device;
-
- if (dsDev->playDesc.hThread) {
- PJ_LOG(4,(THIS_FILE, "Stopping DirectSound player"));
- dsDev->playDesc.dwThreadQuitFlag = 1;
- SetEvent(dsDev->playDesc.hEvent);
- if (WaitForSingleObject(dsDev->playDesc.hThread, 1000) != WAIT_OBJECT_0) {
- PJ_LOG(4,(THIS_FILE, "Timed out waiting player thread to quit"));
- TerminateThread(dsDev->playDesc.hThread, -1);
- IDirectSoundBuffer_Stop( dsDev->playDesc.lpDsPlayBuffer );
- }
-
- pj_thread_destroy (dsDev->playDesc.thread);
- }
- if (dsDev->recDesc.hThread) {
- PJ_LOG(4,(THIS_FILE, "Stopping DirectSound recorder"));
- dsDev->recDesc.dwThreadQuitFlag = 1;
- SetEvent(dsDev->recDesc.hEvent);
- if (WaitForSingleObject(dsDev->recDesc.hThread, 1000) != WAIT_OBJECT_0) {
- PJ_LOG(4,(THIS_FILE, "Timed out waiting recorder thread to quit"));
- TerminateThread(dsDev->recDesc.hThread, -1);
- IDirectSoundCaptureBuffer_Stop( dsDev->recDesc.lpDsCaptureBuffer );
- }
-
- pj_thread_destroy (dsDev->recDesc.thread);
- }
-
- dsound_destroy_dsound_dev( dev->device );
- dev->op = NULL;
- }
-
- PJ_LOG(4,(THIS_FILE, "DirectSound device closed"));
- return 0;
-}
static BOOL AppReadDataFromBuffer(LPDIRECTSOUNDCAPTUREBUFFER lpDsb, // The buffer.
DWORD dwOffset, // Our own write cursor.
@@ -583,295 +385,417 @@ static BOOL AppWriteDataToBuffer(LPDIRECTSOUNDBUFFER lpDsb, // The buffer.
/*
* Player thread.
*/
-static DWORD WINAPI dsound_dev_thread(void *arg)
+static int dsound_dev_thread(void *arg)
{
- struct Thread_Param *param = arg;
- pj_snd_dev *dev = param->dev;
- Direct_Sound_Descriptor *desc = param->desc;
- unsigned bytes_per_pkt = dev->param.bytes_per_frame *
- dev->param.frames_per_packet;
- unsigned samples_per_pkt = dev->param.samples_per_frame *
- dev->param.frames_per_packet;
- void *buffer = NULL;
- DWORD size;
+ pjmedia_snd_stream *strm = arg;
+ HANDLE events[2];
+ unsigned eventCount;
pj_status_t status;
- DWORD sample_pos;
- DWORD byte_pos;
- DWORD buffer_size =
- (PACKET_BUFFER_COUNT * dev->param.bytes_per_frame *
- dev->param.frames_per_packet);
- HRESULT hr;
-
- PJ_LOG(4,(THIS_FILE, "DirectSound thread starting"));
- /* Allocate buffer for sound data */
- buffer = malloc(bytes_per_pkt);
- if (!buffer) {
- PJ_LOG(1,(THIS_FILE, "Unable to allocate packet buffer!"));
- return (DWORD)-1;
- }
- desc->thread = pj_thread_register ("dsound", desc->thread_desc);
- if (desc->thread == NULL)
- return (DWORD)-1;
+ eventCount = 0;
+ if (strm->dir & PJMEDIA_DIR_PLAYBACK)
+ events[eventCount++] = strm->play_strm.hEvent;
+ if (strm->dir & PJMEDIA_DIR_CAPTURE)
+ events[eventCount++] = strm->rec_strm.hEvent;
- /*
- * Start playing or recording!
- */
- if (desc->type == DSOUND_TYPE_PLAYER) {
- hr = IDirectSoundBuffer_SetCurrentPosition( desc->lpDsPlayBuffer, 0);
- if (FAILED(hr)) {
- PJ_LOG(1,(THIS_FILE, "DirectSound play: SetCurrentPosition() error %d", hr));
- goto on_error;
- }
-
- hr = IDirectSoundBuffer_Play(desc->lpDsPlayBuffer, 0, 0, DSBPLAY_LOOPING);
- if (FAILED(hr)) {
- PJ_LOG(1,(THIS_FILE, "DirectSound: Play() error %d", hr));
- goto on_error;
- }
- } else {
- hr = IDirectSoundCaptureBuffer_Start(desc->lpDsCaptureBuffer, DSCBSTART_LOOPING );
- if (FAILED(hr)) {
- PJ_LOG(1,(THIS_FILE, "DirectSound: Record() error %d", hr));
- goto on_error;
- }
- }
- /*
- * Reset initial positions.
- */
- byte_pos = 0xFFFFFFFF;
- sample_pos = 0;
-
- /*
- * Wait to get the first notification.
- */
- if (WaitForSingleObject(desc->hEvent, 100) != WAIT_OBJECT_0) {
- PJ_LOG(1,(THIS_FILE, "DirectSound: error getting notification"));
- goto on_error;
- }
-
-
- /* Get initial byte position. */
- if (desc->type == DSOUND_TYPE_PLAYER) {
- hr = IDirectSoundBuffer_GetCurrentPosition( desc->lpDsPlayBuffer,
- NULL, &byte_pos );
- if (FAILED(hr)) {
- PJ_LOG(1,(THIS_FILE, "DirectSound: unable to get "
- "position, err %d", hr));
- goto on_error;
- }
- } else {
- hr = IDirectSoundCaptureBuffer_GetCurrentPosition( desc->lpDsCaptureBuffer,
- NULL, &byte_pos );
- if (FAILED(hr)) {
- PJ_LOG(1,(THIS_FILE, "DirectSound: unable to get "
- "position, err %d", hr));
- goto on_error;
- }
- }
-
- /* Signal main thread that we're running. */
- assert( desc->hStartEvent );
- SetEvent( desc->hStartEvent );
+ /* Raise self priority */
+ SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
/*
* Loop while not signalled to quit, wait for event object to be signalled
* by DirectSound play buffer, then request for sound data from the
* application and write it to DirectSound buffer.
*/
- do {
+ while (!strm->thread_quit_flag) {
- /* Call callback to get sound data */
- if (desc->type == DSOUND_TYPE_PLAYER) {
- size = bytes_per_pkt;
- status = (*dev->play_cb)(dev, sample_pos, buffer, &size);
+ DWORD rc;
+ pjmedia_dir signalled_dir;
+ struct dsound_stream *dsound_strm;
- /* Quit thread on error. */
- if (status != 0)
- break;
+ rc = WaitForMultipleObjects(eventCount, events, FALSE, 100);
+ if (rc < WAIT_OBJECT_0 || rc >= WAIT_OBJECT_0+eventCount)
+ continue;
- /* Write zeroes when we've got nothing from application. */
- if (size == 0) {
- memset(buffer, 0, bytes_per_pkt);
- size = bytes_per_pkt;
- }
+
+ if (rc == WAIT_OBJECT_0) {
+ if (events[0] == strm->play_strm.hEvent)
+ signalled_dir = PJMEDIA_DIR_PLAYBACK;
+ else
+ signalled_dir = PJMEDIA_DIR_CAPTURE;
+ } else {
+ if (events[1] == strm->play_strm.hEvent)
+ signalled_dir = PJMEDIA_DIR_PLAYBACK;
+ else
+ signalled_dir = PJMEDIA_DIR_CAPTURE;
+ }
+
+
+ if (signalled_dir == PJMEDIA_DIR_PLAYBACK) {
+
+ dsound_strm = &strm->play_strm;
+
+ /* Get frame from application. */
+ status = (*strm->play_cb)(strm->user_data,
+ dsound_strm->timestamp.u32.lo,
+ strm->buffer,
+ strm->samples_per_frame *
+ BYTES_PER_SAMPLE);
+ if (status != PJ_SUCCESS)
+ break;
/* Write to DirectSound buffer. */
- AppWriteDataToBuffer( desc->lpDsPlayBuffer, byte_pos,
- (LPBYTE)buffer, size);
+ AppWriteDataToBuffer( dsound_strm->ds.play.lpDsBuffer,
+ dsound_strm->dwBytePos,
+ (LPBYTE)strm->buffer,
+ strm->samples_per_frame * BYTES_PER_SAMPLE);
} else {
- /* Capture from DirectSound buffer. */
- size = bytes_per_pkt;
- if (AppReadDataFromBuffer( desc->lpDsCaptureBuffer, byte_pos,
- (LPBYTE)buffer, size)) {
+ BOOL rc;
- } else {
- memset(buffer, 0, size);
+ dsound_strm = &strm->rec_strm;
+
+ /* Capture from DirectSound buffer. */
+ rc = AppReadDataFromBuffer(dsound_strm->ds.capture.lpDsBuffer,
+ dsound_strm->dwBytePos,
+ (LPBYTE)strm->buffer,
+ strm->samples_per_frame *
+ BYTES_PER_SAMPLE);
+
+ if (!rc) {
+ pj_memset(strm->buffer, 0, strm->samples_per_frame *
+ BYTES_PER_SAMPLE);
}
/* Call callback */
- status = (*dev->rec_cb)(dev, sample_pos, buffer, size);
+ status = (*strm->rec_cb)(strm->user_data,
+ dsound_strm->timestamp.u32.lo,
+ strm->buffer,
+ strm->samples_per_frame *
+ BYTES_PER_SAMPLE);
/* Quit thread on error. */
- if (status != 0)
+ if (status != PJ_SUCCESS)
break;
+
}
/* Increment position. */
- byte_pos += size;
- if (byte_pos >= buffer_size)
- byte_pos -= buffer_size;
- sample_pos += samples_per_pkt;
-
- while (WaitForSingleObject(desc->hEvent, 500) != WAIT_OBJECT_0 &&
- (!desc->dwThreadQuitFlag))
- {
- Sleep(1);
- }
- } while (!desc->dwThreadQuitFlag);
+ dsound_strm->dwBytePos += strm->samples_per_frame * BYTES_PER_SAMPLE;
+ if (dsound_strm->dwBytePos >= dsound_strm->dwDsBufferSize)
+ dsound_strm->dwBytePos -= dsound_strm->dwDsBufferSize;
+ dsound_strm->timestamp.u64 += strm->samples_per_frame;
+ }
- PJ_LOG(4,(THIS_FILE, "DirectSound: stopping.."));
+ PJ_LOG(5,(THIS_FILE, "DirectSound: thread stopping.."));
- free(buffer);
- if (desc->type == DSOUND_TYPE_PLAYER) {
- IDirectSoundBuffer_Stop( desc->lpDsPlayBuffer );
- } else {
- IDirectSoundCaptureBuffer_Stop( desc->lpDsCaptureBuffer );
- }
return 0;
+}
-on_error:
- PJ_LOG(4,(THIS_FILE, "DirectSound play stopping"));
- if (buffer)
- free(buffer);
- if (desc->type == DSOUND_TYPE_PLAYER) {
- IDirectSoundBuffer_Stop( desc->lpDsPlayBuffer );
- } else {
- IDirectSoundCaptureBuffer_Stop( desc->lpDsCaptureBuffer );
- }
- desc->dwThreadQuitFlag = 1;
- /* Signal main thread that we failed to initialize */
- assert( desc->hStartEvent );
- SetEvent( desc->hStartEvent );
- return -1;
+/*
+ * Init sound library.
+ */
+PJ_DEF(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory)
+{
+ pool_factory = factory;
+ return PJ_SUCCESS;
+}
+
+/*
+ * Deinitialize sound library.
+ */
+PJ_DEF(pj_status_t) pjmedia_snd_deinit(void)
+{
+ return PJ_SUCCESS;
}
+/*
+ * Get device count.
+ */
+PJ_DEF(int) pjmedia_snd_get_dev_count(void)
+{
+ return 1;
+}
/*
- * Generic starter for play/record.
+ * Get device info.
*/
-static pj_status_t dsound_dev_play_record( pj_snd_dev *dev,
- Direct_Sound_Descriptor *desc )
+PJ_DEF(const pjmedia_snd_dev_info*) pjmedia_snd_get_dev_info(unsigned index)
{
- DWORD threadId;
- int op_type = desc->type;
- const char *op_name = (op_type == DSOUND_TYPE_PLAYER) ? "play" : "record";
- struct Thread_Param param;
+ static pjmedia_snd_dev_info info;
- PJ_LOG(4,(THIS_FILE, "DirectSound %s()", op_name));
+ PJ_UNUSED_ARG(index);
- /*
- * Create event for the thread to signal us that it is starting or
- * quitting during startup.
- */
- desc->hStartEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (desc->hStartEvent == NULL) {
- PJ_LOG(1,(THIS_FILE, "DirectSound %s: unable to create event", op_name));
- return -1;
- }
+ pj_memset(&info, 0, sizeof(info));
- param.dev = dev;
- param.desc = desc;
+ info.default_samples_per_sec = 44100;
+ info.input_count = 1;
+ info.output_count = 1;
+ pj_ansi_strcpy(info.name, "Default DirectSound Device");
- /*
- * Create thread to handle feeding up data to player/recorder.
+ return &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()
*/
- desc->hThread = NULL;
- desc->dwThreadQuitFlag = 0;
- desc->hThread = CreateThread( NULL, 0, &dsound_dev_thread, &param,
- CREATE_SUSPENDED, &threadId);
- if (!desc->hThread) {
- PJ_LOG(1,(THIS_FILE, "DirectSound %s(): unable to create thread", op_name));
- return -1;
+ 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);
+
+ /* Don't support device at present */
+ PJ_UNUSED_ARG(rec_id);
+ PJ_UNUSED_ARG(play_id);
+
+
+ /* Create and Initialize stream descriptor */
+ pool = pj_pool_create(pool_factory, "dsound-dev", 1000, 1000, NULL);
+ PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
+
+ strm = pj_pool_zalloc(pool, sizeof(pjmedia_snd_stream));
+ strm->dir = dir;
+ strm->pool = pool;
+ strm->rec_cb = rec_cb;
+ strm->play_cb = play_cb;
+ strm->user_data = user_data;
+
+ strm->samples_per_frame = samples_per_frame;
+ strm->buffer = pj_pool_alloc(pool, samples_per_frame * BYTES_PER_SAMPLE);
+ if (!strm->buffer) {
+ pj_pool_release(pool);
+ return PJ_ENOMEM;
}
- SetThreadPriority( desc->hThread, THREAD_PRIORITY_HIGHEST);
+ /* Create player stream */
+ if (dir & PJMEDIA_DIR_PLAYBACK) {
+ status = init_player_stream( &strm->play_strm, clock_rate,
+ channel_count, samples_per_frame,
+ DEFAULT_BUFFER_COUNT );
+ if (status != PJ_SUCCESS) {
+ pjmedia_snd_stream_close(strm);
+ return status;
+ }
+ }
- /*
- * Resume thread.
- */
- if (ResumeThread(desc->hThread) == (DWORD)-1) {
- PJ_LOG(1,(THIS_FILE, "DirectSound %s(): unable to resume thread", op_name));
- goto on_error;
+ /* Create capture stream */
+ if (dir & PJMEDIA_DIR_CAPTURE) {
+ status = init_capture_stream( &strm->rec_strm, clock_rate,
+ channel_count, samples_per_frame,
+ DEFAULT_BUFFER_COUNT);
+ if (status != PJ_SUCCESS) {
+ pjmedia_snd_stream_close(strm);
+ return status;
+ }
}
- /*
- * Wait until we've got signal from the thread that it has successfully
- * started, or when it is quitting.
- */
- WaitForSingleObject( desc->hStartEvent, INFINITE);
-
- /* We can destroy the event now. */
- CloseHandle( desc->hStartEvent );
- desc->hStartEvent = NULL;
-
- /* Examine thread status. */
- if (desc->dwThreadQuitFlag != 0) {
- /* Thread failed to initialize */
- WaitForSingleObject(desc->hThread, INFINITE);
- CloseHandle(desc->hThread);
- desc->hThread = NULL;
- return -1;
+
+ /* Create and start the thread */
+ status = pj_thread_create(pool, "dsound", &dsound_dev_thread, strm,
+ 0, 0, &strm->thread);
+ if (status != PJ_SUCCESS) {
+ pjmedia_snd_stream_close(strm);
+ return status;
}
- return 0;
+ *p_snd_strm = strm;
-on_error:
- TerminateThread(desc->hThread, -1);
- CloseHandle(desc->hThread);
- desc->hThread = NULL;
- return -1;
+ return PJ_SUCCESS;
}
/*
- * Start playing.
+ * Open stream.
*/
-static pj_status_t dsound_dev_play( pj_snd_dev *dev )
+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_Direct_Sound_Device *dsDev = dev->device;
+ 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);
+}
- assert(dsDev);
- if (!dsDev) {
- assert(0);
- return -1;
+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 );
+}
+
+/*
+ * Start stream.
+ */
+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_Play(stream->play_strm.ds.play.lpDsBuffer,
+ 0, 0, DSBPLAY_LOOPING);
+ if (FAILED(hr))
+ return PJ_RETURN_OS_ERROR(hr);
+ }
+
+ if (stream->rec_strm.ds.capture.lpDsBuffer) {
+ hr = IDirectSoundCaptureBuffer_Start(stream->rec_strm.ds.capture.lpDsBuffer,
+ DSCBSTART_LOOPING );
+ if (FAILED(hr))
+ return PJ_RETURN_OS_ERROR(hr);
}
- return dsound_dev_play_record( dev, &dsDev->playDesc );
+ return PJ_SUCCESS;
}
/*
- * Start recording.
+ * Stop stream.
*/
-static pj_status_t dsound_dev_record( pj_snd_dev *dev )
+PJ_DEF(pj_status_t) pjmedia_snd_stream_stop(pjmedia_snd_stream *stream)
{
- PJ_Direct_Sound_Device *dsDev = dev->device;
+ PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
+
+ if (stream->play_strm.ds.play.lpDsBuffer) {
+ PJ_LOG(5,(THIS_FILE, "Stopping DirectSound playback stream"));
+ IDirectSoundBuffer_Stop( stream->play_strm.ds.play.lpDsBuffer );
+ }
- assert(dsDev);
- if (!dsDev) {
- assert(0);
- return -1;
+ if (stream->rec_strm.ds.capture.lpDsBuffer) {
+ PJ_LOG(5,(THIS_FILE, "Stopping DirectSound capture stream"));
+ IDirectSoundCaptureBuffer_Stop(stream->rec_strm.ds.capture.lpDsBuffer);
}
- return dsound_dev_play_record( dev, &dsDev->recDesc );
+ return PJ_SUCCESS;
}
-#ifdef _MSC_VER
-# pragma warning(pop)
-# pragma warning(disable: 4514) // unreferenced inline function has been removed
-#endif
+
+/*
+ * Destroy stream.
+ */
+PJ_DEF(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream)
+{
+ PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
+
+ pjmedia_snd_stream_stop(stream);
+
+ if (stream->play_strm.lpDsNotify) {
+ IDirectSoundNotify_Release( stream->play_strm.lpDsNotify );
+ stream->play_strm.lpDsNotify = NULL;
+ }
+
+ if (stream->play_strm.hEvent) {
+ CloseHandle(stream->play_strm.hEvent);
+ stream->play_strm.hEvent = NULL;
+ }
+
+ if (stream->play_strm.ds.play.lpDsBuffer) {
+ IDirectSoundBuffer_Release( stream->play_strm.ds.play.lpDsBuffer );
+ stream->play_strm.ds.play.lpDsBuffer = NULL;
+ }
+
+ if (stream->play_strm.ds.play.lpDs) {
+ IDirectSound_Release( stream->play_strm.ds.play.lpDs );
+ stream->play_strm.ds.play.lpDs = NULL;
+ }
+
+ if (stream->rec_strm.lpDsNotify) {
+ IDirectSoundNotify_Release( stream->rec_strm.lpDsNotify );
+ stream->rec_strm.lpDsNotify = NULL;
+ }
+
+ if (stream->rec_strm.hEvent) {
+ CloseHandle(stream->rec_strm.hEvent);
+ stream->rec_strm.hEvent = NULL;
+ }
+
+ if (stream->rec_strm.ds.capture.lpDsBuffer) {
+ IDirectSoundCaptureBuffer_Release( stream->rec_strm.ds.capture.lpDsBuffer );
+ stream->rec_strm.ds.capture.lpDsBuffer = NULL;
+ }
+
+ if (stream->rec_strm.ds.capture.lpDs) {
+ IDirectSoundCapture_Release( stream->rec_strm.ds.capture.lpDs );
+ stream->rec_strm.ds.capture.lpDs = NULL;
+ }
+
+ if (stream->thread) {
+ stream->thread_quit_flag = 1;
+ pj_thread_join(stream->thread);
+ pj_thread_destroy(stream->thread);
+ stream->thread = NULL;
+ }
+
+ pj_pool_release(stream->pool);
+
+ return PJ_SUCCESS;
+}
+
+
+#endif /* PJMEDIA_SOUND_IMPLEMENTATION */
+
diff --git a/pjmedia/src/pjmedia/errno.c b/pjmedia/src/pjmedia/errno.c
index 05222bbd..5901aca3 100644
--- a/pjmedia/src/pjmedia/errno.c
+++ b/pjmedia/src/pjmedia/errno.c
@@ -147,7 +147,7 @@ PJ_DEF(pj_str_t) pjmedia_strerror( pj_status_t statcode,
#if defined(PJ_HAS_ERROR_STRING) && (PJ_HAS_ERROR_STRING != 0)
/* See if the error comes from PortAudio. */
-#if defined(PJMEDIA_HAS_PORTAUDIO_SOUND) && PJMEDIA_HAS_PORTAUDIO_SOUND!=0
+#if PJMEDIA_SOUND_IMPLEMENTATION==PJMEDIA_SOUND_PORTAUDIO_SOUND
if (statcode >= PJMEDIA_ERRNO_FROM_PORTAUDIO(paNotInitialized) &&
statcode < PJMEDIA_ERRNO_FROM_PORTAUDIO(paNotInitialized + 10000))
{
@@ -163,7 +163,7 @@ PJ_DEF(pj_str_t) pjmedia_strerror( pj_status_t statcode,
return errstr;
} else
-#endif /* PJMEDIA_HAS_PORTAUDIO_SOUND */
+#endif /* PJMEDIA_SOUND_IMPLEMENTATION */
if (statcode >= PJMEDIA_ERRNO_START &&
statcode < PJMEDIA_ERRNO_START + PJ_ERRNO_SPACE_SIZE)
{
diff --git a/pjmedia/src/pjmedia/nullsound.c b/pjmedia/src/pjmedia/nullsound.c
index e60cfa31..8ff8bc93 100644
--- a/pjmedia/src/pjmedia/nullsound.c
+++ b/pjmedia/src/pjmedia/nullsound.c
@@ -19,7 +19,7 @@
#include <pjmedia/sound.h>
#include <pj/assert.h>
-#if defined(PJMEDIA_HAS_NULL_SOUND) && PJMEDIA_HAS_NULL_SOUND!=0
+#if PJMEDIA_SOUND_IMPLEMENTATION==PJMEDIA_SOUND_NULL_SOUND
static pjmedia_snd_dev_info null_info =
{
@@ -142,4 +142,4 @@ PJ_DEF(pj_status_t) pjmedia_snd_deinit(void)
}
-#endif /* PJMEDIA_HAS_NULL_SOUND */
+#endif /* PJMEDIA_SOUND_IMPLEMENTATION */
diff --git a/pjmedia/src/pjmedia/pasound.c b/pjmedia/src/pjmedia/pasound.c
index 769a1c14..c019c258 100644
--- a/pjmedia/src/pjmedia/pasound.c
+++ b/pjmedia/src/pjmedia/pasound.c
@@ -23,7 +23,7 @@
#include <pj/string.h>
#include <portaudio.h>
-#if defined(PJMEDIA_HAS_PORTAUDIO_SOUND) && PJMEDIA_HAS_PORTAUDIO_SOUND!=0
+#if PJMEDIA_SOUND_IMPLEMENTATION==PJMEDIA_SOUND_PORTAUDIO_SOUND
#define THIS_FILE "pasound.c"
@@ -280,7 +280,7 @@ PJ_DEF(pj_status_t) pjmedia_snd_open_rec( int index,
pj_strdup2_with_null(pool, &stream->name, paDevInfo->name);
stream->dir = PJMEDIA_DIR_CAPTURE;
stream->user_data = user_data;
- stream->samples_per_sec = samples_per_frame;
+ stream->samples_per_sec = clock_rate;
stream->bytes_per_sample = bits_per_sample / 8;
stream->channel_count = channel_count;
stream->rec_cb = rec_cb;
@@ -373,7 +373,7 @@ PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index,
pj_strdup2_with_null(pool, &stream->name, paDevInfo->name);
stream->dir = stream->dir = PJMEDIA_DIR_PLAYBACK;
stream->user_data = user_data;
- stream->samples_per_sec = samples_per_frame;
+ stream->samples_per_sec = clock_rate;
stream->bytes_per_sample = bits_per_sample / 8;
stream->channel_count = channel_count;
stream->play_cb = play_cb;
@@ -383,7 +383,7 @@ PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index,
outputParam.channelCount = channel_count;
outputParam.hostApiSpecificStreamInfo = NULL;
outputParam.sampleFormat = sampleFormat;
- outputParam.suggestedLatency = paDevInfo->defaultLowInputLatency;
+ outputParam.suggestedLatency = 1.0 * samples_per_frame / clock_rate;;
paHostApiInfo = Pa_GetHostApiInfo(paDevInfo->hostApi);
@@ -398,11 +398,11 @@ PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index,
return PJMEDIA_ERRNO_FROM_PORTAUDIO(err);
}
- PJ_LOG(5,(THIS_FILE, "%s opening device %s(%s) for playing, sample rate=%d"
+ PJ_LOG(5,(THIS_FILE, "%s opening device %d: %s(%s) for playing, sample rate=%d"
", ch=%d, "
"bits=%d, %d samples per frame",
(err==0 ? "Success" : "Error"),
- paDevInfo->name, paHostApiInfo->name,
+ index, paDevInfo->name, paHostApiInfo->name,
clock_rate, channel_count,
bits_per_sample, samples_per_frame));
@@ -494,7 +494,7 @@ PJ_DEF(pj_status_t) pjmedia_snd_open( int rec_id,
pj_strdup2_with_null(pool, &stream->name, paRecDevInfo->name);
stream->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
stream->user_data = user_data;
- stream->samples_per_sec = samples_per_frame;
+ stream->samples_per_sec = clock_rate;
stream->bytes_per_sample = bits_per_sample / 8;
stream->channel_count = channel_count;
stream->rec_cb = rec_cb;
@@ -620,4 +620,4 @@ PJ_DEF(pj_status_t) pjmedia_snd_deinit(void)
}
-#endif /* PJMEDIA_HAS_PORTAUDIO_SOUND */
+#endif /* PJMEDIA_SOUND_IMPLEMENTATION */
diff --git a/pjmedia/src/pjmedia/portaudio/pa_win_hostapis.c b/pjmedia/src/pjmedia/portaudio/pa_win_hostapis.c
index 4e07fee2..eb1d3aba 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_win_hostapis.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_win_hostapis.c
@@ -58,14 +58,14 @@ PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
PaUtilHostApiInitializer *paHostApiInitializers[] =
{
-#ifndef PA_NO_WMME
- PaWinMme_Initialize,
-#endif
-
#ifndef PA_NO_DS
PaWinDs_Initialize,
#endif
+#ifndef PA_NO_WMME
+ PaWinMme_Initialize,
+#endif
+
#ifndef PA_NO_ASIO
PaAsio_Initialize,
#endif
diff --git a/pjsip-apps/build/sample_debug.dsp b/pjsip-apps/build/sample_debug.dsp
index d725d171..a6af92cb 100644
--- a/pjsip-apps/build/sample_debug.dsp
+++ b/pjsip-apps/build/sample_debug.dsp
@@ -50,7 +50,7 @@ BSC32=bscmake.exe
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
-# ADD LINK32 ole32.lib user32.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"../bin/samples/sampledebug_vc6.exe"
+# ADD LINK32 ole32.lib user32.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /map /machine:I386 /out:"../bin/samples/sampledebug_vc6.exe"
!ELSEIF "$(CFG)" == "sample_debug - Win32 Debug"
diff --git a/pjsip-apps/src/samples/debug.c b/pjsip-apps/src/samples/debug.c
index 7e295392..44523301 100644
--- a/pjsip-apps/src/samples/debug.c
+++ b/pjsip-apps/src/samples/debug.c
@@ -27,5 +27,5 @@
* E.g.:
* #include "playfile.c"
*/
-#include "resampleplay.c"
+#include "playfile.c"
diff --git a/pjsip-apps/src/samples/sndinfo.c b/pjsip-apps/src/samples/sndinfo.c
index 7c9f599e..07e5df66 100644
--- a/pjsip-apps/src/samples/sndinfo.c
+++ b/pjsip-apps/src/samples/sndinfo.c
@@ -75,11 +75,37 @@ static void enum_devices(void)
static int play_counter;
static int rec_counter;
+static int min_delay = 0xFFFF, max_delay;
+static char play_delays[1000];
static pj_status_t play_cb(void *user_data, pj_uint32_t timestamp,
void *output, unsigned size)
{
+ static pj_time_val last_cb;
+
++play_counter;
+
+ if (last_cb.sec == 0 && last_cb.msec == 0) {
+ pj_gettimeofday(&last_cb);
+ } else {
+ pj_time_val now, saved;
+ int delay;
+
+ pj_gettimeofday(&now);
+ saved = now;
+ PJ_TIME_VAL_SUB(now, last_cb);
+ delay = PJ_TIME_VAL_MSEC(now);
+
+ if (delay < min_delay)
+ min_delay = delay;
+ if (delay > max_delay)
+ max_delay = delay;
+
+ last_cb = saved;
+
+ play_delays[play_counter-1] = delay;
+ }
+
return PJ_SUCCESS;
}
@@ -98,7 +124,7 @@ static void app_perror(const char *title, pj_status_t status)
printf( "%s: %s (err=%d)\n",
title, errmsg, status);
}
-
+
static int open_device(int dev_id, pjmedia_dir dir,
int clock_rate, int nchannel, int bits)
{
@@ -106,6 +132,7 @@ static int open_device(int dev_id, pjmedia_dir dir,
unsigned nsamples;
pjmedia_snd_stream *strm;
const char *dirtype;
+ unsigned i;
switch (dir) {
case PJMEDIA_DIR_CAPTURE:
@@ -165,6 +192,18 @@ static int open_device(int dev_id, pjmedia_dir dir,
}
puts("Success.");
+
+ printf("Delay: ");
+ for (i=0; i<play_counter; ++i)
+ printf("%d ", play_delays[i]);
+
+ puts("");
+ if (dir & PJMEDIA_DIR_PLAYBACK) {
+ printf("Callback interval: min interval=%d ms, max interval=%d ms\n",
+ min_delay, max_delay);
+ }
+
+
return 0;
}