📄 pasound.c
字号:
}
paSI = Pa_GetStreamInfo(stream->rec_strm);
paRate = (unsigned)paSI->sampleRate;
paLatency = (unsigned)(paSI->inputLatency * 1000);
PJ_LOG(5,(THIS_FILE, "Opened device %s (%s) for recording, sample "
"rate=%d, ch=%d, "
"bits=%d, %d samples per frame, latency=%d ms",
paDevInfo->name, paHostApiInfo->name,
paRate, channel_count,
bits_per_sample, samples_per_frame,
paLatency));
*p_snd_strm = stream;
return PJ_SUCCESS;
}
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_pool_t *pool;
pjmedia_snd_stream *stream;
PaStreamParameters outputParam;
int sampleFormat;
const PaDeviceInfo *paDevInfo = NULL;
const PaHostApiInfo *paHostApiInfo = NULL;
const PaStreamInfo *paSI;
unsigned paFrames, paRate, paLatency;
PaError err;
if (index < 0) {
index = pa_get_default_output_dev(channel_count);
if (index < 0) {
/* No such device. */
return PJMEDIA_ENOSNDPLAY;
}
}
paDevInfo = Pa_GetDeviceInfo(index);
if (!paDevInfo) {
/* Assumed it is "No such device" error. */
return PJMEDIA_ESNDINDEVID;
}
if (bits_per_sample == 8)
sampleFormat = paUInt8;
else if (bits_per_sample == 16)
sampleFormat = paInt16;
else if (bits_per_sample == 32)
sampleFormat = paInt32;
else
return PJMEDIA_ESNDINSAMPLEFMT;
pool = pj_pool_create( snd_mgr.factory, "sndstream", 1024, 1024, NULL);
if (!pool)
return PJ_ENOMEM;
stream = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_stream);
stream->pool = pool;
pj_strdup2_with_null(pool, &stream->name, paDevInfo->name);
stream->dir = stream->dir = PJMEDIA_DIR_PLAYBACK;
stream->play_id = index;
stream->rec_id = -1;
stream->user_data = user_data;
stream->samples_per_sec = clock_rate;
stream->samples_per_frame = samples_per_frame;
stream->bytes_per_sample = bits_per_sample / 8;
stream->channel_count = channel_count;
stream->play_cb = play_cb;
pj_bzero(&outputParam, sizeof(outputParam));
outputParam.device = index;
outputParam.channelCount = channel_count;
outputParam.hostApiSpecificStreamInfo = NULL;
outputParam.sampleFormat = sampleFormat;
outputParam.suggestedLatency = 1.0 * samples_per_frame / clock_rate;;
paHostApiInfo = Pa_GetHostApiInfo(paDevInfo->hostApi);
/* Frames in PortAudio is number of samples in a single channel */
paFrames = samples_per_frame / channel_count;
err = Pa_OpenStream( &stream->play_strm, NULL, &outputParam,
clock_rate, paFrames,
paClipOff, &PaPlayerCallback, stream );
if (err != paNoError) {
pj_pool_release(pool);
return PJMEDIA_ERRNO_FROM_PORTAUDIO(err);
}
paSI = Pa_GetStreamInfo(stream->play_strm);
paRate = (unsigned)(paSI->sampleRate);
paLatency = (unsigned)(paSI->outputLatency * 1000);
PJ_LOG(5,(THIS_FILE, "Opened device %d: %s(%s) for playing, sample rate=%d"
", ch=%d, "
"bits=%d, %d samples per frame, latency=%d ms",
index, paDevInfo->name, paHostApiInfo->name,
paRate, channel_count,
bits_per_sample, samples_per_frame, paLatency));
*p_snd_strm = stream;
return PJ_SUCCESS;
}
/*
* 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_pool_t *pool;
pjmedia_snd_stream *stream;
PaStream *paStream = NULL;
PaStreamParameters inputParam;
PaStreamParameters outputParam;
int sampleFormat;
const PaDeviceInfo *paRecDevInfo = NULL;
const PaDeviceInfo *paPlayDevInfo = NULL;
const PaHostApiInfo *paRecHostApiInfo = NULL;
const PaHostApiInfo *paPlayHostApiInfo = NULL;
const PaStreamInfo *paSI;
unsigned paFrames, paRate, paInputLatency, paOutputLatency;
PaError err;
if (rec_id < 0) {
rec_id = pa_get_default_input_dev(channel_count);
if (rec_id < 0) {
/* No such device. */
return PJMEDIA_ENOSNDREC;
}
}
paRecDevInfo = Pa_GetDeviceInfo(rec_id);
if (!paRecDevInfo) {
/* Assumed it is "No such device" error. */
return PJMEDIA_ESNDINDEVID;
}
if (play_id < 0) {
play_id = pa_get_default_output_dev(channel_count);
if (play_id < 0) {
/* No such device. */
return PJMEDIA_ENOSNDPLAY;
}
}
paPlayDevInfo = Pa_GetDeviceInfo(play_id);
if (!paPlayDevInfo) {
/* Assumed it is "No such device" error. */
return PJMEDIA_ESNDINDEVID;
}
if (bits_per_sample == 8)
sampleFormat = paUInt8;
else if (bits_per_sample == 16)
sampleFormat = paInt16;
else if (bits_per_sample == 32)
sampleFormat = paInt32;
else
return PJMEDIA_ESNDINSAMPLEFMT;
pool = pj_pool_create( snd_mgr.factory, "sndstream", 1024, 1024, NULL);
if (!pool)
return PJ_ENOMEM;
stream = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_stream);
stream->pool = pool;
pj_strdup2_with_null(pool, &stream->name, paRecDevInfo->name);
stream->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
stream->play_id = play_id;
stream->rec_id = rec_id;
stream->user_data = user_data;
stream->samples_per_sec = clock_rate;
stream->samples_per_frame = samples_per_frame;
stream->bytes_per_sample = bits_per_sample / 8;
stream->channel_count = channel_count;
stream->rec_cb = rec_cb;
stream->play_cb = play_cb;
pj_bzero(&inputParam, sizeof(inputParam));
inputParam.device = rec_id;
inputParam.channelCount = channel_count;
inputParam.hostApiSpecificStreamInfo = NULL;
inputParam.sampleFormat = sampleFormat;
inputParam.suggestedLatency = paRecDevInfo->defaultLowInputLatency;
paRecHostApiInfo = Pa_GetHostApiInfo(paRecDevInfo->hostApi);
pj_bzero(&outputParam, sizeof(outputParam));
outputParam.device = play_id;
outputParam.channelCount = channel_count;
outputParam.hostApiSpecificStreamInfo = NULL;
outputParam.sampleFormat = sampleFormat;
outputParam.suggestedLatency = paPlayDevInfo->defaultLowOutputLatency;
paPlayHostApiInfo = Pa_GetHostApiInfo(paPlayDevInfo->hostApi);
/* Frames in PortAudio is number of samples in a single channel */
paFrames = samples_per_frame / channel_count;
/* 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);
return PJMEDIA_ERRNO_FROM_PORTAUDIO(err);
}
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);
PJ_LOG(5,(THIS_FILE, "Opened device %s(%s)/%s(%s) for recording and "
"playback, sample rate=%d, ch=%d, "
"bits=%d, %d samples per frame, input latency=%d ms, "
"output latency=%d ms",
paRecDevInfo->name, paRecHostApiInfo->name,
paPlayDevInfo->name, paPlayHostApiInfo->name,
paRate, channel_count,
bits_per_sample, samples_per_frame,
paInputLatency, paOutputLatency));
*p_snd_strm = stream;
return PJ_SUCCESS;
}
/*
* Get stream info.
*/
PJ_DEF(pj_status_t) pjmedia_snd_stream_get_info(pjmedia_snd_stream *strm,
pjmedia_snd_stream_info *pi)
{
const PaStreamInfo *paPlaySI = NULL, *paRecSI = NULL;
PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
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));
pi->dir = strm->dir;
pi->play_id = strm->play_id;
pi->rec_id = strm->rec_id;
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)(paRecSI ? paRecSI->inputLatency *
paRecSI->sampleRate : 0);
pi->play_latency = (unsigned)(paPlaySI ? paPlaySI->outputLatency *
paPlaySI->sampleRate : 0);
return PJ_SUCCESS;
}
/*
* Start stream.
*/
PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream)
{
int err = 0;
PJ_LOG(5,(THIS_FILE, "Starting %s stream..", stream->name.ptr));
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));
return err ? PJMEDIA_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
}
/*
* Stop stream.
*/
PJ_DEF(pj_status_t) pjmedia_snd_stream_stop(pjmedia_snd_stream *stream)
{
int i, err = 0;
stream->quit_flag = 1;
for (i=0; !stream->rec_thread_exited && i<100; ++i)
pj_thread_sleep(10);
for (i=0; !stream->play_thread_exited && i<100; ++i)
pj_thread_sleep(10);
pj_thread_sleep(1);
PJ_LOG(5,(THIS_FILE, "Stopping 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));
return err ? PJMEDIA_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
}
/*
* Destroy stream.
*/
PJ_DEF(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream)
{
int i, err = 0;
stream->quit_flag = 1;
for (i=0; !stream->rec_thread_exited && i<100; ++i) {
pj_thread_sleep(1);
}
for (i=0; !stream->play_thread_exited && i<100; ++i) {
pj_thread_sleep(1);
}
PJ_LOG(5,(THIS_FILE, "Closing %.*s: %lu underflow, %lu overflow",
(int)stream->name.slen,
stream->name.ptr,
stream->underflow, stream->overflow));
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);
return err ? PJMEDIA_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
}
/*
* Deinitialize sound library.
*/
PJ_DEF(pj_status_t) pjmedia_snd_deinit(void)
{
if (--snd_init_count == 0) {
int err;
PJ_LOG(4,(THIS_FILE, "PortAudio sound library shutting down.."));
err = Pa_Terminate();
return err ? PJMEDIA_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
} else {
return PJ_SUCCESS;
}
}
#endif /* PJMEDIA_SOUND_IMPLEMENTATION */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -