⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dsound.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: dsound.c 974 2007-02-19 01:13:53Z bennylp $ *//*  * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * 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(push, 3)#endif#include <windows.h>#include <mmsystem.h>#include <dsound.h>#ifdef _MSC_VER#   pragma warning(pop)#endif#define THIS_FILE	    "dsound.c"#define BITS_PER_SAMPLE	    16#define BYTES_PER_SAMPLE    (BITS_PER_SAMPLE/8)#define MAX_PACKET_BUFFER_COUNT	    PJMEDIA_SOUND_BUFFER_COUNT#define DEFAULT_BUFFER_COUNT	    PJMEDIA_SOUND_BUFFER_COUNT#define MAX_HARDWARE		    16struct dsound_dev_info{    pjmedia_snd_dev_info    info;    LPGUID		    lpGuid;};static unsigned dev_count;static struct dsound_dev_info dev_info[MAX_HARDWARE];/* Individual DirectSound capture/playback stream descriptor */struct dsound_stream{    union     {	struct	{	    LPDIRECTSOUND	    lpDs;	    LPDIRECTSOUNDBUFFER	    lpDsBuffer;	} play;	struct	{	    LPDIRECTSOUNDCAPTURE	lpDs;	    LPDIRECTSOUNDCAPTUREBUFFER	lpDsBuffer;	} capture;    } ds;    HANDLE		    hEvent;    LPDIRECTSOUNDNOTIFY	    lpDsNotify;    DWORD		    dwBytePos;    DWORD		    dwDsBufferSize;    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 dsound_stream    play_strm;		/**< Playback stream.	    */    struct dsound_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.	    */    pj_bool_t		    thread_quit_flag;	/**< Quit signal to thread  */};static pj_pool_factory *pool_factory;static void init_waveformatex (PCMWAVEFORMAT *pcmwf, 			       unsigned clock_rate,			       unsigned channel_count){    pj_bzero(pcmwf, sizeof(PCMWAVEFORMAT));     pcmwf->wf.wFormatTag = WAVE_FORMAT_PCM;     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 init_player_stream( struct dsound_stream *ds_strm,				       int dev_id,				       unsigned clock_rate,				       unsigned channel_count,				       unsigned samples_per_frame,				       unsigned buffer_count){    HRESULT hr;    HWND hwnd;    PCMWAVEFORMAT pcmwf;     DSBUFFERDESC dsbdesc;    DSBPOSITIONNOTIFY dsPosNotify[MAX_PACKET_BUFFER_COUNT];    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 DirectSound device.     */    hr = DirectSoundCreate(dev_info[dev_id].lpGuid, &ds_strm->ds.play.lpDs, 			   NULL);    if (FAILED(hr))	return PJ_RETURN_OS_ERROR(hr);    hwnd = GetForegroundWindow();    if (hwnd == NULL) {	hwnd = GetDesktopWindow();    }        hr = IDirectSound_SetCooperativeLevel( ds_strm->ds.play.lpDs, hwnd, 					   DSSCL_PRIORITY);    if FAILED(hr)	return PJ_RETURN_OS_ERROR(hr);        /*     * 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. */    pj_bzero(&dsbdesc, sizeof(DSBUFFERDESC));     dsbdesc.dwSize = sizeof(DSBUFFERDESC);     dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY |		      DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS;    dsbdesc.dwBufferBytes = buffer_count * bytes_per_frame;    dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf;     /*     * Create DirectSound playback buffer.      */    hr = IDirectSound_CreateSoundBuffer(ds_strm->ds.play.lpDs, &dsbdesc, 					&ds_strm->ds.play.lpDsBuffer, NULL);     if (FAILED(hr) )	return PJ_RETURN_OS_ERROR(hr);    /*     * Create event for play notification.     */    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( ds_strm->ds.play.lpDsBuffer, 					    &IID_IDirectSoundNotify, 					    (LPVOID *)&ds_strm->lpDsNotify);     if (FAILED(hr))	return PJ_RETURN_OS_ERROR(hr);        for (i=0; i<buffer_count; ++i) {	dsPosNotify[i].dwOffset = i * bytes_per_frame;	dsPosNotify[i].hEventNotify = ds_strm->hEvent;    }        hr = IDirectSoundNotify_SetNotificationPositions( ds_strm->lpDsNotify, 						      buffer_count, 						      dsPosNotify);    if (FAILED(hr))	return PJ_RETURN_OS_ERROR(hr);    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;    /* Done setting up play device. */    PJ_LOG(5,(THIS_FILE, 	      " DirectSound 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 DirectSound recorder device */static pj_status_t init_capture_stream( struct dsound_stream *ds_strm,				        int dev_id,				        unsigned clock_rate,				        unsigned channel_count,				        unsigned samples_per_frame,				        unsigned buffer_count){    HRESULT hr;    PCMWAVEFORMAT pcmwf;     DSCBUFFERDESC dscbdesc;    DSBPOSITIONNOTIFY dsPosNotify[MAX_PACKET_BUFFER_COUNT];    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);    /*     * Creating recorder device.     */    hr = DirectSoundCaptureCreate(dev_info[dev_id].lpGuid, 				  &ds_strm->ds.capture.lpDs, NULL);    if (FAILED(hr))	return PJ_RETURN_OS_ERROR(hr);    /* 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.     */    pj_bzero(&dscbdesc, sizeof(DSCBUFFERDESC));    dscbdesc.dwSize = sizeof(DSCBUFFERDESC);     dscbdesc.dwFlags = DSCBCAPS_WAVEMAPPED ;    dscbdesc.dwBufferBytes = buffer_count * bytes_per_frame;     dscbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf;     hr = IDirectSoundCapture_CreateCaptureBuffer( ds_strm->ds.capture.lpDs,						  &dscbdesc, 						  &ds_strm->ds.capture.lpDsBuffer,						  NULL);    if (FAILED(hr))	return PJ_RETURN_OS_ERROR(hr);    /*     * Create event for play notification.     */    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( ds_strm->ds.capture.lpDsBuffer, 						   &IID_IDirectSoundNotify, 						   (LPVOID *)&ds_strm->lpDsNotify);     if (FAILED(hr))	return PJ_RETURN_OS_ERROR(hr);        for (i=0; i<buffer_count; ++i) {	dsPosNotify[i].dwOffset = i * bytes_per_frame;	dsPosNotify[i].hEventNotify = ds_strm->hEvent;    }        hr = IDirectSoundNotify_SetNotificationPositions( ds_strm->lpDsNotify, 						      buffer_count, 						      dsPosNotify);    if (FAILED(hr))	return PJ_RETURN_OS_ERROR(hr);    hr = IDirectSoundCaptureBuffer_GetCurrentPosition( ds_strm->ds.capture.lpDsBuffer, 						       NULL, &ds_strm->dwBytePos );    if (FAILED(hr))	return PJ_RETURN_OS_ERROR(hr);    ds_strm->timestamp.u64 = 0;    ds_strm->dwDsBufferSize = buffer_count * bytes_per_frame;    /* Done setting up recorder device. */    PJ_LOG(5,(THIS_FILE, 	      " DirectSound capture \"%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;}static BOOL AppReadDataFromBuffer(LPDIRECTSOUNDCAPTUREBUFFER lpDsb, // The buffer.				  DWORD dwOffset,		    // Our own write cursor.				  LPBYTE lpbSoundData,		    // Start of our data.				  DWORD dwSoundBytes)		    // Size of block to copy.{     LPVOID  lpvPtr1;     DWORD dwBytes1;     LPVOID  lpvPtr2;     DWORD dwBytes2;     HRESULT hr;         // Obtain memory address of write block. This will be in two parts    // if the block wraps around.        hr = IDirectSoundCaptureBuffer_Lock( lpDsb, dwOffset, dwSoundBytes, &lpvPtr1, 					 &dwBytes1, &lpvPtr2, &dwBytes2, 0);         if SUCCEEDED(hr) { 	// Read from pointers. 	pj_memcpy(lpbSoundData, lpvPtr1, dwBytes1); 	if (lpvPtr2 != NULL)	    pj_memcpy(lpbSoundData+dwBytes1, lpvPtr2, dwBytes2); 		// Release the data back to DirectSound. 	hr = IDirectSoundCaptureBuffer_Unlock(lpDsb, lpvPtr1, dwBytes1, lpvPtr2, dwBytes2); 	if SUCCEEDED(hr)	    return TRUE;     }         // Lock, Unlock, or Restore failed.     return FALSE; }static BOOL AppWriteDataToBuffer(LPDIRECTSOUNDBUFFER lpDsb,  // The buffer.				 DWORD dwOffset,	      // Our own write cursor.				 LPBYTE lpbSoundData,	      // Start of our data.				 DWORD dwSoundBytes)	      // Size of block to copy.{     LPVOID  lpvPtr1;     DWORD dwBytes1;     LPVOID  lpvPtr2;     DWORD dwBytes2;     HRESULT hr;         // Obtain memory address of write block. This will be in two parts    // if the block wraps around.        hr = IDirectSoundBuffer_Lock( lpDsb, dwOffset, dwSoundBytes, &lpvPtr1, 				  &dwBytes1, &lpvPtr2, &dwBytes2, 0);         // If the buffer was lost, restore and retry lock.     if (DSERR_BUFFERLOST == hr) { 	IDirectSoundBuffer_Restore(lpDsb); 	hr = IDirectSoundBuffer_Lock( lpDsb, dwOffset, dwSoundBytes, 				      &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0);     }     if SUCCEEDED(hr) { 	pj_memcpy(lpvPtr1, lpbSoundData, dwBytes1); 	if (NULL != lpvPtr2) 	    pj_memcpy(lpvPtr2, lpbSoundData+dwBytes1, dwBytes2); 		hr = IDirectSoundBuffer_Unlock(lpDsb, lpvPtr1, dwBytes1, lpvPtr2, dwBytes2); 	if SUCCEEDED(hr)	    return TRUE;     }         return FALSE; }/* * 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;    if (readPos < dsound_strm->dwBytePos)	size_available = readPos +		    (dsound_strm->dwDsBufferSize) - dsound_strm->dwBytePos;    else	size_available = readPos - dsound_strm->dwBytePos;    return size_available;}/* * DirectSound capture and playback thread. */static int dsound_dev_thread(void *arg){    pjmedia_snd_stream *strm = arg;    HANDLE events[2];    unsigned eventCount;    unsigned bytes_per_frame;    pj_status_t status;    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;    /* Raise self priority. We don't want the audio to be distorted by     * system activity.     */    //SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST);    /* 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 DirectSound capture and play buffer.     */    while (!strm->thread_quit_flag) {		DWORD rc;	pjmedia_dir signalled_dir;	rc = WaitForMultipleObjects(eventCount, events, FALSE, 				    100);	if (rc < WAIT_OBJECT_0 || rc >= WAIT_OBJECT_0+eventCount)	    continue;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -