?? dsound.c
字號:
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; 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){ 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 + -