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

📄 dsound.c

📁 一个开源的sip源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	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) {
	    
	    struct dsound_stream *dsound_strm;

	    /*
	     * DirectSound has requested us to feed some frames to
	     * playback buffer.
	     */

	    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;

	    /* 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;

	} else {
	    /*
	     * DirectSound has indicated that it has some frames ready
	     * in the capture buffer. Get as much frames as possible to
	     * prevent overflows.
	     */
	    struct dsound_stream *dsound_strm;
	    BOOL rc;

	    dsound_strm = &strm->rec_strm;

	    do {
		/* 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);
		} 

		/* Call callback */
		status = (*strm->rec_cb)(strm->user_data, 
					 dsound_strm->timestamp.u32.lo, 
					 strm->buffer, 
					 bytes_per_frame);

		/* Quit thread on error. */
		if (status != PJ_SUCCESS)
		    goto on_error;


		/* 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;

		/* Fetch while we have more than 1 frame */
	    } while (dsound_captured_size(dsound_strm) > bytes_per_frame);

	}
    }


on_error:
    PJ_LOG(5,(THIS_FILE, "DirectSound: thread stopping.."));
    return 0;
}


/* DirectSound enum device callback */
static BOOL CALLBACK DSEnumCallback( LPGUID lpGuid, LPCSTR lpcstrDescription,  
				     LPCSTR lpcstrModule, LPVOID lpContext)
{
    unsigned index, max = sizeof(dev_info[index].info.name);
    pj_bool_t is_capture_device = (lpContext != NULL);


    PJ_UNUSED_ARG(lpcstrModule);


    /* Put the capture and playback of the same devices to the same 
     * dev_info item, by looking at the GUID.
     */
    for (index=0; index<dev_count; ++index) {
	if (dev_info[index].lpGuid == lpGuid)
	    break;
    }

    if (index == dev_count)
	++dev_count;
    else if (dev_count >= MAX_HARDWARE) {
	pj_assert(!"Too many DirectSound hardware found");
	PJ_LOG(4,(THIS_FILE, "Too many hardware found, some devices will "
			     "not be listed"));
	return FALSE;
    }

    strncpy(dev_info[index].info.name, lpcstrDescription, max);
    dev_info[index].info.name[max-1] = '\0';
    dev_info[index].lpGuid = lpGuid;
    dev_info[index].info.default_samples_per_sec = 44100;
    
    /* Just assumed that device supports stereo capture/playback */
    if (is_capture_device)
	dev_info[index].info.input_count+=2;
    else
	dev_info[index].info.output_count+=2;

    return TRUE;
}


/*
 * Init sound library.
 */
PJ_DEF(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory)
{
    HRESULT hr;
    unsigned i;

    if (++snd_init_count != 1)
	return PJ_SUCCESS;

    pool_factory = factory;

    /* Enumerate sound playback devices */
    hr = DirectSoundEnumerate(&DSEnumCallback, NULL);
    if (FAILED(hr))
	return PJ_RETURN_OS_ERROR(hr);

    /* Enumerate sound capture devices */
    hr = DirectSoundCaptureEnumerate(&DSEnumCallback, (void*)1);
    if (FAILED(hr))
	return PJ_RETURN_OS_ERROR(hr);

    PJ_LOG(4,(THIS_FILE, "DirectSound initialized, found %d devices:",
	      dev_count));
    for (i=0; i<dev_count; ++i) {
	PJ_LOG(4,(THIS_FILE, " dev_id %d: %s  (in=%d, out=%d)", 
		  i, dev_info[i].info.name, 
		  dev_info[i].info.input_count, 
		  dev_info[i].info.output_count));
    }

    return PJ_SUCCESS;
}

/*
 * Deinitialize sound library.
 */
PJ_DEF(pj_status_t) pjmedia_snd_deinit(void)
{
    --snd_init_count;
    return PJ_SUCCESS;
}

/*
 * Get device count.
 */
PJ_DEF(int) pjmedia_snd_get_dev_count(void)
{
    return dev_count;
}

/*
 * Get device info.
 */
PJ_DEF(const pjmedia_snd_dev_info*) pjmedia_snd_get_dev_info(unsigned index)
{
    if (index == (unsigned)-1) 
	index = 0;

    PJ_ASSERT_RETURN(index < dev_count, NULL);

    return &dev_info[index].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()
     */
    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);

    /* 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->play_id = play_id;
    strm->rec_id = rec_id;
    strm->pool = pool;
    strm->rec_cb = rec_cb;
    strm->play_cb = play_cb;
    strm->user_data = user_data;
    strm->clock_rate = clock_rate;
    strm->samples_per_frame = samples_per_frame;
    strm->bits_per_sample = bits_per_sample;
    strm->channel_count = channel_count;
    strm->buffer = pj_pool_alloc(pool, samples_per_frame * BYTES_PER_SAMPLE);
    if (!strm->buffer) {
	pj_pool_release(pool);
	return PJ_ENOMEM;
    }

    /* Create player stream */
    if (dir & PJMEDIA_DIR_PLAYBACK) {
	status = init_player_stream( &strm->play_strm, play_id, clock_rate,
				     channel_count, samples_per_frame,
				     DEFAULT_BUFFER_COUNT );
	if (status != PJ_SUCCESS) {
	    pjmedia_snd_stream_close(strm);
	    return status;
	}
    }

    /* Create capture stream */
    if (dir & PJMEDIA_DIR_CAPTURE) {
	status = init_capture_stream( &strm->rec_strm, rec_id, clock_rate,
				      channel_count, samples_per_frame,
				      DEFAULT_BUFFER_COUNT);
	if (status != PJ_SUCCESS) {
	    pjmedia_snd_stream_close(strm);
	    return status;
	}
    }


    /* 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;
    }

    *p_snd_strm = strm;

    return PJ_SUCCESS;
}

/*
 * Open stream.
 */
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_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);
}

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 );
}

/*
 * Get stream info.
 */
PJ_DEF(pj_status_t) pjmedia_snd_stream_get_info(pjmedia_snd_stream *strm,
						pjmedia_snd_stream_info *pi)
{

    PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);

    pj_bzero(pi, sizeof(*pi));
    pi->dir = strm->dir;
    pi->play_id = strm->play_id;
    pi->rec_id = strm->rec_id;
    pi->clock_rate = strm->clock_rate;
    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 = 0;
    pi->play_latency = 0;

    return PJ_SUCCESS;
}


/*
 * 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);
	PJ_LOG(5,(THIS_FILE, "DirectSound playback stream started"));
    }
    
    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);
	PJ_LOG(5,(THIS_FILE, "DirectSound capture stream started"));
    }

    return PJ_SUCCESS;
}

/*
 * Stop stream.
 */
PJ_DEF(pj_status_t) pjmedia_snd_stream_stop(pjmedia_snd_stream *stream)
{
    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 );
    }

    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 PJ_SUCCESS;
}


/*
 * 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->thread) {
	stream->thread_quit_flag = 1;
	pj_thread_join(stream->thread);
	pj_thread_destroy(stream->thread);
	stream->thread = NULL;
    }

    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;
    }


    pj_pool_release(stream->pool);

    return PJ_SUCCESS;
}


#endif	/* PJMEDIA_SOUND_IMPLEMENTATION */

⌨️ 快捷键说明

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