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
This commit is contained in:
Benny Prijono 2006-03-15 20:56:04 +00:00
parent de38058342
commit de8a259f42
7 changed files with 133 additions and 134 deletions

View File

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

View File

@ -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.

View File

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

View File

@ -18,6 +18,7 @@
*/
#include <pjmedia/errno.h>
#include <pj/string.h>
#include <portaudio.h>
@ -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!

View File

@ -17,9 +17,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pjmedia/sound.h>
#include <pj/string.h>
#include <pj/os.h>
#include <pjmedia/errno.h>
#include <pj/log.h>
#include <pj/os.h>
#include <pj/string.h>
#include <portaudio.h>
#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;
}

View File

@ -64,7 +64,7 @@ typedef enum PaErrorCode
{
paNoError = 0,
paNotInitialized = -10000,
paNotInitialized = 1, /* blp: changed from -10000 */
paUnanticipatedHostError,
paInvalidChannelCount,
paInvalidSampleRate,

View File

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