From de8a259f42cc5b01aff0bcccb56cfe8a7075a2b0 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Wed, 15 Mar 2006 20:56:04 +0000 Subject: [PATCH] Tidying up sound device, register PortAudio error codes, and initial support for stereo sound device (untested) git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@319 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/include/pjmedia/errno.h | 11 ++ pjmedia/include/pjmedia/sound.h | 37 +++---- pjmedia/src/pjmedia/conference.c | 34 +++--- pjmedia/src/pjmedia/errno.c | 20 +++- pjmedia/src/pjmedia/pasound.c | 125 ++++++++++++---------- pjmedia/src/pjmedia/portaudio/portaudio.h | 2 +- pjmedia/src/pjmedia/stream.c | 38 +------ 7 files changed, 133 insertions(+), 134 deletions(-) diff --git a/pjmedia/include/pjmedia/errno.h b/pjmedia/include/pjmedia/errno.h index 354383b2e..7537744a0 100644 --- a/pjmedia/include/pjmedia/errno.h +++ b/pjmedia/include/pjmedia/errno.h @@ -30,6 +30,17 @@ PJ_BEGIN_DECL #define PJMEDIA_ERRNO_START (PJ_ERRNO_START_USER + PJ_ERRNO_SPACE_SIZE) +/* + * Mapping from PortAudio error codes to pjmedia error space. + */ +#define PJMEDIA_PORTAUDIO_ERRNO_START (PJMEDIA_ERRNO_START+PJ_ERRNO_SPACE_SIZE-1000) + +/* + * Convert PortAudio error code to PJMEDIA error code. + */ +#define PJMEDIA_ERRNO_FROM_PORTAUDIO(err) (err+PJMEDIA_PORTAUDIO_ERRNO_START) + + /************************************************************ * GENERIC/GENERAL PJMEDIA ERRORS ***********************************************************/ diff --git a/pjmedia/include/pjmedia/sound.h b/pjmedia/include/pjmedia/sound.h index 53c0907de..ec7564fa8 100644 --- a/pjmedia/include/pjmedia/sound.h +++ b/pjmedia/include/pjmedia/sound.h @@ -49,19 +49,6 @@ typedef struct pj_snd_dev_info unsigned default_samples_per_sec;/**< Default sampling rate. */ } pj_snd_dev_info; -/** - * Sound device parameter, to be specified when calling #pj_snd_open_recorder - * or #pj_snd_open_player. - */ -typedef struct pj_snd_stream_info -{ - unsigned samples_per_sec; /**< Sampling rate. */ - unsigned bits_per_sample; /**< No of bits per sample. */ - unsigned samples_per_frame; /**< No of samples per frame. */ - unsigned bytes_per_frame; /**< No of bytes per frame. */ - unsigned frames_per_packet; /**< No of frames per packet. */ -} pj_snd_stream_info; - /** * This callback is called by player stream when it needs additional data * to be played by the device. Application must fill in the whole of output @@ -134,10 +121,14 @@ PJ_DECL(const pj_snd_dev_info*) pj_snd_get_dev_info(unsigned index); * * @return Audio stream, or NULL if failed. */ -PJ_DECL(pj_snd_stream*) pj_snd_open_recorder(int index, - const pj_snd_stream_info *param, - pj_snd_rec_cb rec_cb, - void *user_data); +PJ_DECL(pj_status_t) pj_snd_open_recorder( int index, + unsigned clock_rate, + unsigned channel_count, + unsigned samples_per_frame, + unsigned bits_per_sample, + pj_snd_rec_cb rec_cb, + void *user_data, + pj_snd_stream **p_snd_strm); /** * Create a new audio stream for playing audio samples. @@ -150,10 +141,14 @@ PJ_DECL(pj_snd_stream*) pj_snd_open_recorder(int index, * * @return Audio stream, or NULL if failed. */ -PJ_DECL(pj_snd_stream*) pj_snd_open_player(int index, - const pj_snd_stream_info *param, - pj_snd_play_cb play_cb, - void *user_data); +PJ_DECL(pj_status_t) pj_snd_open_player( int index, + unsigned clock_rate, + unsigned channel_count, + unsigned samples_per_frame, + unsigned bits_per_sample, + pj_snd_play_cb play_cb, + void *user_data, + pj_snd_stream **p_snd_strm ); /** * Start the stream. diff --git a/pjmedia/src/pjmedia/conference.c b/pjmedia/src/pjmedia/conference.c index 90c24e638..3dbe7c5ae 100644 --- a/pjmedia/src/pjmedia/conference.c +++ b/pjmedia/src/pjmedia/conference.c @@ -139,7 +139,6 @@ struct pjmedia_conf unsigned clock_rate; /**< Sampling rate. */ unsigned samples_per_frame; /**< Samples per frame. */ unsigned bits_per_sample; /**< Bits per sample. */ - pj_snd_stream_info snd_info; /**< Sound device parameter. */ }; @@ -286,15 +285,6 @@ static pj_status_t create_sound_port( pj_pool_t *pool, pj_status_t status; - /* Init default sound device parameters. */ - pj_memset(&conf->snd_info, 0, sizeof(conf->snd_info)); - conf->snd_info.samples_per_sec = conf->clock_rate; - conf->snd_info.bits_per_sample = conf->bits_per_sample; - conf->snd_info.samples_per_frame = conf->samples_per_frame; - conf->snd_info.bytes_per_frame = conf->samples_per_frame * - conf->bits_per_sample / 8; - conf->snd_info.frames_per_packet = 1; - /* Create port */ status = create_conf_port(pool, conf, NULL, &name, &conf_port); @@ -388,22 +378,32 @@ PJ_DEF(pj_status_t) pjmedia_conf_create( pj_pool_t *pool, */ static pj_status_t create_sound( pjmedia_conf *conf ) { + pj_status_t status; + /* Open recorder only if mic is not disabled. */ if ((conf->options & PJMEDIA_CONF_NO_MIC) == 0) { - conf->snd_rec = pj_snd_open_recorder(-1 ,&conf->snd_info, - &rec_cb, conf); - if (conf->snd_rec == NULL) { - return -1; + status = pj_snd_open_recorder(-1, conf->clock_rate, 1, + conf->samples_per_frame, + conf->bits_per_sample, + &rec_cb, conf, &conf->snd_rec); + if (status != PJ_SUCCESS) { + conf->snd_rec = NULL; + return status; } } /* Open player */ - conf->snd_player = pj_snd_open_player(-1, &conf->snd_info, &play_cb, conf); - if (conf->snd_player == NULL) { + status = pj_snd_open_player(-1, conf->clock_rate, 1, + conf->samples_per_frame, + conf->bits_per_sample, + &play_cb, conf, &conf->snd_player); + if (status != PJ_SUCCESS) { if (conf->snd_rec) { pj_snd_stream_close(conf->snd_rec); + conf->snd_rec = NULL; } - return -1; + conf->snd_player = NULL; + return status; } return PJ_SUCCESS; diff --git a/pjmedia/src/pjmedia/errno.c b/pjmedia/src/pjmedia/errno.c index 6fb71e0a9..b9886796c 100644 --- a/pjmedia/src/pjmedia/errno.c +++ b/pjmedia/src/pjmedia/errno.c @@ -18,6 +18,7 @@ */ #include #include +#include @@ -129,8 +130,23 @@ PJ_DEF(pj_str_t) pjmedia_strerror( pj_status_t statcode, { pj_str_t errstr; - if (statcode >= PJMEDIA_ERRNO_START && - statcode < PJMEDIA_ERRNO_START + PJ_ERRNO_SPACE_SIZE) + /* See if the error comes from PortAudio. */ + if (statcode >= PJMEDIA_ERRNO_FROM_PORTAUDIO(paNotInitialized) && + statcode < PJMEDIA_ERRNO_FROM_PORTAUDIO(paNotInitialized + 10000)) + { + + int pa_err = statcode - PJMEDIA_ERRNO_FROM_PORTAUDIO(0); + pj_str_t msg; + + msg.ptr = (char*)Pa_GetErrorText(pa_err); + msg.slen = pj_ansi_strlen(msg.ptr); + + errstr.ptr = buf; + pj_strncpy_with_null(&errstr, &msg, bufsize); + return errstr; + + } else if (statcode >= PJMEDIA_ERRNO_START && + statcode < PJMEDIA_ERRNO_START + PJ_ERRNO_SPACE_SIZE) { /* Find the error in the table. * Use binary search! diff --git a/pjmedia/src/pjmedia/pasound.c b/pjmedia/src/pjmedia/pasound.c index 69a3c892f..176f98ed9 100644 --- a/pjmedia/src/pjmedia/pasound.c +++ b/pjmedia/src/pjmedia/pasound.c @@ -17,9 +17,10 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include -#include -#include +#include #include +#include +#include #include #define THIS_FILE "pasound.c" @@ -37,6 +38,7 @@ struct pj_snd_stream int dev_index; int bytes_per_sample; pj_uint32_t samples_per_sec; + int channel_count; pj_uint32_t timestamp; pj_uint32_t underflow; pj_uint32_t overflow; @@ -188,10 +190,14 @@ PJ_DEF(const pj_snd_dev_info*) pj_snd_get_dev_info(unsigned index) /* * Open stream. */ -PJ_DEF(pj_snd_stream*) pj_snd_open_recorder( int index, - const pj_snd_stream_info *param, - pj_snd_rec_cb rec_cb, - void *user_data) +PJ_DEF(pj_status_t) pj_snd_open_recorder( int index, + unsigned clock_rate, + unsigned channel_count, + unsigned samples_per_frame, + unsigned bits_per_sample, + pj_snd_rec_cb rec_cb, + void *user_data, + pj_snd_stream **p_snd_strm) { pj_pool_t *pool; pj_snd_stream *stream; @@ -208,70 +214,75 @@ PJ_DEF(pj_snd_stream*) pj_snd_open_recorder( int index, break; } if (index == count) { - PJ_LOG(2,(THIS_FILE, "Error: unable to find recorder device")); - return NULL; + /* No such device. */ + return PJ_ENOTFOUND; } } else { paDevInfo = Pa_GetDeviceInfo(index); - if (!paDevInfo) - return NULL; + if (!paDevInfo) { + /* Assumed it is "No such device" error. */ + return PJ_ENOTFOUND; + } } - if (param->bits_per_sample == 8) + if (bits_per_sample == 8) sampleFormat = paUInt8; - else if (param->bits_per_sample == 16) + else if (bits_per_sample == 16) sampleFormat = paInt16; - else if (param->bits_per_sample == 32) + else if (bits_per_sample == 32) sampleFormat = paInt32; else - return NULL; + return PJ_ENOTSUP; pool = pj_pool_create( snd_mgr.factory, "sndstream", 1024, 1024, NULL); if (!pool) - return NULL; + return PJ_ENOMEM; - stream = pj_pool_calloc(pool, 1, sizeof(*stream)); + stream = pj_pool_zalloc(pool, sizeof(*stream)); stream->pool = pool; - stream->name = pj_str("recorder"); + stream->name = pj_str("snd-rec"); stream->user_data = user_data; stream->dev_index = index; - stream->samples_per_sec = param->samples_per_frame; - stream->bytes_per_sample = param->bits_per_sample / 8; + stream->samples_per_sec = samples_per_frame; + stream->bytes_per_sample = bits_per_sample / 8; + stream->channel_count = channel_count; stream->rec_cb = rec_cb; pj_memset(&inputParam, 0, sizeof(inputParam)); inputParam.device = index; - inputParam.channelCount = 1; + inputParam.channelCount = channel_count; inputParam.hostApiSpecificStreamInfo = NULL; inputParam.sampleFormat = sampleFormat; inputParam.suggestedLatency = paDevInfo->defaultLowInputLatency; err = Pa_OpenStream( &stream->stream, &inputParam, NULL, - param->samples_per_sec, - param->samples_per_frame * param->frames_per_packet, - 0, - &PaRecorderCallback, stream ); + clock_rate, samples_per_frame, + 0, &PaRecorderCallback, stream ); if (err != paNoError) { pj_pool_release(pool); - PJ_LOG(2,(THIS_FILE, "Error opening player: %s", Pa_GetErrorText(err))); - return NULL; + return PJMEDIA_ERRNO_FROM_PORTAUDIO(err); } PJ_LOG(5,(THIS_FILE, "%s opening device %s for recording, sample rate=%d, " + "channel count=%d, " "%d bits per sample, %d samples per buffer", (err==0 ? "Success" : "Error"), - paDevInfo->name, param->samples_per_sec, - param->bits_per_sample, - param->samples_per_frame * param->frames_per_packet)); + paDevInfo->name, clock_rate, channel_count, + bits_per_sample, samples_per_frame)); - return stream; + *p_snd_strm = stream; + return PJ_SUCCESS; } -PJ_DEF(pj_snd_stream*) pj_snd_open_player(int index, - const pj_snd_stream_info *param, - pj_snd_play_cb play_cb, - void *user_data) +PJ_DEF(pj_status_t) pj_snd_open_player( int index, + unsigned clock_rate, + unsigned channel_count, + unsigned samples_per_frame, + unsigned bits_per_sample, + pj_snd_play_cb play_cb, + void *user_data, + pj_snd_stream **p_snd_strm) { pj_pool_t *pool; pj_snd_stream *stream; @@ -288,63 +299,65 @@ PJ_DEF(pj_snd_stream*) pj_snd_open_player(int index, break; } if (index == count) { - PJ_LOG(2,(THIS_FILE, "Error: unable to find player device")); - return NULL; + /* No such device. */ + return PJ_ENOTFOUND; } } else { paDevInfo = Pa_GetDeviceInfo(index); - if (!paDevInfo) - return NULL; + if (!paDevInfo) { + /* Assumed it is "No such device" error. */ + return PJ_ENOTFOUND; + } } - if (param->bits_per_sample == 8) + if (bits_per_sample == 8) sampleFormat = paUInt8; - else if (param->bits_per_sample == 16) + else if (bits_per_sample == 16) sampleFormat = paInt16; - else if (param->bits_per_sample == 32) + else if (bits_per_sample == 32) sampleFormat = paInt32; else - return NULL; + return PJ_ENOTSUP; pool = pj_pool_create( snd_mgr.factory, "sndstream", 1024, 1024, NULL); if (!pool) - return NULL; + return PJ_ENOMEM; stream = pj_pool_calloc(pool, 1, sizeof(*stream)); stream->pool = pool; stream->name = pj_str("player"); stream->user_data = user_data; - stream->samples_per_sec = param->samples_per_frame; - stream->bytes_per_sample = param->bits_per_sample / 8; + stream->samples_per_sec = samples_per_frame; + stream->bytes_per_sample = bits_per_sample / 8; + stream->channel_count = channel_count; stream->dev_index = index; stream->play_cb = play_cb; pj_memset(&outputParam, 0, sizeof(outputParam)); outputParam.device = index; - outputParam.channelCount = 1; + outputParam.channelCount = channel_count; outputParam.hostApiSpecificStreamInfo = NULL; outputParam.sampleFormat = sampleFormat; outputParam.suggestedLatency = paDevInfo->defaultLowInputLatency; err = Pa_OpenStream( &stream->stream, NULL, &outputParam, - param->samples_per_sec, - param->samples_per_frame * param->frames_per_packet, - 0, - &PaPlayerCallback, stream ); + clock_rate, samples_per_frame, + 0, &PaPlayerCallback, stream ); if (err != paNoError) { pj_pool_release(pool); - PJ_LOG(2,(THIS_FILE, "Error opening player: %s", Pa_GetErrorText(err))); - return NULL; + return PJMEDIA_ERRNO_FROM_PORTAUDIO(err); } PJ_LOG(5,(THIS_FILE, "%s opening device %s for playing, sample rate=%d, " + "channel count=%d, " "%d bits per sample, %d samples per buffer", (err==0 ? "Success" : "Error"), - paDevInfo->name, param->samples_per_sec, - param->bits_per_sample, - param->samples_per_frame * param->frames_per_packet)); + paDevInfo->name, clock_rate, channel_count, + bits_per_sample, samples_per_frame)); - return stream; + *p_snd_strm = stream; + + return PJ_SUCCESS; } diff --git a/pjmedia/src/pjmedia/portaudio/portaudio.h b/pjmedia/src/pjmedia/portaudio/portaudio.h index 5d4a97efd..981dd0ac2 100644 --- a/pjmedia/src/pjmedia/portaudio/portaudio.h +++ b/pjmedia/src/pjmedia/portaudio/portaudio.h @@ -64,7 +64,7 @@ typedef enum PaErrorCode { paNoError = 0, - paNotInitialized = -10000, + paNotInitialized = 1, /* blp: changed from -10000 */ paUnanticipatedHostError, paInvalidChannelCount, paInvalidSampleRate, diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c index 8b41a9480..c2624b207 100644 --- a/pjmedia/src/pjmedia/stream.c +++ b/pjmedia/src/pjmedia/stream.c @@ -53,8 +53,6 @@ struct pjmedia_channel pjmedia_dir dir; /**< Channel direction. */ unsigned pt; /**< Payload type. */ pj_bool_t paused; /**< Paused?. */ - pj_snd_stream_info snd_info; /**< Sound stream param. */ - //pj_snd_stream *snd_stream; /**< Sound stream. */ unsigned in_pkt_size; /**< Size of input buffer. */ void *in_pkt; /**< Input buffer. */ unsigned out_pkt_size; /**< Size of output buffer. */ @@ -278,7 +276,7 @@ static pj_status_t put_frame( pjmedia_port *port, return -1; /* Number of samples in the frame */ - ts_len = frame->size / (channel->snd_info.bits_per_sample / 8); + ts_len = frame->size / 2; /* Init frame_out buffer. */ frame_out.buf = ((char*)channel->out_pkt) + sizeof(pjmedia_rtp_hdr); @@ -563,24 +561,6 @@ static int PJ_THREAD_FUNC jitter_buffer_thread (void*arg) } -/* - * Create sound stream parameter from codec attributes. - */ -static void init_snd_param( pj_snd_stream_info *snd_param, - const pjmedia_codec_param *codec_param) -{ - pj_memset(snd_param, 0, sizeof(*snd_param)); - - snd_param->bits_per_sample = codec_param->pcm_bits_per_sample; - snd_param->bytes_per_frame = 2; - snd_param->frames_per_packet = codec_param->sample_rate * - codec_param->ptime / - 1000; - snd_param->samples_per_frame = 1; - snd_param->samples_per_sec = codec_param->sample_rate; -} - - /* * Create media channel. */ @@ -643,22 +623,6 @@ static pj_status_t create_channel( pj_pool_t *pool, if (status != PJ_SUCCESS) return status; - /* Create and initialize sound device */ - - init_snd_param(&channel->snd_info, codec_param); - - /* - if (dir == PJMEDIA_DIR_ENCODING) - channel->snd_stream = pj_snd_open_recorder(-1, &channel->snd_info, - &rec_callback, channel); - else - channel->snd_stream = pj_snd_open_player(-1, &channel->snd_info, - &play_callback, channel); - - if (!channel->snd_stream) - return -1; - */ - /* Done. */ *p_channel = channel; return PJ_SUCCESS;