Support for codec with non-integer ptime (#3555)

This commit is contained in:
sauwming 2023-05-16 13:13:10 +08:00 committed by GitHub
parent e8f58dd6d6
commit e8fa2237f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 218 additions and 64 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1830,7 +1830,9 @@ void CodecParam::fromPj(const pjmedia_codec_param &param)
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;