- Fixed conf switch on reinit-ing conf port TX buf.

- Updated conf switch to enable RX/TX level adjustment.
- Added VAD & PLC setting in passthrough codecs.
- Changed G711 fourcc codes.
- Updated bits-to-bytes calculations all over the places.
- Minor update: changed log level for dumping jbuf states in stream.




git-svn-id: https://svn.pjsip.org/repos/pjproject/branches/projects/aps-direct@2445 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
Nanang Izzuddin 2009-02-10 04:43:16 +00:00
parent bfa860b133
commit d5c54ab720
6 changed files with 214 additions and 93 deletions

View File

@ -300,31 +300,26 @@ typedef struct pjmedia_frame_ext_subframe {
*/ */
PJ_INLINE(void) pjmedia_frame_ext_append_subframe(pjmedia_frame_ext *frm, PJ_INLINE(void) pjmedia_frame_ext_append_subframe(pjmedia_frame_ext *frm,
const void *src, const void *src,
pj_uint16_t bitlen, unsigned bitlen,
pj_uint16_t samples_cnt) unsigned samples_cnt)
{ {
pjmedia_frame_ext_subframe *fsub;
pj_uint8_t *p; pj_uint8_t *p;
unsigned i, tmp; unsigned i;
p = (pj_uint8_t*)frm + sizeof(pjmedia_frame_ext); p = (pj_uint8_t*)frm + sizeof(pjmedia_frame_ext);
for (i = 0; i < frm->subframe_cnt; ++i) { for (i = 0; i < frm->subframe_cnt; ++i) {
pjmedia_frame_ext_subframe *fsub;
fsub = (pjmedia_frame_ext_subframe*) p; fsub = (pjmedia_frame_ext_subframe*) p;
p += sizeof(fsub->bitlen) + (fsub->bitlen >> 3); p += sizeof(fsub->bitlen) + ((fsub->bitlen+7) >> 3);
if (fsub->bitlen & 0x07)
++p;
} }
tmp = bitlen >> 3; fsub = (pjmedia_frame_ext_subframe*) p;
if (bitlen & 0x07) fsub->bitlen = (pj_uint16_t)bitlen;
++tmp; if (bitlen)
pj_memcpy(fsub->data, src, (bitlen+7) >> 3);
pj_memcpy(p, &bitlen, sizeof(bitlen));
if (tmp)
pj_memcpy(p + sizeof(bitlen), src, tmp);
frm->subframe_cnt++; frm->subframe_cnt++;
frm->samples_cnt = frm->samples_cnt + samples_cnt; frm->samples_cnt = frm->samples_cnt + (pj_uint16_t)samples_cnt;
} }
/** /**
@ -348,9 +343,7 @@ PJ_INLINE(pjmedia_frame_ext_subframe*)
p = (pj_uint8_t*)frm + sizeof(pjmedia_frame_ext); p = (pj_uint8_t*)frm + sizeof(pjmedia_frame_ext);
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
sf = (pjmedia_frame_ext_subframe*) p; sf = (pjmedia_frame_ext_subframe*) p;
p += sizeof(sf->bitlen) + (sf->bitlen >> 3); p += sizeof(sf->bitlen) + ((sf->bitlen+7) >> 3);
if (sf->bitlen & 0x07)
++p;
} }
sf = (pjmedia_frame_ext_subframe*) p; sf = (pjmedia_frame_ext_subframe*) p;
@ -383,9 +376,7 @@ PJ_INLINE(pj_status_t)
move_src = (pj_uint8_t*)pjmedia_frame_ext_get_subframe(frm, n); move_src = (pj_uint8_t*)pjmedia_frame_ext_get_subframe(frm, n);
sf = pjmedia_frame_ext_get_subframe(frm, frm->subframe_cnt-1); sf = pjmedia_frame_ext_get_subframe(frm, frm->subframe_cnt-1);
move_len = (pj_uint8_t*)sf - move_src + sizeof(sf->bitlen) + move_len = (pj_uint8_t*)sf - move_src + sizeof(sf->bitlen) +
(sf->bitlen >> 3); ((sf->bitlen+7) >> 3);
if (sf->bitlen & 0x07)
++move_len;
pj_memmove((pj_uint8_t*)frm+sizeof(pjmedia_frame_ext), pj_memmove((pj_uint8_t*)frm+sizeof(pjmedia_frame_ext),
move_src, move_len); move_src, move_len);

View File

@ -196,8 +196,8 @@ typedef union pjmedia_fourcc {
* FourCC identifier definitions. * FourCC identifier definitions.
*/ */
#define PJMEDIA_FOURCC_L16 PJMEDIA_FOURCC_PACK(' ', 'L', '1', '6') #define PJMEDIA_FOURCC_L16 PJMEDIA_FOURCC_PACK(' ', 'L', '1', '6')
#define PJMEDIA_FOURCC_G711A PJMEDIA_FOURCC_PACK('G', '7', '1', '1') #define PJMEDIA_FOURCC_PCMA PJMEDIA_FOURCC_PACK('A', 'L', 'A', 'W')
#define PJMEDIA_FOURCC_G711U PJMEDIA_FOURCC_PACK('U', 'L', 'A', 'W') #define PJMEDIA_FOURCC_PCMU PJMEDIA_FOURCC_PACK('u', 'L', 'A', 'W')
#define PJMEDIA_FOURCC_AMR PJMEDIA_FOURCC_PACK(' ', 'A', 'M', 'R') #define PJMEDIA_FOURCC_AMR PJMEDIA_FOURCC_PACK(' ', 'A', 'M', 'R')
#define PJMEDIA_FOURCC_G729 PJMEDIA_FOURCC_PACK('G', '7', '2', '9') #define PJMEDIA_FOURCC_G729 PJMEDIA_FOURCC_PACK('G', '7', '2', '9')
#define PJMEDIA_FOURCC_ILBC PJMEDIA_FOURCC_PACK('I', 'L', 'B', 'C') #define PJMEDIA_FOURCC_ILBC PJMEDIA_FOURCC_PACK('I', 'L', 'B', 'C')

View File

@ -162,6 +162,8 @@ static struct codec_desc {
unsigned def_bitrate; /* Default bitrate of this codec. */ unsigned def_bitrate; /* Default bitrate of this codec. */
unsigned max_bitrate; /* Maximum bitrate of this codec. */ unsigned max_bitrate; /* Maximum bitrate of this codec. */
pj_uint8_t frm_per_pkt; /* Default num of frames per packet.*/ pj_uint8_t frm_per_pkt; /* Default num of frames per packet.*/
pj_uint8_t vad; /* VAD enabled/disabled. */
pj_uint8_t plc; /* PLC enabled/disabled. */
parse_cb parse; /* Callback to parse bitstream. */ parse_cb parse; /* Callback to parse bitstream. */
pack_cb pack; /* Callback to pack bitstream. */ pack_cb pack; /* Callback to pack bitstream. */
pjmedia_codec_fmtp dec_fmtp; /* Decoder's fmtp params. */ pjmedia_codec_fmtp dec_fmtp; /* Decoder's fmtp params. */
@ -172,7 +174,7 @@ codec_desc[] =
# if PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR # if PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR
{1, "AMR", PJMEDIA_RTP_PT_AMR, {PJMEDIA_FOURCC_AMR}, {1, "AMR", PJMEDIA_RTP_PT_AMR, {PJMEDIA_FOURCC_AMR},
8000, 1, 160, 8000, 1, 160,
12200, 12200, 2, 7400, 12200, 2, 1, 1,
&parse_amr, &pack_amr &parse_amr, &pack_amr
/*, {1, {{{"octet-align", 11}, {"1", 1}}} } */ /*, {1, {{{"octet-align", 11}, {"1", 1}}} } */
}, },
@ -181,30 +183,30 @@ codec_desc[] =
# if PJMEDIA_HAS_PASSTHROUGH_CODEC_G729 # if PJMEDIA_HAS_PASSTHROUGH_CODEC_G729
{1, "G729", PJMEDIA_RTP_PT_G729, {PJMEDIA_FOURCC_G729}, {1, "G729", PJMEDIA_RTP_PT_G729, {PJMEDIA_FOURCC_G729},
8000, 1, 80, 8000, 1, 80,
8000, 8000, 2 8000, 8000, 2, 1, 1
}, },
# endif # endif
# if PJMEDIA_HAS_PASSTHROUGH_CODEC_ILBC # if PJMEDIA_HAS_PASSTHROUGH_CODEC_ILBC
{1, "iLBC", PJMEDIA_RTP_PT_ILBC, {PJMEDIA_FOURCC_ILBC}, {1, "iLBC", PJMEDIA_RTP_PT_ILBC, {PJMEDIA_FOURCC_ILBC},
8000, 1, 240, 8000, 1, 240,
13333, 15200, 2, 13333, 15200, 1, 1, 1,
NULL, NULL, NULL, NULL,
{1, {{{"mode", 4}, {"30", 2}}} } {1, {{{"mode", 4}, {"30", 2}}} }
}, },
# endif # endif
# if PJMEDIA_HAS_PASSTHROUGH_CODEC_PCMU # if PJMEDIA_HAS_PASSTHROUGH_CODEC_PCMU
{1, "PCMU", PJMEDIA_RTP_PT_PCMU, {PJMEDIA_FOURCC_G711U}, {1, "PCMU", PJMEDIA_RTP_PT_PCMU, {PJMEDIA_FOURCC_PCMU},
8000, 1, 80, 8000, 1, 80,
64000, 64000, 2 64000, 64000, 2, 1, 1
}, },
# endif # endif
# if PJMEDIA_HAS_PASSTHROUGH_CODEC_PCMA # if PJMEDIA_HAS_PASSTHROUGH_CODEC_PCMA
{1, "PCMA", PJMEDIA_RTP_PT_PCMA, {PJMEDIA_FOURCC_G711A}, {1, "PCMA", PJMEDIA_RTP_PT_PCMA, {PJMEDIA_FOURCC_PCMA},
8000, 1, 80, 8000, 1, 80,
64000, 64000, 2 64000, 64000, 2, 1, 1
}, },
# endif # endif
}; };
@ -246,15 +248,17 @@ static pj_status_t pack_amr ( codec_private_t *codec_data,
unsigned len; unsigned len;
sf = pjmedia_frame_ext_get_subframe(input, i); sf = pjmedia_frame_ext_get_subframe(input, i);
len = (sf->bitlen + 7) >> 3;
len = sf->bitlen >> 3;
if (sf->bitlen & 0x07)
++len;
info = (pjmedia_codec_amr_bit_info*) &frames[i].bit_info; info = (pjmedia_codec_amr_bit_info*) &frames[i].bit_info;
pj_bzero(info, sizeof(*info)); pj_bzero(info, sizeof(*info));
info->frame_type = pjmedia_codec_amr_get_mode2(enc_setting->amr_nb,
len); if (len == 0) {
info->frame_type = (pj_uint8_t)(enc_setting->amr_nb? 14 : 15);
} else {
info->frame_type = pjmedia_codec_amr_get_mode2(enc_setting->amr_nb,
len);
}
info->good_quality = 1; info->good_quality = 1;
info->mode = setting->enc_mode; info->mode = setting->enc_mode;
@ -449,9 +453,9 @@ static pj_status_t default_attr ( pjmedia_codec_factory *factory,
/* Default flags. */ /* Default flags. */
attr->setting.frm_per_pkt = codec_desc[i].frm_per_pkt; attr->setting.frm_per_pkt = codec_desc[i].frm_per_pkt;
attr->setting.plc = 0; attr->setting.plc = codec_desc[i].plc;
attr->setting.penh= 0; attr->setting.penh= 0;
attr->setting.vad = 0; attr->setting.vad = codec_desc[i].vad;
attr->setting.cng = attr->setting.vad; attr->setting.cng = attr->setting.vad;
attr->setting.dec_fmtp = codec_desc[i].dec_fmtp; attr->setting.dec_fmtp = codec_desc[i].dec_fmtp;
@ -758,14 +762,22 @@ static pj_status_t codec_encode( pjmedia_codec *codec,
sf = pjmedia_frame_ext_get_subframe(input_, i); sf = pjmedia_frame_ext_get_subframe(input_, i);
pj_assert(sf); pj_assert(sf);
sf_len = sf->bitlen >> 3; sf_len = (sf->bitlen + 7) >> 3;
if (sf->bitlen & 0x07)
++sf_len;
pj_memcpy(p, sf->data, sf_len); pj_memcpy(p, sf->data, sf_len);
p += sf_len; p += sf_len;
output->size += sf_len; output->size += sf_len;
#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
/* If there is SID or DTX frame, break the loop. */
if (desc->pt == PJMEDIA_RTP_PT_G729 &&
sf_len < codec_data->avg_frame_size)
{
break;
}
#endif
} }
} }
} }

View File

@ -51,6 +51,8 @@
#define SLOT_TYPE unsigned #define SLOT_TYPE unsigned
#define INVALID_SLOT ((SLOT_TYPE)-1) #define INVALID_SLOT ((SLOT_TYPE)-1)
#define BUFFER_SIZE PJMEDIA_MAX_MTU #define BUFFER_SIZE PJMEDIA_MAX_MTU
#define MAX_LEVEL (32767)
#define MIN_LEVEL (-32768)
/* /*
* DON'T GET CONFUSED WITH TX/RX!! * DON'T GET CONFUSED WITH TX/RX!!
@ -152,6 +154,10 @@ static pj_status_t create_conf_port( pj_pool_t *pool,
conf_port->rx_setting = PJMEDIA_PORT_ENABLE; conf_port->rx_setting = PJMEDIA_PORT_ENABLE;
conf_port->tx_setting = PJMEDIA_PORT_ENABLE; conf_port->tx_setting = PJMEDIA_PORT_ENABLE;
/* Default level adjustment is 128 (which means no adjustment) */
conf_port->tx_adj_level = NORMAL_LEVEL;
conf_port->rx_adj_level = NORMAL_LEVEL;
/* Create transmit flag array */ /* Create transmit flag array */
conf_port->listener_slots = (SLOT_TYPE*) conf_port->listener_slots = (SLOT_TYPE*)
pj_pool_zalloc(pool, pj_pool_zalloc(pool,
@ -165,7 +171,6 @@ static pj_status_t create_conf_port( pj_pool_t *pool,
/* Init pjmedia_frame structure in the TX buffer. */ /* Init pjmedia_frame structure in the TX buffer. */
f = (pjmedia_frame*)conf_port->tx_buf; f = (pjmedia_frame*)conf_port->tx_buf;
f->buf = conf_port->tx_buf + sizeof(pjmedia_frame); f->buf = conf_port->tx_buf + sizeof(pjmedia_frame);
f->size = 0;
/* Done */ /* Done */
*p_conf_port = conf_port; *p_conf_port = conf_port;
@ -672,6 +677,8 @@ PJ_DEF(pj_status_t) pjmedia_conf_disconnect_port( pjmedia_conf *conf,
} }
if (i != src_port->listener_cnt) { if (i != src_port->listener_cnt) {
pjmedia_frame_ext *f;
pj_assert(src_port->listener_cnt > 0 && pj_assert(src_port->listener_cnt > 0 &&
src_port->listener_cnt < conf->max_ports); src_port->listener_cnt < conf->max_ports);
pj_assert(dst_port->transmitter_cnt > 0 && pj_assert(dst_port->transmitter_cnt > 0 &&
@ -682,8 +689,12 @@ PJ_DEF(pj_status_t) pjmedia_conf_disconnect_port( pjmedia_conf *conf,
--src_port->listener_cnt; --src_port->listener_cnt;
--dst_port->transmitter_cnt; --dst_port->transmitter_cnt;
/* Clean up sink TX buffer. */ /* Cleanup listener TX buffer. */
pj_bzero(dst_port->tx_buf, sizeof(pjmedia_frame_ext)); f = (pjmedia_frame_ext*)dst_port->tx_buf;
f->base.type = PJMEDIA_FRAME_TYPE_NONE;
f->base.size = 0;
f->samples_cnt = 0;
f->subframe_cnt = 0;
PJ_LOG(4,(THIS_FILE, PJ_LOG(4,(THIS_FILE,
"Port %d (%.*s) stop transmitting to port %d (%.*s)", "Port %d (%.*s) stop transmitting to port %d (%.*s)",
@ -776,6 +787,7 @@ PJ_DEF(pj_status_t) pjmedia_conf_remove_port( pjmedia_conf *conf,
while (conf_port->listener_cnt) { while (conf_port->listener_cnt) {
unsigned dst_slot; unsigned dst_slot;
struct conf_port *dst_port; struct conf_port *dst_port;
pjmedia_frame_ext *f;
dst_slot = conf_port->listener_slots[conf_port->listener_cnt-1]; dst_slot = conf_port->listener_slots[conf_port->listener_cnt-1];
dst_port = conf->ports[dst_slot]; dst_port = conf->ports[dst_slot];
@ -784,8 +796,12 @@ PJ_DEF(pj_status_t) pjmedia_conf_remove_port( pjmedia_conf *conf,
pj_assert(conf->connect_cnt > 0); pj_assert(conf->connect_cnt > 0);
--conf->connect_cnt; --conf->connect_cnt;
/* Clean up TX buffer. */ /* Cleanup & reinit listener TX buffer. */
pj_bzero(dst_port->tx_buf, sizeof(pjmedia_frame_ext)); f = (pjmedia_frame_ext*)dst_port->tx_buf;
f->base.type = PJMEDIA_FRAME_TYPE_NONE;
f->base.size = 0;
f->samples_cnt = 0;
f->subframe_cnt = 0;
} }
/* Remove the port. */ /* Remove the port. */
@ -856,6 +872,8 @@ PJ_DEF(pj_status_t) pjmedia_conf_get_port_info( pjmedia_conf *conf,
info->samples_per_frame = conf_port->info->samples_per_frame; info->samples_per_frame = conf_port->info->samples_per_frame;
info->bits_per_sample = conf_port->info->bits_per_sample; info->bits_per_sample = conf_port->info->bits_per_sample;
info->format = conf_port->port->info.format; info->format = conf_port->port->info.format;
info->tx_adj_level = conf_port->tx_adj_level - NORMAL_LEVEL;
info->rx_adj_level = conf_port->rx_adj_level - NORMAL_LEVEL;
return PJ_SUCCESS; return PJ_SUCCESS;
} }
@ -934,6 +952,11 @@ PJ_DEF(pj_status_t) pjmedia_conf_adjust_rx_level( pjmedia_conf *conf,
conf_port = conf->ports[slot]; conf_port = conf->ports[slot];
/* Level adjustment is applicable only for ports that work with raw PCM. */
PJ_ASSERT_RETURN(conf_port->info->format.u32 == 0 ||
conf_port->info->format.u32 == PJMEDIA_FOURCC_L16,
PJ_EIGNORED);
/* Set normalized adjustment level. */ /* Set normalized adjustment level. */
conf_port->rx_adj_level = adj_level + NORMAL_LEVEL; conf_port->rx_adj_level = adj_level + NORMAL_LEVEL;
@ -964,6 +987,14 @@ PJ_DEF(pj_status_t) pjmedia_conf_adjust_tx_level( pjmedia_conf *conf,
conf_port = conf->ports[slot]; conf_port = conf->ports[slot];
/* Level adjustment is applicable only for ports that work with raw PCM. */
PJ_ASSERT_RETURN(conf_port->info->format.u32 == 0 ||
conf_port->info->format.u32 == PJMEDIA_FOURCC_L16,
PJ_EIGNORED);
/* Set normalized adjustment level. */
conf_port->tx_adj_level = adj_level + NORMAL_LEVEL;
return PJ_SUCCESS; return PJ_SUCCESS;
} }
@ -1032,6 +1063,28 @@ static pj_status_t write_frame(struct conf_port *cport_dst,
if (nsamples_to_copy > nsamples_req) if (nsamples_to_copy > nsamples_req)
nsamples_to_copy = nsamples_req; nsamples_to_copy = nsamples_req;
/* Adjust TX level. */
if (cport_dst->tx_adj_level != NORMAL_LEVEL) {
pj_int16_t *p, *p_end;
p = f_start;
p_end = p + nsamples_to_copy;
while (p < p_end) {
pj_int32_t itemp = *p;
/* Adjust the level */
itemp = (itemp * cport_dst->tx_adj_level) >> 7;
/* Clip the signal if it's too loud */
if (itemp > MAX_LEVEL) itemp = MAX_LEVEL;
else if (itemp < MIN_LEVEL) itemp = MIN_LEVEL;
/* Put back in the buffer. */
*p = (pj_int16_t)itemp;
++p;
}
}
pjmedia_copy_samples((pj_int16_t*)frm_dst->buf + (frm_dst->size>>1), pjmedia_copy_samples((pj_int16_t*)frm_dst->buf + (frm_dst->size>>1),
f_start, f_start,
nsamples_to_copy); nsamples_to_copy);
@ -1131,8 +1184,6 @@ static pj_status_t get_frame(pjmedia_port *this_port,
pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata; pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata;
unsigned ci, i; unsigned ci, i;
PJ_TODO(ADJUST_RX_TX_LEVEL_FOR_PCM_FRAMES);
/* Must lock mutex */ /* Must lock mutex */
pj_mutex_lock(conf->mutex); pj_mutex_lock(conf->mutex);
@ -1173,7 +1224,7 @@ static pj_status_t get_frame(pjmedia_port *this_port,
pjmedia_frame *f = (pjmedia_frame*)conf->buf; pjmedia_frame *f = (pjmedia_frame*)conf->buf;
pj_status_t status; pj_status_t status;
unsigned j; unsigned j;
pj_int32_t level; pj_int32_t level = 0;
pj_add_timestamp32(&cport->ts_rx, cport->info->samples_per_frame); pj_add_timestamp32(&cport->ts_rx, cport->info->samples_per_frame);
@ -1185,18 +1236,41 @@ static pj_status_t get_frame(pjmedia_port *this_port,
if (status != PJ_SUCCESS) if (status != PJ_SUCCESS)
continue; continue;
/* Calculate RX level. */ /* Calculate & adjust RX level. */
if (f->type == PJMEDIA_FRAME_TYPE_AUDIO) { if (f->type == PJMEDIA_FRAME_TYPE_AUDIO) {
level = pjmedia_calc_avg_signal((const pj_int16_t*)f->buf, if (cport->rx_adj_level != NORMAL_LEVEL) {
f->size >>1 ); pj_int16_t *p = (pj_int16_t*)f->buf;
pj_int16_t *end;
end = p + (f->size >> 1);
while (p < end) {
pj_int32_t itemp = *p;
/* Adjust the level */
itemp = (itemp * cport->rx_adj_level) >> 7;
/* Clip the signal if it's too loud */
if (itemp > MAX_LEVEL) itemp = MAX_LEVEL;
else if (itemp < MIN_LEVEL) itemp = MIN_LEVEL;
level += PJ_ABS(itemp);
/* Put back in the buffer. */
*p = (pj_int16_t)itemp;
++p;
}
level /= (f->size >> 1);
} else {
level = pjmedia_calc_avg_signal((const pj_int16_t*)f->buf,
f->size >> 1);
}
} else if (f->type == PJMEDIA_FRAME_TYPE_EXTENDED) { } else if (f->type == PJMEDIA_FRAME_TYPE_EXTENDED) {
/* For extended frame, TX level is unknown, so we just set /* For extended frame, TX level is unknown, so we just set
* it to NORMAL_LEVEL. * it to NORMAL_LEVEL.
*/ */
level = NORMAL_LEVEL; level = NORMAL_LEVEL;
} else { /* PJMEDIA_FRAME_TYPE_NONE */
level = 0;
} }
cport->rx_level = pjmedia_linear2ulaw(level) ^ 0xff; cport->rx_level = pjmedia_linear2ulaw(level) ^ 0xff;
/* Put the frame to all listeners. */ /* Put the frame to all listeners. */
@ -1220,8 +1294,11 @@ static pj_status_t get_frame(pjmedia_port *this_port,
continue; continue;
} }
/* Set listener TX level equal to transmitter RX level. */ /* Set listener TX level based on transmitter RX level &
listener->tx_level = cport->rx_level; * listener TX level.
*/
listener->tx_level = (cport->rx_level * listener->tx_adj_level)
>> 8;
} }
} }
} }
@ -1241,10 +1318,16 @@ static pj_status_t get_frame(pjmedia_port *this_port,
if (cport->tx_setting==PJMEDIA_PORT_MUTE || cport->transmitter_cnt==0) if (cport->tx_setting==PJMEDIA_PORT_MUTE || cport->transmitter_cnt==0)
{ {
pjmedia_frame_ext *f;
/* Clear left-over samples in tx_buffer, if any, so that it won't /* Clear left-over samples in tx_buffer, if any, so that it won't
* be transmitted next time we have audio signal. * be transmitted next time we have audio signal.
*/ */
pj_bzero(cport->tx_buf, sizeof(pjmedia_frame_ext)); f = (pjmedia_frame_ext*)cport->tx_buf;
f->base.type = PJMEDIA_FRAME_TYPE_NONE;
f->base.size = 0;
f->samples_cnt = 0;
f->subframe_cnt = 0;
cport->tx_level = 0; cport->tx_level = 0;
@ -1279,8 +1362,9 @@ static pj_status_t get_frame(pjmedia_port *this_port,
pj_uint16_t samples_per_subframe; pj_uint16_t samples_per_subframe;
if (f_src_->samples_cnt < this_cport->info->samples_per_frame) { if (f_src_->samples_cnt < this_cport->info->samples_per_frame) {
pj_bzero(this_cport->tx_buf, sizeof(pjmedia_frame_ext)); f_dst->base.type = PJMEDIA_FRAME_TYPE_NONE;
frame->type = PJMEDIA_FRAME_TYPE_NONE; f_dst->samples_cnt = 0;
f_dst->subframe_cnt = 0;
break; break;
} }
@ -1302,8 +1386,8 @@ static pj_status_t get_frame(pjmedia_port *this_port,
} else if (f_src->type == PJMEDIA_FRAME_TYPE_AUDIO) { } else if (f_src->type == PJMEDIA_FRAME_TYPE_AUDIO) {
if ((f_src->size>>1) < this_cport->info->samples_per_frame) { if ((f_src->size>>1) < this_cport->info->samples_per_frame) {
pj_bzero(this_cport->tx_buf, sizeof(pjmedia_frame_ext));
frame->type = PJMEDIA_FRAME_TYPE_NONE; frame->type = PJMEDIA_FRAME_TYPE_NONE;
frame->size = 0;
break; break;
} }
@ -1320,9 +1404,12 @@ static pj_status_t get_frame(pjmedia_port *this_port,
this_cport->info->samples_per_frame, this_cport->info->samples_per_frame,
f_src->size >> 1); f_src->size >> 1);
} else { /* PJMEDIA_FRAME_TYPE_NONE */ } else { /* PJMEDIA_FRAME_TYPE_NONE */
pjmedia_frame_ext *f_dst = (pjmedia_frame_ext*)frame;
/* Reset TX buffer */ /* Reset TX buffer */
pj_bzero(this_cport->tx_buf, sizeof(pjmedia_frame_ext)); f_dst->base.type = PJMEDIA_FRAME_TYPE_NONE;
frame->type = PJMEDIA_FRAME_TYPE_NONE; f_dst->samples_cnt = 0;
f_dst->subframe_cnt = 0;
} }
} while (0); } while (0);
@ -1341,7 +1428,7 @@ static pj_status_t put_frame(pjmedia_port *this_port,
pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata; pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata;
struct conf_port *cport = conf->ports[this_port->port_data.ldata]; struct conf_port *cport = conf->ports[this_port->port_data.ldata];
unsigned j; unsigned j;
pj_int32_t level; pj_int32_t level = 0;
pj_add_timestamp32(&cport->ts_rx, cport->info->samples_per_frame); pj_add_timestamp32(&cport->ts_rx, cport->info->samples_per_frame);
@ -1357,18 +1444,41 @@ static pj_status_t put_frame(pjmedia_port *this_port,
return PJ_SUCCESS; return PJ_SUCCESS;
} }
/* Calculate RX level. */ /* Calculate & adjust RX level. */
if (f->type == PJMEDIA_FRAME_TYPE_AUDIO) { if (f->type == PJMEDIA_FRAME_TYPE_AUDIO) {
level = pjmedia_calc_avg_signal((const pj_int16_t*)f->buf, if (cport->rx_adj_level != NORMAL_LEVEL) {
f->size >>1 ); pj_int16_t *p = (pj_int16_t*)f->buf;
pj_int16_t *end;
end = p + (f->size >> 1);
while (p < end) {
pj_int32_t itemp = *p;
/* Adjust the level */
itemp = (itemp * cport->rx_adj_level) >> 7;
/* Clip the signal if it's too loud */
if (itemp > MAX_LEVEL) itemp = MAX_LEVEL;
else if (itemp < MIN_LEVEL) itemp = MIN_LEVEL;
level += PJ_ABS(itemp);
/* Put back in the buffer. */
*p = (pj_int16_t)itemp;
++p;
}
level /= (f->size >> 1);
} else {
level = pjmedia_calc_avg_signal((const pj_int16_t*)f->buf,
f->size >> 1);
}
} else if (f->type == PJMEDIA_FRAME_TYPE_EXTENDED) { } else if (f->type == PJMEDIA_FRAME_TYPE_EXTENDED) {
/* For extended frame, TX level is unknown, so we just set /* For extended frame, TX level is unknown, so we just set
* it to NORMAL_LEVEL. * it to NORMAL_LEVEL.
*/ */
level = NORMAL_LEVEL; level = NORMAL_LEVEL;
} else { /* PJMEDIA_FRAME_TYPE_NONE. */
level = 0;
} }
cport->rx_level = pjmedia_linear2ulaw(level) ^ 0xff; cport->rx_level = pjmedia_linear2ulaw(level) ^ 0xff;
/* Put the frame to all listeners. */ /* Put the frame to all listeners. */
@ -1401,8 +1511,10 @@ static pj_status_t put_frame(pjmedia_port *this_port,
continue; continue;
} }
/* Set listener TX level equal to transmitter RX level. */ /* Set listener TX level based on transmitter RX level & listener
listener->tx_level = cport->rx_level; * TX level.
*/
listener->tx_level = (cport->rx_level * listener->tx_adj_level) >> 8;
} }
return PJ_SUCCESS; return PJ_SUCCESS;

View File

@ -482,7 +482,7 @@ static pj_status_t get_frame_ext( pjmedia_port *port, pjmedia_frame *frame)
} }
if (frame_type == PJMEDIA_JB_MISSING_FRAME) { if (frame_type == PJMEDIA_JB_MISSING_FRAME) {
PJ_LOG(1,(stream->port.info.name.ptr, "Frame lost!")); PJ_LOG(5,(stream->port.info.name.ptr, "Frame lost!"));
} else if (frame_type == PJMEDIA_JB_ZERO_EMPTY_FRAME) { } else if (frame_type == PJMEDIA_JB_ZERO_EMPTY_FRAME) {
/* Jitter buffer is empty. Check if this is the first "empty" /* Jitter buffer is empty. Check if this is the first "empty"
* state. * state.
@ -492,7 +492,7 @@ static pj_status_t get_frame_ext( pjmedia_port *port, pjmedia_frame *frame)
/* Report the state of jitter buffer */ /* Report the state of jitter buffer */
pjmedia_jbuf_get_state(stream->jb, &jb_state); pjmedia_jbuf_get_state(stream->jb, &jb_state);
PJ_LOG(1,(stream->port.info.name.ptr, PJ_LOG(5,(stream->port.info.name.ptr,
"Jitter buffer empty (prefetch=%d)", "Jitter buffer empty (prefetch=%d)",
jb_state.prefetch)); jb_state.prefetch));
} }
@ -506,7 +506,7 @@ static pj_status_t get_frame_ext( pjmedia_port *port, pjmedia_frame *frame)
pjmedia_jbuf_get_state(stream->jb, &jb_state); pjmedia_jbuf_get_state(stream->jb, &jb_state);
if (stream->jb_last_frm != frame_type) { if (stream->jb_last_frm != frame_type) {
PJ_LOG(1,(stream->port.info.name.ptr, PJ_LOG(5,(stream->port.info.name.ptr,
"Jitter buffer is bufferring (prefetch=%d)", "Jitter buffer is bufferring (prefetch=%d)",
jb_state.prefetch)); jb_state.prefetch));
} }

View File

@ -778,8 +778,8 @@ static void RecCb(TAPSCommBuffer &buf, void *user_data)
} }
break; break;
case PJMEDIA_FOURCC_G711U: case PJMEDIA_FOURCC_PCMU:
case PJMEDIA_FOURCC_G711A: case PJMEDIA_FOURCC_PCMA:
{ {
unsigned samples_processed = 0; unsigned samples_processed = 0;
@ -857,13 +857,10 @@ static void PlayCb(TAPSCommBuffer &buf, void *user_data)
/* AMR header for APS is one byte, the format (may be!): /* AMR header for APS is one byte, the format (may be!):
* 0xxxxy00, where xxxx:frame type, y:not sure. * 0xxxxy00, where xxxx:frame type, y:not sure.
*/ */
unsigned len = sf->bitlen>>3; unsigned len = (sf->bitlen+7)>>3;
enum {SID_FT = 8 }; enum {SID_FT = 8 };
pj_uint8_t amr_header = 4, ft = SID_FT; pj_uint8_t amr_header = 4, ft = SID_FT;
if (sf->bitlen & 0x07)
++len;
if (len >= pjmedia_codec_amrnb_framelen[0]) if (len >= pjmedia_codec_amrnb_framelen[0])
ft = pjmedia_codec_amr_get_mode2(PJ_TRUE, len); ft = pjmedia_codec_amr_get_mode2(PJ_TRUE, len);
@ -975,8 +972,8 @@ static void PlayCb(TAPSCommBuffer &buf, void *user_data)
} }
break; break;
case PJMEDIA_FOURCC_G711U: case PJMEDIA_FOURCC_PCMU:
case PJMEDIA_FOURCC_G711A: case PJMEDIA_FOURCC_PCMA:
{ {
unsigned samples_ready = 0; unsigned samples_ready = 0;
unsigned samples_req = aps_g711_frame_len; unsigned samples_req = aps_g711_frame_len;
@ -1104,8 +1101,9 @@ static pj_status_t sound_open(pjmedia_dir dir,
if (strm->setting.format.u32 == 0) if (strm->setting.format.u32 == 0)
strm->setting.format.u32 = PJMEDIA_FOURCC_L16; strm->setting.format.u32 = PJMEDIA_FOURCC_L16;
/* Set audio engine settings. */ /* Set audio engine fourcc. */
if (strm->setting.format.u32 == PJMEDIA_FOURCC_G711U || if (strm->setting.format.u32 == PJMEDIA_FOURCC_PCMU ||
strm->setting.format.u32 == PJMEDIA_FOURCC_PCMA ||
strm->setting.format.u32 == PJMEDIA_FOURCC_L16) strm->setting.format.u32 == PJMEDIA_FOURCC_L16)
{ {
aps_setting.fourcc = TFourCC(KMCPFourCCIdG711); aps_setting.fourcc = TFourCC(KMCPFourCCIdG711);
@ -1113,33 +1111,41 @@ static pj_status_t sound_open(pjmedia_dir dir,
aps_setting.fourcc = TFourCC(strm->setting.format.u32); aps_setting.fourcc = TFourCC(strm->setting.format.u32);
} }
/* Set audio engine mode. */
if (strm->setting.format.u32 == PJMEDIA_FOURCC_AMR) if (strm->setting.format.u32 == PJMEDIA_FOURCC_AMR)
{ {
aps_setting.mode = (TAPSCodecMode)strm->setting.bitrate; aps_setting.mode = (TAPSCodecMode)strm->setting.bitrate;
} else if (strm->setting.format.u32 == PJMEDIA_FOURCC_G711U || }
strm->setting.format.u32 == PJMEDIA_FOURCC_L16 || else if (strm->setting.format.u32 == PJMEDIA_FOURCC_PCMU ||
(strm->setting.format.u32 == PJMEDIA_FOURCC_ILBC && strm->setting.format.u32 == PJMEDIA_FOURCC_L16 ||
strm->setting.mode == 30)) (strm->setting.format.u32 == PJMEDIA_FOURCC_ILBC &&
strm->setting.mode == 30))
{ {
aps_setting.mode = EULawOr30ms; aps_setting.mode = EULawOr30ms;
} else { }
else if (strm->setting.format.u32 == PJMEDIA_FOURCC_PCMA ||
(strm->setting.format.u32 == PJMEDIA_FOURCC_ILBC &&
strm->setting.mode == 20))
{
aps_setting.mode = EALawOr20ms; aps_setting.mode = EALawOr20ms;
} }
/* Disable VAD on L16 and G711. */ /* Disable VAD on L16 and G711. */
if (strm->setting.format.u32 == PJMEDIA_FOURCC_L16 || if (strm->setting.format.u32 == PJMEDIA_FOURCC_PCMU ||
strm->setting.format.u32 == PJMEDIA_FOURCC_G711U || strm->setting.format.u32 == PJMEDIA_FOURCC_PCMA ||
strm->setting.format.u32 == PJMEDIA_FOURCC_G711A) strm->setting.format.u32 == PJMEDIA_FOURCC_L16)
{ {
aps_setting.vad = EFalse; aps_setting.vad = EFalse;
} else { } else {
aps_setting.vad = strm->setting.vad; aps_setting.vad = strm->setting.vad;
} }
/* Set other audio engine attributes. */
aps_setting.plc = strm->setting.plc; aps_setting.plc = strm->setting.plc;
aps_setting.cng = strm->setting.cng; aps_setting.cng = strm->setting.cng;
aps_setting.loudspk = strm->setting.loudspk; aps_setting.loudspk = strm->setting.loudspk;
/* Set audio engine callbacks. */
if (strm->setting.format.u32 == PJMEDIA_FOURCC_L16) { if (strm->setting.format.u32 == PJMEDIA_FOURCC_L16) {
aps_play_cb = &PlayCbPcm; aps_play_cb = &PlayCbPcm;
aps_rec_cb = &RecCbPcm; aps_rec_cb = &RecCbPcm;
@ -1148,7 +1154,7 @@ static pj_status_t sound_open(pjmedia_dir dir,
aps_rec_cb = &RecCb; aps_rec_cb = &RecCb;
} }
// Create the audio engine. /* Create the audio engine. */
TRAPD(err, strm->engine = CPjAudioEngine::NewL(strm, TRAPD(err, strm->engine = CPjAudioEngine::NewL(strm,
aps_rec_cb, aps_play_cb, aps_rec_cb, aps_play_cb,
strm, aps_setting)); strm, aps_setting));