Support for codec with non-integer ptime (#3555)
This commit is contained in:
parent
e8f58dd6d6
commit
e8fa2237f2
|
@ -98,7 +98,8 @@ typedef struct pjmedia_codec_opus_config
|
|||
{
|
||||
unsigned sample_rate; /**< Sample rate in Hz. */
|
||||
unsigned channel_cnt; /**< Number of channels. */
|
||||
unsigned frm_ptime; /**< Frame time in msec. */
|
||||
unsigned frm_ptime; /**< Frame ptime in msec. */
|
||||
unsigned frm_ptime_denum;/**< Frame ptime denumerator, can be zero*/
|
||||
unsigned bit_rate; /**< Encoder bit rate in bps. */
|
||||
unsigned packet_loss; /**< Encoder's expected packet loss pct. */
|
||||
unsigned complexity; /**< Encoder complexity, 0-10(10 is highest)*/
|
||||
|
|
|
@ -270,6 +270,9 @@ typedef struct pjmedia_codec_param
|
|||
/**
|
||||
* The "info" part of codec param describes the capability of the codec,
|
||||
* and is recommended not to be modified unless necessary.
|
||||
* Note that application must be ready to handle cases when ptime
|
||||
* denumerators are zero, since most codecs that only support integer
|
||||
* ptime will leave these fields untouched.
|
||||
*/
|
||||
struct {
|
||||
unsigned clock_rate; /**< Sampling rate in Hz */
|
||||
|
@ -278,8 +281,12 @@ typedef struct pjmedia_codec_param
|
|||
pj_uint32_t max_bps; /**< Maximum bandwidth in bits/sec */
|
||||
unsigned max_rx_frame_size; /**< Maximum frame size */
|
||||
pj_uint16_t frm_ptime; /**< Decoder frame ptime in msec. */
|
||||
pj_uint8_t frm_ptime_denum; /**< Decoder frame ptime denum, or
|
||||
zero if ptime is integer. */
|
||||
pj_uint16_t enc_ptime; /**< Encoder ptime, or zero if it's
|
||||
equal to decoder ptime. */
|
||||
pj_uint8_t enc_ptime_denum; /**< Encoder frame ptime denum, or
|
||||
zero if ptime is integer. */
|
||||
pj_uint8_t pcm_bits_per_sample; /**< Bits/sample in the PCM side */
|
||||
pj_uint8_t pt; /**< Payload type. */
|
||||
pjmedia_format_id fmt_id; /**< Source format, it's format of
|
||||
|
@ -355,8 +362,8 @@ typedef struct pjmedia_codec_op
|
|||
/**
|
||||
* Open the codec and initialize with the specified parameter.
|
||||
* Upon successful initialization, the codec may modify the parameter
|
||||
* and fills in the unspecified values (such as enc_ptime, when
|
||||
* encoder ptime is different than decoder ptime).
|
||||
* and fills in the unspecified values (such as enc_ptime/enc_ptime_denum,
|
||||
* when encoder ptime is different than decoder ptime).
|
||||
*
|
||||
* Application should call #pjmedia_codec_open() instead of
|
||||
* calling this function directly.
|
||||
|
@ -404,7 +411,7 @@ typedef struct pjmedia_codec_op
|
|||
* Instruct the codec to inspect the specified payload/packet and
|
||||
* split the packet into individual base frames. Each output frames will
|
||||
* have ptime that is equal to basic frame ptime (i.e. the value of
|
||||
* info.frm_ptime in #pjmedia_codec_param).
|
||||
* info.frm_ptime/info.frm_ptime_denum in #pjmedia_codec_param).
|
||||
*
|
||||
* Application should call #pjmedia_codec_parse() instead of
|
||||
* calling this function directly.
|
||||
|
@ -431,7 +438,8 @@ typedef struct pjmedia_codec_op
|
|||
/**
|
||||
* Instruct the codec to encode the specified input frame. The input
|
||||
* PCM samples MUST have ptime that is multiplication of base frame
|
||||
* ptime (i.e. the value of info.frm_ptime in #pjmedia_codec_param).
|
||||
* ptime (i.e. the value of info.frm_ptime/info.frm_ptime_denum in
|
||||
* #pjmedia_codec_param).
|
||||
*
|
||||
* Application should call #pjmedia_codec_encode() instead of
|
||||
* calling this function directly.
|
||||
|
@ -451,7 +459,8 @@ typedef struct pjmedia_codec_op
|
|||
/**
|
||||
* Instruct the codec to decode the specified input frame. The input
|
||||
* frame MUST have ptime that is exactly equal to base frame
|
||||
* ptime (i.e. the value of info.frm_ptime in #pjmedia_codec_param).
|
||||
* ptime (i.e. the value of info.frm_ptime/info.frm_ptime_denum in
|
||||
* #pjmedia_codec_param).
|
||||
* Application can achieve this by parsing the packet into base
|
||||
* frames before decoding each frame.
|
||||
*
|
||||
|
@ -1037,7 +1046,7 @@ PJ_INLINE(pj_status_t) pjmedia_codec_modify(pjmedia_codec *codec,
|
|||
* Instruct the codec to inspect the specified payload/packet and
|
||||
* split the packet into individual base frames. Each output frames will
|
||||
* have ptime that is equal to basic frame ptime (i.e. the value of
|
||||
* info.frm_ptime in #pjmedia_codec_param).
|
||||
* info.frm_ptime/info.frm_ptime_denum in #pjmedia_codec_param).
|
||||
*
|
||||
* @param codec The codec instance
|
||||
* @param pkt The input packet.
|
||||
|
@ -1066,7 +1075,8 @@ PJ_INLINE(pj_status_t) pjmedia_codec_parse( pjmedia_codec *codec,
|
|||
/**
|
||||
* Instruct the codec to encode the specified input frame. The input
|
||||
* PCM samples MUST have ptime that is multiplication of base frame
|
||||
* ptime (i.e. the value of info.frm_ptime in #pjmedia_codec_param).
|
||||
* ptime (i.e. the value of info.frm_ptime/info.frm_ptime_denum in
|
||||
* #pjmedia_codec_param).
|
||||
*
|
||||
* @param codec The codec instance.
|
||||
* @param input The input frame.
|
||||
|
@ -1088,7 +1098,8 @@ PJ_INLINE(pj_status_t) pjmedia_codec_encode(
|
|||
/**
|
||||
* Instruct the codec to decode the specified input frame. The input
|
||||
* frame MUST have ptime that is exactly equal to base frame
|
||||
* ptime (i.e. the value of info.frm_ptime in #pjmedia_codec_param).
|
||||
* ptime (i.e. the value of info.frm_ptime/info.frm_ptime_denum in
|
||||
* #pjmedia_codec_param).
|
||||
* Application can achieve this by parsing the packet into base
|
||||
* frames before decoding each frame.
|
||||
*
|
||||
|
|
|
@ -170,8 +170,8 @@ PJ_DECL(pj_status_t) pjmedia_jbuf_create(pj_pool_t *pool,
|
|||
/**
|
||||
* Set the jitter buffer's frame duration.
|
||||
*
|
||||
* @param jb The jitter buffer
|
||||
* @param ptime Frame duration.
|
||||
* @param jb The jitter buffer.
|
||||
* @param ptime Frame ptime.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
|
@ -179,6 +179,20 @@ PJ_DECL(pj_status_t) pjmedia_jbuf_set_ptime( pjmedia_jbuf *jb,
|
|||
unsigned ptime);
|
||||
|
||||
|
||||
/**
|
||||
* Set the jitter buffer's frame duration.
|
||||
*
|
||||
* @param jb The jitter buffer.
|
||||
* @param ptime Frame ptime.
|
||||
* @param ptime_denum Frame ptime denumerator.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pjmedia_jbuf_set_ptime2(pjmedia_jbuf *jb,
|
||||
unsigned ptime,
|
||||
unsigned ptime_denum);
|
||||
|
||||
|
||||
/**
|
||||
* Set the jitter buffer to fixed delay mode. The default behavior
|
||||
* is to adapt the delay with actual packet delay.
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
|
||||
/* Default frame time (msec) */
|
||||
#define PTIME 20
|
||||
#define PTIME_DENUM 1
|
||||
|
||||
/* Tracing */
|
||||
#if 0
|
||||
|
@ -139,7 +140,9 @@ struct opus_data
|
|||
OpusRepacketizer *dec_packer;
|
||||
pjmedia_codec_opus_config cfg;
|
||||
unsigned enc_ptime;
|
||||
unsigned enc_ptime_denum;
|
||||
unsigned dec_ptime;
|
||||
unsigned dec_ptime_denum;
|
||||
pjmedia_frame dec_frame[2];
|
||||
int dec_frame_index;
|
||||
};
|
||||
|
@ -152,7 +155,8 @@ static pjmedia_codec_opus_config opus_cfg =
|
|||
{
|
||||
PJMEDIA_CODEC_OPUS_DEFAULT_SAMPLE_RATE, /* Sample rate */
|
||||
1, /* Channel count */
|
||||
PTIME, /* Frame time */
|
||||
PTIME, /* Frame ptime */
|
||||
PTIME_DENUM, /* Frame ptime denum */
|
||||
PJMEDIA_CODEC_OPUS_DEFAULT_BIT_RATE, /* Bit rate */
|
||||
5, /* Expected packet loss */
|
||||
PJMEDIA_CODEC_OPUS_DEFAULT_COMPLEXITY, /* Complexity */
|
||||
|
@ -420,7 +424,9 @@ pjmedia_codec_opus_set_default_param(const pjmedia_codec_opus_config *cfg,
|
|||
param->info.clock_rate = opus_cfg.sample_rate = cfg->sample_rate;
|
||||
param->info.max_bps = opus_cfg.sample_rate * 2;
|
||||
opus_cfg.frm_ptime = cfg->frm_ptime;
|
||||
opus_cfg.frm_ptime_denum = cfg->frm_ptime_denum;
|
||||
param->info.frm_ptime = (pj_uint16_t)cfg->frm_ptime;
|
||||
param->info.frm_ptime_denum = (pj_uint8_t)cfg->frm_ptime_denum;
|
||||
|
||||
/* Set channel count */
|
||||
if (cfg->channel_cnt != 1 && cfg->channel_cnt != 2)
|
||||
|
@ -503,6 +509,7 @@ static pj_status_t factory_default_attr( pjmedia_codec_factory *factory,
|
|||
attr->info.avg_bps = opus_cfg.bit_rate;
|
||||
attr->info.max_bps = opus_cfg.sample_rate * 2;
|
||||
attr->info.frm_ptime = (pj_uint16_t)opus_cfg.frm_ptime;
|
||||
attr->info.frm_ptime_denum = (pj_uint8_t)opus_cfg.frm_ptime_denum;
|
||||
attr->setting.frm_per_pkt = 1;
|
||||
attr->info.pcm_bits_per_sample = 16;
|
||||
attr->setting.vad = OPUS_DEFAULT_VAD;
|
||||
|
@ -644,6 +651,9 @@ static pj_status_t codec_open( pjmedia_codec *codec,
|
|||
opus_data->cfg.sample_rate = attr->info.clock_rate;
|
||||
opus_data->cfg.channel_cnt = attr->info.channel_cnt;
|
||||
opus_data->enc_ptime = opus_data->dec_ptime = attr->info.frm_ptime;
|
||||
opus_data->enc_ptime_denum = attr->info.frm_ptime_denum?
|
||||
attr->info.frm_ptime_denum: 1;
|
||||
opus_data->dec_ptime_denum = opus_data->enc_ptime_denum;
|
||||
|
||||
/* Allocate memory used by the codec */
|
||||
if (!opus_data->enc) {
|
||||
|
@ -757,7 +767,8 @@ static pj_status_t codec_open( pjmedia_codec *codec,
|
|||
|
||||
PJ_LOG(4, (THIS_FILE, "Initialize Opus encoder, sample rate: %d, ch: %d, "
|
||||
"avg bitrate: %d%s, vad: %d, plc: %d, pkt loss: %d, "
|
||||
"complexity: %d, constant bit rate: %d",
|
||||
"complexity: %d, constant bit rate: %d, "
|
||||
"ptime: %d/%d",
|
||||
opus_data->cfg.sample_rate,
|
||||
opus_data->cfg.channel_cnt,
|
||||
(auto_bit_rate? 0: attr->info.avg_bps),
|
||||
|
@ -766,7 +777,9 @@ static pj_status_t codec_open( pjmedia_codec *codec,
|
|||
attr->setting.plc?1:0,
|
||||
opus_data->cfg.packet_loss,
|
||||
opus_data->cfg.complexity,
|
||||
opus_data->cfg.cbr?1:0));
|
||||
opus_data->cfg.cbr?1:0,
|
||||
opus_data->enc_ptime,
|
||||
opus_data->enc_ptime_denum));
|
||||
|
||||
/* Initialize decoder */
|
||||
err = opus_decoder_init (opus_data->dec,
|
||||
|
@ -821,6 +834,11 @@ static pj_status_t codec_modify( pjmedia_codec *codec,
|
|||
|
||||
TRACE_((THIS_FILE, "%s:%d: - TRACE", __FUNCTION__, __LINE__));
|
||||
|
||||
/* Set encoder ptime */
|
||||
opus_data->enc_ptime = attr->info.frm_ptime;
|
||||
opus_data->enc_ptime_denum = attr->info.frm_ptime_denum?
|
||||
attr->info.frm_ptime_denum: 1;
|
||||
|
||||
/* Set bitrate */
|
||||
opus_data->cfg.bit_rate = attr->info.avg_bps;
|
||||
opus_encoder_ctl(opus_data->enc, OPUS_SET_BITRATE(attr->info.avg_bps?
|
||||
|
@ -848,7 +866,8 @@ static pj_status_t codec_modify( pjmedia_codec *codec,
|
|||
|
||||
PJ_LOG(4, (THIS_FILE, "Modifying Opus encoder, sample rate: %d, ch: %d, "
|
||||
"avg bitrate: %d%s, vad: %d, plc: %d, pkt loss: %d, "
|
||||
"complexity: %d, constant bit rate: %d",
|
||||
"complexity: %d, constant bit rate: %d, "
|
||||
"ptime: %d/%d ms",
|
||||
attr->info.clock_rate,
|
||||
attr->info.channel_cnt,
|
||||
(attr->info.avg_bps? attr->info.avg_bps: 0),
|
||||
|
@ -857,7 +876,9 @@ static pj_status_t codec_modify( pjmedia_codec *codec,
|
|||
attr->setting.plc?1:0,
|
||||
attr->setting.packet_loss,
|
||||
attr->setting.complexity,
|
||||
attr->setting.cbr?1:0));
|
||||
attr->setting.cbr?1:0,
|
||||
opus_data->enc_ptime,
|
||||
opus_data->enc_ptime_denum));
|
||||
|
||||
pj_mutex_unlock (opus_data->mutex);
|
||||
return PJ_SUCCESS;
|
||||
|
@ -922,6 +943,7 @@ static pj_status_t codec_parse( pjmedia_codec *codec,
|
|||
if (i == 0) {
|
||||
int nsamples;
|
||||
unsigned ptime;
|
||||
unsigned ptime_denum = 1;
|
||||
|
||||
nsamples = opus_packet_get_nb_samples(frames[i].buf,
|
||||
frames[i].size,
|
||||
|
@ -933,12 +955,22 @@ static pj_status_t codec_parse( pjmedia_codec *codec,
|
|||
return PJMEDIA_CODEC_EFAILED;
|
||||
}
|
||||
|
||||
ptime = nsamples * 1000 / opus_data->cfg.sample_rate;
|
||||
if (ptime != opus_data->dec_ptime) {
|
||||
PJ_LOG(4, (THIS_FILE, "Opus ptime change detected: %d ms "
|
||||
"--> %d ms",
|
||||
opus_data->dec_ptime, ptime));
|
||||
if ((nsamples * 1000) % opus_data->cfg.sample_rate != 0) {
|
||||
/* The only non-integer ptime that Opus supports is 2.5 ms */
|
||||
ptime_denum = 2;
|
||||
}
|
||||
ptime = nsamples * ptime_denum * 1000 / opus_data->cfg.sample_rate;
|
||||
|
||||
if (ptime * opus_data->dec_ptime_denum !=
|
||||
opus_data->dec_ptime * ptime_denum)
|
||||
{
|
||||
PJ_LOG(4, (THIS_FILE, "Opus ptime change detected: %d/%d ms "
|
||||
"--> %d/%d ms",
|
||||
opus_data->dec_ptime,
|
||||
opus_data->dec_ptime_denum,
|
||||
ptime, ptime_denum));
|
||||
opus_data->dec_ptime = ptime;
|
||||
opus_data->dec_ptime_denum = ptime_denum;
|
||||
opus_data->dec_frame_index = -1;
|
||||
|
||||
/* Signal to the stream about ptime change. */
|
||||
|
@ -977,7 +1009,8 @@ static pj_status_t codec_encode( pjmedia_codec *codec,
|
|||
pj_mutex_lock (opus_data->mutex);
|
||||
|
||||
samples_per_frame = (opus_data->cfg.sample_rate *
|
||||
opus_data->enc_ptime) / 1000;
|
||||
opus_data->enc_ptime /
|
||||
opus_data->enc_ptime_denum) / 1000;
|
||||
frame_size = samples_per_frame * opus_data->cfg.channel_cnt *
|
||||
sizeof(opus_int16);
|
||||
|
||||
|
@ -1092,7 +1125,8 @@ static pj_status_t codec_decode( pjmedia_codec *codec,
|
|||
if (inframe->type != PJMEDIA_FRAME_TYPE_AUDIO || fec) {
|
||||
frm_size = PJ_MIN((unsigned)frm_size,
|
||||
opus_data->cfg.sample_rate *
|
||||
opus_data->dec_ptime / 1000);
|
||||
opus_data->dec_ptime /
|
||||
opus_data->dec_ptime_denum / 1000);
|
||||
}
|
||||
decoded_samples = opus_decode( opus_data->dec,
|
||||
inframe->type==PJMEDIA_FRAME_TYPE_AUDIO ?
|
||||
|
@ -1153,7 +1187,7 @@ static pj_status_t codec_recover( pjmedia_codec *codec,
|
|||
/* Recover the first packet? Don't think so, fill it with zeroes. */
|
||||
unsigned samples_per_frame;
|
||||
samples_per_frame = opus_data->cfg.sample_rate * opus_data->dec_ptime/
|
||||
1000;
|
||||
opus_data->dec_ptime_denum / 1000;
|
||||
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
|
||||
output->size = samples_per_frame << 1;
|
||||
pjmedia_zero_samples((pj_int16_t*)output->buf, samples_per_frame);
|
||||
|
@ -1167,7 +1201,8 @@ static pj_status_t codec_recover( pjmedia_codec *codec,
|
|||
opus_data->cfg.channel_cnt);
|
||||
if (inframe->type != PJMEDIA_FRAME_TYPE_AUDIO) {
|
||||
frm_size = PJ_MIN((unsigned)frm_size, opus_data->cfg.sample_rate *
|
||||
opus_data->dec_ptime/1000);
|
||||
opus_data->dec_ptime / opus_data->dec_ptime_denum /
|
||||
1000);
|
||||
}
|
||||
decoded_samples = opus_decode(opus_data->dec,
|
||||
inframe->type==PJMEDIA_FRAME_TYPE_AUDIO ?
|
||||
|
|
|
@ -98,6 +98,7 @@ struct pjmedia_jbuf
|
|||
pj_str_t jb_name; /**< jitter buffer name */
|
||||
pj_size_t jb_frame_size; /**< frame size */
|
||||
unsigned jb_frame_ptime; /**< frame duration. */
|
||||
unsigned jb_frame_ptime_denum;/**< frame duration denumerator. */
|
||||
pj_size_t jb_max_count; /**< capacity of jitter buffer,
|
||||
in frames */
|
||||
int jb_init_prefetch; /**< Initial prefetch */
|
||||
|
@ -608,6 +609,7 @@ PJ_DEF(pj_status_t) pjmedia_jbuf_create(pj_pool_t *pool,
|
|||
pj_strdup_with_null(pool, &jb->jb_name, name);
|
||||
jb->jb_frame_size = frame_size;
|
||||
jb->jb_frame_ptime = ptime;
|
||||
jb->jb_frame_ptime_denum = 1;
|
||||
jb->jb_prefetch = PJ_MIN(PJMEDIA_JB_DEFAULT_INIT_DELAY,max_count*4/5);
|
||||
jb->jb_min_prefetch = 0;
|
||||
jb->jb_max_prefetch = max_count*4/5;
|
||||
|
@ -628,13 +630,21 @@ PJ_DEF(pj_status_t) pjmedia_jbuf_create(pj_pool_t *pool,
|
|||
|
||||
PJ_DEF(pj_status_t) pjmedia_jbuf_set_ptime( pjmedia_jbuf *jb,
|
||||
unsigned ptime)
|
||||
{
|
||||
return pjmedia_jbuf_set_ptime2(jb, ptime, 1);
|
||||
}
|
||||
|
||||
PJ_DEF(pj_status_t) pjmedia_jbuf_set_ptime2(pjmedia_jbuf *jb,
|
||||
unsigned ptime,
|
||||
unsigned ptime_denum)
|
||||
{
|
||||
PJ_ASSERT_RETURN(jb, PJ_EINVAL);
|
||||
|
||||
jb->jb_frame_ptime = ptime;
|
||||
jb->jb_min_shrink_gap = PJMEDIA_JBUF_DISC_MIN_GAP / ptime;
|
||||
jb->jb_max_burst = (int)PJ_MAX(MAX_BURST_MSEC / ptime,
|
||||
jb->jb_max_count*3/4);
|
||||
jb->jb_frame_ptime_denum = ptime_denum;
|
||||
jb->jb_min_shrink_gap = PJMEDIA_JBUF_DISC_MIN_GAP * ptime_denum / ptime;
|
||||
jb->jb_max_burst = (int)PJ_MAX(MAX_BURST_MSEC * ptime_denum / ptime,
|
||||
jb->jb_max_count*3/4);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
@ -910,7 +920,8 @@ static void jbuf_discard_progressive(pjmedia_jbuf *jb)
|
|||
|
||||
/* Calculate current discard distance */
|
||||
overflow = cur_size - burst_level;
|
||||
discard_dist = T / overflow / jb->jb_frame_ptime;
|
||||
discard_dist = T * jb->jb_frame_ptime_denum / overflow /
|
||||
jb->jb_frame_ptime;
|
||||
|
||||
/* Get last seq number in the JB */
|
||||
last_seq = jb_framelist_origin(&jb->jb_framelist) +
|
||||
|
@ -1161,7 +1172,8 @@ PJ_DEF(void) pjmedia_jbuf_get_frame3(pjmedia_jbuf *jb,
|
|||
/* We've just retrieved one frame, so add one to cur_size */
|
||||
cur_size = jb_framelist_eff_size(&jb->jb_framelist) + 1;
|
||||
pj_math_stat_update(&jb->jb_delay,
|
||||
cur_size*jb->jb_frame_ptime);
|
||||
cur_size * jb->jb_frame_ptime /
|
||||
jb->jb_frame_ptime_denum);
|
||||
}
|
||||
} else {
|
||||
/* Jitter buffer is empty */
|
||||
|
|
|
@ -145,6 +145,7 @@ struct pjmedia_stream
|
|||
decoding buffer. */
|
||||
|
||||
pj_uint16_t dec_ptime; /**< Decoder frame ptime in ms. */
|
||||
pj_uint8_t dec_ptime_denum;/**< Decoder ptime denum. */
|
||||
pj_bool_t detect_ptime_change;
|
||||
/**< Detect decode ptime change */
|
||||
|
||||
|
@ -556,6 +557,7 @@ static pj_status_t get_frame( pjmedia_port *port, pjmedia_frame *frame)
|
|||
samples_per_frame = stream->dec_ptime *
|
||||
stream->codec_param.info.clock_rate *
|
||||
stream->codec_param.info.channel_cnt /
|
||||
stream->dec_ptime_denum /
|
||||
1000;
|
||||
p_out_samp = (pj_int16_t*) frame->buf;
|
||||
|
||||
|
@ -846,6 +848,7 @@ static pj_status_t get_frame_ext( pjmedia_port *port, pjmedia_frame *frame)
|
|||
samples_per_frame = stream->codec_param.info.frm_ptime *
|
||||
stream->codec_param.info.clock_rate *
|
||||
stream->codec_param.info.channel_cnt /
|
||||
stream->codec_param.info.frm_ptime_denum /
|
||||
1000;
|
||||
|
||||
pj_bzero(f, sizeof(pjmedia_frame_ext));
|
||||
|
@ -1300,7 +1303,9 @@ static void rebuffer(pjmedia_stream *stream,
|
|||
|
||||
/* How many samples are needed */
|
||||
count = stream->codec_param.info.enc_ptime *
|
||||
PJMEDIA_PIA_SRATE(&stream->port.info) / 1000;
|
||||
PJMEDIA_PIA_SRATE(&stream->port.info) /
|
||||
stream->codec_param.info.enc_ptime_denum /
|
||||
1000;
|
||||
|
||||
/* See if we have enough samples */
|
||||
if (stream->enc_buf_count >= count) {
|
||||
|
@ -2065,21 +2070,34 @@ static void on_rx_rtp( pjmedia_tp_cb_param *param)
|
|||
} else if (stream->detect_ptime_change &&
|
||||
frames[0].bit_info > 0xFFFF)
|
||||
{
|
||||
unsigned dec_ptime, old_ptime;
|
||||
unsigned dec_ptime, dec_ptime_denum = 1;
|
||||
pj_uint16_t old_ptime, old_ptime_denum;
|
||||
|
||||
old_ptime = stream->dec_ptime;
|
||||
old_ptime_denum = stream->dec_ptime_denum;
|
||||
|
||||
frames[0].bit_info &= 0xFFFF;
|
||||
dec_ptime = frames[0].bit_info * 1000 /
|
||||
if ((frames[0].bit_info * 1000) %
|
||||
stream->codec_param.info.clock_rate != 0)
|
||||
{
|
||||
dec_ptime_denum = 2;
|
||||
}
|
||||
dec_ptime = frames[0].bit_info * 1000 * dec_ptime_denum /
|
||||
stream->codec_param.info.clock_rate;
|
||||
stream->rtp_rx_ts_len_per_frame= stream->rtp_rx_ts_len_per_frame *
|
||||
dec_ptime / stream->dec_ptime;
|
||||
dec_ptime *
|
||||
stream->dec_ptime_denum /
|
||||
stream->dec_ptime /
|
||||
dec_ptime_denum;
|
||||
stream->dec_ptime = (pj_uint16_t)dec_ptime;
|
||||
pjmedia_jbuf_set_ptime(stream->jb, stream->dec_ptime);
|
||||
stream->dec_ptime_denum = (pj_uint8_t)dec_ptime_denum;
|
||||
pjmedia_jbuf_set_ptime2(stream->jb, stream->dec_ptime,
|
||||
stream->dec_ptime_denum);
|
||||
|
||||
PJ_LOG(4, (stream->port.info.name.ptr, "codec decode "
|
||||
"ptime change detected: %d -> %d",
|
||||
old_ptime, dec_ptime));
|
||||
"ptime change detected: %d/%d -> %d/%d",
|
||||
old_ptime, old_ptime_denum,
|
||||
dec_ptime, dec_ptime_denum));
|
||||
|
||||
/* Reset jitter buffer after ptime changed */
|
||||
pjmedia_jbuf_reset(stream->jb);
|
||||
|
@ -2155,11 +2173,13 @@ static void on_rx_rtp( pjmedia_tp_cb_param *param)
|
|||
} else {
|
||||
ts_span = stream->dec_ptime *
|
||||
stream->codec_param.info.clock_rate /
|
||||
stream->dec_ptime_denum /
|
||||
1000;
|
||||
}
|
||||
#else
|
||||
ts_span = stream->dec_ptime *
|
||||
stream->codec_param.info.clock_rate /
|
||||
stream->dec_ptime_denum /
|
||||
1000;
|
||||
#endif
|
||||
|
||||
|
@ -2523,6 +2543,9 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
|
|||
if (stream->codec_param.setting.frm_per_pkt < 1)
|
||||
stream->codec_param.setting.frm_per_pkt = 1;
|
||||
|
||||
if (stream->codec_param.info.frm_ptime_denum < 1)
|
||||
stream->codec_param.info.frm_ptime_denum = 1;
|
||||
|
||||
/* Init the codec. */
|
||||
status = pjmedia_codec_init(stream->codec, pool);
|
||||
if (status != PJ_SUCCESS)
|
||||
|
@ -2552,9 +2575,12 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
|
|||
|
||||
/* Set additional info and callbacks. */
|
||||
stream->dec_ptime = stream->codec_param.info.frm_ptime;
|
||||
stream->dec_ptime_denum = PJ_MAX(stream->codec_param.info.frm_ptime_denum,
|
||||
1);
|
||||
afd->bits_per_sample = 16;
|
||||
afd->frame_time_usec = stream->codec_param.info.frm_ptime *
|
||||
stream->codec_param.setting.frm_per_pkt * 1000;
|
||||
stream->codec_param.setting.frm_per_pkt * 1000 /
|
||||
stream->codec_param.info.frm_ptime_denum;
|
||||
stream->port.info.fmt.id = stream->codec_param.info.fmt_id;
|
||||
if (stream->codec_param.info.fmt_id == PJMEDIA_FORMAT_L16) {
|
||||
/* Raw format */
|
||||
|
@ -2588,30 +2614,43 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
|
|||
* with iLBC
|
||||
*/
|
||||
if (stream->codec_param.info.enc_ptime!=0 &&
|
||||
stream->codec_param.info.enc_ptime!=stream->codec_param.info.frm_ptime)
|
||||
stream->codec_param.info.enc_ptime *
|
||||
stream->codec_param.info.frm_ptime_denum !=
|
||||
stream->codec_param.info.frm_ptime *
|
||||
stream->codec_param.info.enc_ptime_denum)
|
||||
{
|
||||
unsigned ptime;
|
||||
|
||||
stream->enc_samples_per_pkt = stream->codec_param.info.enc_ptime *
|
||||
stream->codec_param.info.channel_cnt *
|
||||
afd->clock_rate / 1000;
|
||||
afd->clock_rate /
|
||||
stream->codec_param.info.enc_ptime_denum
|
||||
/ 1000;
|
||||
|
||||
/* Set buffer size as twice the largest ptime value between
|
||||
* stream's ptime, encoder ptime, or decoder ptime.
|
||||
*/
|
||||
|
||||
ptime = afd->frame_time_usec / 1000;
|
||||
ptime = afd->frame_time_usec;
|
||||
|
||||
if (stream->codec_param.info.enc_ptime > ptime)
|
||||
ptime = stream->codec_param.info.enc_ptime;
|
||||
if (stream->codec_param.info.enc_ptime * 1000 >
|
||||
ptime * stream->codec_param.info.enc_ptime_denum)
|
||||
{
|
||||
ptime = stream->codec_param.info.enc_ptime * 1000 /
|
||||
stream->codec_param.info.enc_ptime_denum;
|
||||
}
|
||||
|
||||
if (stream->codec_param.info.frm_ptime > ptime)
|
||||
ptime = stream->codec_param.info.frm_ptime;
|
||||
if (stream->codec_param.info.frm_ptime * 1000 >
|
||||
ptime * stream->codec_param.info.frm_ptime_denum)
|
||||
{
|
||||
ptime = stream->codec_param.info.frm_ptime * 1000 /
|
||||
stream->codec_param.info.frm_ptime_denum;
|
||||
}
|
||||
|
||||
ptime <<= 1;
|
||||
|
||||
/* Allocate buffer */
|
||||
stream->enc_buf_size = afd->clock_rate * ptime / 1000;
|
||||
stream->enc_buf_size = afd->clock_rate * ptime / 1000 / 1000;
|
||||
stream->enc_buf = (pj_int16_t*)
|
||||
pj_pool_alloc(pool, stream->enc_buf_size * 2);
|
||||
|
||||
|
@ -2634,17 +2673,22 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
|
|||
stream->frame_size = stream->codec_param.info.max_rx_frame_size;
|
||||
} else {
|
||||
stream->frame_size = stream->codec_param.info.max_bps *
|
||||
stream->codec_param.info.frm_ptime / 8 / 1000;
|
||||
stream->codec_param.info.frm_ptime /
|
||||
stream->codec_param.info.frm_ptime_denum /
|
||||
8 / 1000;
|
||||
if ((stream->codec_param.info.max_bps *
|
||||
stream->codec_param.info.frm_ptime) % 8000 != 0)
|
||||
stream->codec_param.info.frm_ptime /
|
||||
stream->codec_param.info.frm_ptime_denum) % 8000 != 0)
|
||||
{
|
||||
++stream->frame_size;
|
||||
}
|
||||
}
|
||||
|
||||
/* How many consecutive PLC frames can be generated */
|
||||
stream->max_plc_cnt = (MAX_PLC_MSEC+stream->codec_param.info.frm_ptime-1)/
|
||||
stream->codec_param.info.frm_ptime;
|
||||
stream->max_plc_cnt = (MAX_PLC_MSEC+stream->codec_param.info.frm_ptime/
|
||||
stream->codec_param.info.frm_ptime_denum-1) *
|
||||
stream->codec_param.info.frm_ptime_denum /
|
||||
stream->codec_param.info.frm_ptime;
|
||||
/* Disable PLC until a "NORMAL" frame is gotten from the jitter buffer. */
|
||||
stream->plc_cnt = stream->max_plc_cnt;
|
||||
|
||||
|
@ -2687,29 +2731,50 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
|
|||
#endif
|
||||
|
||||
/* Init jitter buffer parameters: */
|
||||
if (info->jb_max >= stream->codec_param.info.frm_ptime)
|
||||
jb_max = (info->jb_max + stream->codec_param.info.frm_ptime - 1) /
|
||||
if (info->jb_max * stream->codec_param.info.frm_ptime_denum >=
|
||||
stream->codec_param.info.frm_ptime)
|
||||
{
|
||||
jb_max = (info->jb_max + stream->codec_param.info.frm_ptime /
|
||||
stream->codec_param.info.frm_ptime_denum - 1) *
|
||||
stream->codec_param.info.frm_ptime_denum /
|
||||
stream->codec_param.info.frm_ptime;
|
||||
else
|
||||
jb_max = 500 / stream->codec_param.info.frm_ptime;
|
||||
} else {
|
||||
jb_max = 500 * stream->codec_param.info.frm_ptime_denum /
|
||||
stream->codec_param.info.frm_ptime;
|
||||
}
|
||||
|
||||
if (info->jb_min_pre >= stream->codec_param.info.frm_ptime)
|
||||
jb_min_pre = info->jb_min_pre / stream->codec_param.info.frm_ptime;
|
||||
else
|
||||
if (info->jb_min_pre * stream->codec_param.info.frm_ptime_denum >=
|
||||
stream->codec_param.info.frm_ptime)
|
||||
{
|
||||
jb_min_pre = info->jb_min_pre *
|
||||
stream->codec_param.info.frm_ptime_denum /
|
||||
stream->codec_param.info.frm_ptime;
|
||||
} else {
|
||||
//jb_min_pre = 60 / stream->codec_param.info.frm_ptime;
|
||||
jb_min_pre = 1;
|
||||
}
|
||||
|
||||
if (info->jb_max_pre >= stream->codec_param.info.frm_ptime)
|
||||
jb_max_pre = info->jb_max_pre / stream->codec_param.info.frm_ptime;
|
||||
else
|
||||
if (info->jb_max_pre * stream->codec_param.info.frm_ptime_denum >=
|
||||
stream->codec_param.info.frm_ptime)
|
||||
{
|
||||
jb_max_pre = info->jb_max_pre *
|
||||
stream->codec_param.info.frm_ptime_denum /
|
||||
stream->codec_param.info.frm_ptime;
|
||||
} else {
|
||||
//jb_max_pre = 240 / stream->codec_param.info.frm_ptime;
|
||||
jb_max_pre = PJ_MAX(1, jb_max * 4 / 5);
|
||||
}
|
||||
|
||||
if (info->jb_init >= stream->codec_param.info.frm_ptime)
|
||||
jb_init = info->jb_init / stream->codec_param.info.frm_ptime;
|
||||
else
|
||||
if (info->jb_init * stream->codec_param.info.frm_ptime_denum >=
|
||||
stream->codec_param.info.frm_ptime)
|
||||
{
|
||||
jb_init = info->jb_init *
|
||||
stream->codec_param.info.frm_ptime_denum /
|
||||
stream->codec_param.info.frm_ptime;
|
||||
} else {
|
||||
//jb_init = (jb_min_pre + jb_max_pre) / 2;
|
||||
jb_init = 0;
|
||||
}
|
||||
|
||||
/* Create jitter buffer */
|
||||
status = pjmedia_jbuf_create(pool, &stream->port.info.name,
|
||||
|
@ -2721,6 +2786,8 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
|
|||
|
||||
|
||||
/* Set up jitter buffer */
|
||||
pjmedia_jbuf_set_ptime2(stream->jb, stream->codec_param.info.frm_ptime,
|
||||
stream->codec_param.info.frm_ptime_denum);
|
||||
pjmedia_jbuf_set_adaptive( stream->jb, jb_init, jb_min_pre, jb_max_pre);
|
||||
pjmedia_jbuf_set_discard(stream->jb, info->jb_discard_algo);
|
||||
|
||||
|
@ -2845,7 +2912,8 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
|
|||
i);
|
||||
|
||||
/* Jitter buffer absolute maximum delay */
|
||||
i = jb_max * stream->codec_param.info.frm_ptime;
|
||||
i = jb_max * stream->codec_param.info.frm_ptime /
|
||||
stream->codec_param.info.frm_ptime_denum;
|
||||
pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,
|
||||
PJMEDIA_RTCP_XR_INFO_JB_ABS_MAX,
|
||||
i);
|
||||
|
|
|
@ -2444,8 +2444,12 @@ struct CodecParamInfo
|
|||
unsigned maxBps; /**< Maximum bandwidth in bits/sec */
|
||||
unsigned maxRxFrameSize; /**< Maximum frame size */
|
||||
unsigned frameLen; /**< Decoder frame ptime in msec. */
|
||||
unsigned frameLenDenum; /**< Decoder frame ptime denum, or
|
||||
zero if ptime is integer. */
|
||||
unsigned encFrameLen; /**< Encoder ptime, or zero if it's
|
||||
equal to decoder ptime. */
|
||||
unsigned encFrameLenDenum; /**< Encoder ptime denum, or zero
|
||||
if ptime is integer. */
|
||||
unsigned pcmBitsPerSample; /**< Bits/sample in the PCM side */
|
||||
unsigned pt; /**< Payload type. */
|
||||
pjmedia_format_id fmtId; /**< Source format, it's format of
|
||||
|
@ -2462,7 +2466,9 @@ public:
|
|||
maxBps(0),
|
||||
maxRxFrameSize(0),
|
||||
frameLen(0),
|
||||
frameLenDenum(0),
|
||||
encFrameLen(0),
|
||||
encFrameLenDenum(0),
|
||||
pcmBitsPerSample(0),
|
||||
pt(0),
|
||||
fmtId(PJMEDIA_FORMAT_L16)
|
||||
|
@ -2516,6 +2522,7 @@ struct CodecOpusConfig
|
|||
unsigned sample_rate; /**< Sample rate in Hz. */
|
||||
unsigned channel_cnt; /**< Number of channels. */
|
||||
unsigned frm_ptime; /**< Frame time in msec. */
|
||||
unsigned frm_ptime_denum;/**< Frame time denumerator. */
|
||||
unsigned bit_rate; /**< Encoder bit rate in bps. */
|
||||
unsigned packet_loss; /**< Encoder's expected packet loss pct. */
|
||||
unsigned complexity; /**< Encoder complexity, 0-10(10 is highest)*/
|
||||
|
|
|
@ -1830,7 +1830,9 @@ void CodecParam::fromPj(const pjmedia_codec_param ¶m)
|
|||
info.maxBps = param.info.max_bps;
|
||||
info.maxRxFrameSize = param.info.max_rx_frame_size;
|
||||
info.frameLen = param.info.frm_ptime;
|
||||
info.frameLenDenum = param.info.frm_ptime_denum;
|
||||
info.encFrameLen = param.info.enc_ptime;
|
||||
info.encFrameLenDenum = param.info.enc_ptime_denum;
|
||||
info.pcmBitsPerSample = param.info.pcm_bits_per_sample;
|
||||
info.pt = param.info.pt;
|
||||
info.fmtId = param.info.fmt_id;
|
||||
|
@ -1860,7 +1862,9 @@ pjmedia_codec_param CodecParam::toPj() const
|
|||
param.info.max_bps= (pj_uint32_t)info.maxBps;
|
||||
param.info.max_rx_frame_size = info.maxRxFrameSize;
|
||||
param.info.frm_ptime = (pj_uint16_t)info.frameLen;
|
||||
param.info.frm_ptime_denum = (pj_uint16_t)info.frameLenDenum;
|
||||
param.info.enc_ptime = (pj_uint16_t)info.encFrameLen;
|
||||
param.info.enc_ptime_denum = (pj_uint16_t)info.encFrameLenDenum;
|
||||
param.info.pcm_bits_per_sample = (pj_uint8_t)info.pcmBitsPerSample;
|
||||
param.info.pt = (pj_uint8_t)info.pt;
|
||||
param.info.fmt_id = info.fmtId;
|
||||
|
@ -1887,6 +1891,7 @@ pjmedia_codec_opus_config CodecOpusConfig::toPj() const
|
|||
config.sample_rate = sample_rate;
|
||||
config.channel_cnt = channel_cnt;
|
||||
config.frm_ptime = frm_ptime;
|
||||
config.frm_ptime_denum = frm_ptime_denum;
|
||||
config.bit_rate = bit_rate;
|
||||
config.packet_loss = packet_loss;
|
||||
config.complexity = complexity;
|
||||
|
@ -1900,6 +1905,7 @@ void CodecOpusConfig::fromPj(const pjmedia_codec_opus_config &config)
|
|||
sample_rate = config.sample_rate;
|
||||
channel_cnt = config.channel_cnt;
|
||||
frm_ptime = config.frm_ptime;
|
||||
frm_ptime_denum = config.frm_ptime_denum;
|
||||
bit_rate = config.bit_rate;
|
||||
packet_loss = config.packet_loss;
|
||||
complexity = config.complexity;
|
||||
|
|
Loading…
Reference in New Issue