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:
parent
de38058342
commit
de8a259f42
|
@ -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
|
||||
***********************************************************/
|
||||
|
|
|
@ -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_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);
|
||||
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_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);
|
||||
void *user_data,
|
||||
pj_snd_stream **p_snd_strm );
|
||||
|
||||
/**
|
||||
* Start the stream.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
#include <pjmedia/errno.h>
|
||||
#include <pj/string.h>
|
||||
#include <portaudio.h>
|
||||
|
||||
|
||||
|
||||
|
@ -129,7 +130,22 @@ PJ_DEF(pj_str_t) pjmedia_strerror( pj_status_t statcode,
|
|||
{
|
||||
pj_str_t errstr;
|
||||
|
||||
if (statcode >= PJMEDIA_ERRNO_START &&
|
||||
/* 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.
|
||||
|
|
|
@ -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_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)
|
||||
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_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)
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ typedef enum PaErrorCode
|
|||
{
|
||||
paNoError = 0,
|
||||
|
||||
paNotInitialized = -10000,
|
||||
paNotInitialized = 1, /* blp: changed from -10000 */
|
||||
paUnanticipatedHostError,
|
||||
paInvalidChannelCount,
|
||||
paInvalidSampleRate,
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue