Ticket #504: final installment to support stereo audio all the way in PJMEDIA. Please see tickiet #504 for more info
git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@1898 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
parent
a171e9edbe
commit
7d60d052eb
|
@ -58,6 +58,7 @@ SOURCE session.c
|
|||
SOURCE silencedet.c
|
||||
SOURCE sound_port.c
|
||||
SOURCE splitcomb.c
|
||||
SOURCE stereo_port.c
|
||||
SOURCE stream.c
|
||||
SOURCE tonegen.c
|
||||
SOURCE transport_ice.c
|
||||
|
|
|
@ -52,8 +52,8 @@ export PJMEDIA_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
|
|||
null_port.o plc_common.o port.o splitcomb.o \
|
||||
resample_resample.o resample_libsamplerate.o \
|
||||
resample_port.o rtcp.o rtp.o sdp.o sdp_cmp.o sdp_neg.o \
|
||||
session.o silencedet.o sound_port.o stream.o \
|
||||
tonegen.o transport_ice.o transport_srtp.o \
|
||||
session.o silencedet.o sound_port.o stereo_port.o \
|
||||
stream.o tonegen.o transport_ice.o transport_srtp.o \
|
||||
transport_udp.o \
|
||||
wav_player.o wav_playlist.o wav_writer.o wave.o \
|
||||
wsola.o $(SOUND_OBJS) $(NULLSOUND_OBJS)
|
||||
|
|
|
@ -237,6 +237,10 @@ SOURCE=..\src\pjmedia\splitcomb.c
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\pjmedia\stereo_port.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\pjmedia\stream.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -401,6 +405,10 @@ SOURCE=..\include\pjmedia\splitcomb.h
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\include\pjmedia\stereo.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\include\pjmedia\stream.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
|
@ -917,6 +917,10 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\pjmedia\stereo_port.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\pjmedia\stream.c"
|
||||
>
|
||||
|
@ -1208,6 +1212,10 @@
|
|||
RelativePath="..\include\pjmedia\splitcomb.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\pjmedia\stereo.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\pjmedia\stream.h"
|
||||
>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -51,6 +51,7 @@
|
|||
#include <pjmedia/sound.h>
|
||||
#include <pjmedia/sound_port.h>
|
||||
#include <pjmedia/splitcomb.h>
|
||||
#include <pjmedia/stereo.h>
|
||||
#include <pjmedia/tonegen.h>
|
||||
#include <pjmedia/transport.h>
|
||||
#include <pjmedia/transport_ice.h>
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <pjmedia/resample.h>
|
||||
#include <pjmedia/silencedet.h>
|
||||
#include <pjmedia/sound_port.h>
|
||||
#include <pjmedia/stereo.h>
|
||||
#include <pjmedia/stream.h>
|
||||
#include <pj/array.h>
|
||||
#include <pj/assert.h>
|
||||
|
@ -112,11 +113,11 @@ struct conf_port
|
|||
unsigned listener_cnt; /**< Number of listeners. */
|
||||
SLOT_TYPE *listener_slots;/**< Array of listeners. */
|
||||
unsigned transmitter_cnt;/**<Number of transmitters. */
|
||||
pjmedia_silence_det *vad; /**< VAD for this port. */
|
||||
|
||||
/* Shortcut for port info. */
|
||||
unsigned clock_rate; /**< Port's clock rate. */
|
||||
unsigned samples_per_frame; /**< Port's samples per frame. */
|
||||
unsigned channel_count; /**< Port's channel count. */
|
||||
|
||||
/* Calculated signal levels: */
|
||||
unsigned tx_level; /**< Last tx level to this port. */
|
||||
|
@ -285,26 +286,14 @@ static pj_status_t create_conf_port( pj_pool_t *pool,
|
|||
conf_port->port = port;
|
||||
conf_port->clock_rate = port->info.clock_rate;
|
||||
conf_port->samples_per_frame = port->info.samples_per_frame;
|
||||
conf_port->channel_count = port->info.channel_count;
|
||||
} else {
|
||||
conf_port->port = NULL;
|
||||
conf_port->clock_rate = conf->clock_rate;
|
||||
conf_port->samples_per_frame = conf->samples_per_frame;
|
||||
conf_port->channel_count = conf->channel_count;
|
||||
}
|
||||
|
||||
/* Create and init vad. */
|
||||
status = pjmedia_silence_det_create( pool,
|
||||
conf_port->clock_rate,
|
||||
conf_port->samples_per_frame,
|
||||
&conf_port->vad);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Set fixed */
|
||||
pjmedia_silence_det_set_fixed(conf_port->vad, 2);
|
||||
|
||||
/* Set VAD name */
|
||||
pjmedia_silence_det_set_name(conf_port->vad, conf_port->name.ptr);
|
||||
|
||||
/* If port's clock rate is different than conference's clock rate,
|
||||
* create a resample sessions.
|
||||
*/
|
||||
|
@ -346,16 +335,48 @@ static pj_status_t create_conf_port( pj_pool_t *pool,
|
|||
|
||||
/*
|
||||
* Initialize rx and tx buffer, only when port's samples per frame or
|
||||
* port's clock rate is different then the conference bridge settings.
|
||||
* port's clock rate or channel number is different then the conference
|
||||
* bridge settings.
|
||||
*/
|
||||
if (conf_port->clock_rate != conf->clock_rate ||
|
||||
conf_port->channel_count != conf->channel_count ||
|
||||
conf_port->samples_per_frame != conf->samples_per_frame)
|
||||
{
|
||||
unsigned port_ptime, conf_ptime, buff_ptime;
|
||||
|
||||
port_ptime = conf_port->samples_per_frame / conf_port->channel_count *
|
||||
1000 / conf_port->clock_rate;
|
||||
conf_ptime = conf->samples_per_frame / conf->channel_count *
|
||||
1000 / conf->clock_rate;
|
||||
|
||||
/* Calculate the size (in ptime) for the port buffer according to
|
||||
* this formula:
|
||||
* - if either ptime is an exact multiple of the other, then use
|
||||
* the larger ptime (e.g. 20ms and 40ms, use 40ms).
|
||||
* - if not, then the ptime is sum of both ptimes (e.g. 20ms
|
||||
* and 30ms, use 50ms)
|
||||
*/
|
||||
if (port_ptime > conf_ptime) {
|
||||
buff_ptime = conf_ptime * (port_ptime / conf_ptime);
|
||||
if (port_ptime % conf_ptime)
|
||||
buff_ptime += conf_ptime;
|
||||
} else {
|
||||
buff_ptime = port_ptime * (conf_ptime / port_ptime);
|
||||
if (conf_ptime % port_ptime)
|
||||
buff_ptime += port_ptime;
|
||||
}
|
||||
|
||||
/* Create RX buffer. */
|
||||
conf_port->rx_buf_cap = (unsigned)(conf_port->samples_per_frame +
|
||||
conf->samples_per_frame *
|
||||
conf_port->clock_rate * 1.0 /
|
||||
conf->clock_rate);
|
||||
//conf_port->rx_buf_cap = (unsigned)(conf_port->samples_per_frame +
|
||||
// conf->samples_per_frame *
|
||||
// conf_port->clock_rate * 1.0 /
|
||||
// conf->clock_rate);
|
||||
conf_port->rx_buf_cap = conf_port->clock_rate * buff_ptime / 1000;
|
||||
if (conf_port->channel_count > conf->channel_count)
|
||||
conf_port->rx_buf_cap *= conf_port->channel_count;
|
||||
else
|
||||
conf_port->rx_buf_cap *= conf->channel_count;
|
||||
|
||||
conf_port->rx_buf_count = 0;
|
||||
conf_port->rx_buf = (pj_int16_t*)
|
||||
pj_pool_alloc(pool, conf_port->rx_buf_cap *
|
||||
|
@ -698,10 +719,13 @@ PJ_DEF(pj_status_t) pjmedia_conf_add_port( pjmedia_conf *conf,
|
|||
if (!port_name)
|
||||
port_name = &strm_port->info.name;
|
||||
|
||||
/* For this version of PJMEDIA, port MUST have the same number of
|
||||
* PCM channels.
|
||||
/* For this version of PJMEDIA, channel(s) number MUST be:
|
||||
* - same between port & conference bridge.
|
||||
* - monochannel on port or conference bridge.
|
||||
*/
|
||||
if (strm_port->info.channel_count != conf->channel_count) {
|
||||
if (strm_port->info.channel_count != conf->channel_count &&
|
||||
(strm_port->info.channel_count != 1 && conf->channel_count != 1))
|
||||
{
|
||||
pj_assert(!"Number of channels mismatch");
|
||||
return PJMEDIA_ENCCHANNEL;
|
||||
}
|
||||
|
@ -766,10 +790,13 @@ PJ_DEF(pj_status_t) pjmedia_conf_add_passive_port( pjmedia_conf *conf,
|
|||
|
||||
PJ_ASSERT_RETURN(conf && pool, PJ_EINVAL);
|
||||
|
||||
/* For this version of PJMEDIA, port MUST have the same number of
|
||||
* PCM channels.
|
||||
/* For this version of PJMEDIA, channel(s) number MUST be:
|
||||
* - same between port & conference bridge.
|
||||
* - monochannel on port or conference bridge.
|
||||
*/
|
||||
if (channel_count != conf->channel_count) {
|
||||
if (channel_count != conf->channel_count &&
|
||||
(channel_count != 1 && conf->channel_count != 1))
|
||||
{
|
||||
pj_assert(!"Number of channels mismatch");
|
||||
return PJMEDIA_ENCCHANNEL;
|
||||
}
|
||||
|
@ -1140,7 +1167,7 @@ PJ_DEF(pj_status_t) pjmedia_conf_get_port_info( pjmedia_conf *conf,
|
|||
info->listener_cnt = conf_port->listener_cnt;
|
||||
info->listener_slots = conf_port->listener_slots;
|
||||
info->clock_rate = conf_port->clock_rate;
|
||||
info->channel_count = conf->channel_count;
|
||||
info->channel_count = conf_port->channel_count;
|
||||
info->samples_per_frame = conf_port->samples_per_frame;
|
||||
info->bits_per_sample = conf->bits_per_sample;
|
||||
info->tx_adj_level = conf_port->tx_adj_level - NORMAL_LEVEL;
|
||||
|
@ -1274,8 +1301,10 @@ static pj_status_t read_port( pjmedia_conf *conf,
|
|||
(int)cport->name.slen, cport->name.ptr,
|
||||
count));
|
||||
|
||||
/* If port's samples per frame and sampling rate matches conference
|
||||
* bridge's settings, get the frame directly from the port.
|
||||
/*
|
||||
* If port's samples per frame and sampling rate and channel count
|
||||
* matche conference bridge's settings, get the frame directly from
|
||||
* the port.
|
||||
*/
|
||||
if (cport->rx_buf_cap == 0) {
|
||||
pjmedia_frame f;
|
||||
|
@ -1295,6 +1324,7 @@ static pj_status_t read_port( pjmedia_conf *conf,
|
|||
return status;
|
||||
|
||||
} else {
|
||||
unsigned samples_req;
|
||||
|
||||
/* Initialize frame type */
|
||||
if (cport->rx_buf_count == 0) {
|
||||
|
@ -1306,10 +1336,14 @@ static pj_status_t read_port( pjmedia_conf *conf,
|
|||
|
||||
/*
|
||||
* If we don't have enough samples in rx_buf, read from the port
|
||||
* first. Remember that rx_buf may be in different clock rate!
|
||||
* first. Remember that rx_buf may be in different clock rate and
|
||||
* channel count!
|
||||
*/
|
||||
while (cport->rx_buf_count < count * 1.0 *
|
||||
cport->clock_rate / conf->clock_rate) {
|
||||
|
||||
samples_req = (unsigned) (count * 1.0 *
|
||||
cport->clock_rate / conf->clock_rate);
|
||||
|
||||
while (cport->rx_buf_count < samples_req) {
|
||||
|
||||
pjmedia_frame f;
|
||||
pj_status_t status;
|
||||
|
@ -1336,7 +1370,26 @@ static pj_status_t read_port( pjmedia_conf *conf,
|
|||
*type = PJMEDIA_FRAME_TYPE_AUDIO;
|
||||
}
|
||||
|
||||
cport->rx_buf_count += cport->samples_per_frame;
|
||||
/* Adjust channels */
|
||||
if (cport->channel_count != conf->channel_count) {
|
||||
if (cport->channel_count == 1) {
|
||||
pjmedia_convert_channel_1ton(f.buf, f.buf,
|
||||
conf->channel_count,
|
||||
cport->samples_per_frame,
|
||||
0);
|
||||
cport->rx_buf_count += (cport->samples_per_frame *
|
||||
conf->channel_count);
|
||||
} else { /* conf->channel_count == 1 */
|
||||
pjmedia_convert_channel_nto1(f.buf, f.buf,
|
||||
cport->channel_count,
|
||||
cport->samples_per_frame,
|
||||
PJMEDIA_STEREO_MIX, 0);
|
||||
cport->rx_buf_count += (cport->samples_per_frame /
|
||||
cport->channel_count);
|
||||
}
|
||||
} else {
|
||||
cport->rx_buf_count += cport->samples_per_frame;
|
||||
}
|
||||
|
||||
TRACE_((THIS_FILE, " rx buffer size is now %d",
|
||||
cport->rx_buf_count));
|
||||
|
@ -1361,7 +1414,7 @@ static pj_status_t read_port( pjmedia_conf *conf,
|
|||
conf->clock_rate);
|
||||
cport->rx_buf_count -= src_count;
|
||||
if (cport->rx_buf_count) {
|
||||
pjmedia_copy_samples(cport->rx_buf, cport->rx_buf+src_count,
|
||||
pjmedia_move_samples(cport->rx_buf, cport->rx_buf+src_count,
|
||||
cport->rx_buf_count);
|
||||
}
|
||||
|
||||
|
@ -1373,7 +1426,7 @@ static pj_status_t read_port( pjmedia_conf *conf,
|
|||
pjmedia_copy_samples(frame, cport->rx_buf, count);
|
||||
cport->rx_buf_count -= count;
|
||||
if (cport->rx_buf_count) {
|
||||
pjmedia_copy_samples(cport->rx_buf, cport->rx_buf+count,
|
||||
pjmedia_move_samples(cport->rx_buf, cport->rx_buf+count,
|
||||
cport->rx_buf_count);
|
||||
}
|
||||
}
|
||||
|
@ -1395,6 +1448,7 @@ static pj_status_t write_port(pjmedia_conf *conf, struct conf_port *cport,
|
|||
pj_status_t status;
|
||||
pj_int32_t adj_level;
|
||||
pj_int32_t tx_level;
|
||||
unsigned dst_count;
|
||||
|
||||
*frm_type = PJMEDIA_FRAME_TYPE_AUDIO;
|
||||
|
||||
|
@ -1412,7 +1466,8 @@ static pj_status_t write_port(pjmedia_conf *conf, struct conf_port *cport,
|
|||
|
||||
/* Add sample counts to heart-beat samples */
|
||||
cport->tx_heart_beat += conf->samples_per_frame * cport->clock_rate /
|
||||
conf->clock_rate;
|
||||
conf->clock_rate *
|
||||
cport->channel_count / conf->channel_count;
|
||||
|
||||
/* Set frame timestamp */
|
||||
frame.timestamp.u64 = timestamp->u64 * cport->clock_rate /
|
||||
|
@ -1476,8 +1531,8 @@ static pj_status_t write_port(pjmedia_conf *conf, struct conf_port *cport,
|
|||
|
||||
tx_level = 0;
|
||||
|
||||
for (j=0; j<conf->samples_per_frame; ++j) {
|
||||
if (adj_level != NORMAL_LEVEL) {
|
||||
if (adj_level != NORMAL_LEVEL) {
|
||||
for (j=0; j<conf->samples_per_frame; ++j) {
|
||||
pj_int32_t itemp = cport->mix_buf[j];
|
||||
|
||||
/* Adjust the level */
|
||||
|
@ -1490,11 +1545,14 @@ static pj_status_t write_port(pjmedia_conf *conf, struct conf_port *cport,
|
|||
|
||||
/* Put back in the buffer. */
|
||||
buf[j] = (pj_int16_t) itemp;
|
||||
} else {
|
||||
buf[j] = (pj_int16_t) cport->mix_buf[j];
|
||||
}
|
||||
|
||||
tx_level += (buf[j]>0? buf[j] : -buf[j]);
|
||||
tx_level += (buf[j]>=0? buf[j] : -buf[j]);
|
||||
}
|
||||
} else {
|
||||
for (j=0; j<conf->samples_per_frame; ++j) {
|
||||
buf[j] = (pj_int16_t) cport->mix_buf[j];
|
||||
tx_level += (buf[j]>=0? buf[j] : -buf[j]);
|
||||
}
|
||||
}
|
||||
|
||||
tx_level /= conf->samples_per_frame;
|
||||
|
@ -1504,11 +1562,13 @@ static pj_status_t write_port(pjmedia_conf *conf, struct conf_port *cport,
|
|||
|
||||
cport->tx_level = tx_level;
|
||||
|
||||
/* If port has the same clock_rate and samples_per_frame settings as
|
||||
* the conference bridge, transmit the frame as is.
|
||||
/* If port has the same clock_rate and samples_per_frame and
|
||||
* number of channels as the conference bridge, transmit the
|
||||
* frame as is.
|
||||
*/
|
||||
if (cport->clock_rate == conf->clock_rate &&
|
||||
cport->samples_per_frame == conf->samples_per_frame)
|
||||
cport->samples_per_frame == conf->samples_per_frame &&
|
||||
cport->channel_count == conf->channel_count)
|
||||
{
|
||||
if (cport->port != NULL) {
|
||||
pjmedia_frame frame;
|
||||
|
@ -1532,25 +1592,39 @@ static pj_status_t write_port(pjmedia_conf *conf, struct conf_port *cport,
|
|||
|
||||
/* If it has different clock_rate, must resample. */
|
||||
if (cport->clock_rate != conf->clock_rate) {
|
||||
|
||||
unsigned dst_count;
|
||||
|
||||
pjmedia_resample_run( cport->tx_resample, buf,
|
||||
cport->tx_buf + cport->tx_buf_count );
|
||||
|
||||
dst_count = (unsigned)(conf->samples_per_frame * 1.0 *
|
||||
cport->clock_rate / conf->clock_rate);
|
||||
cport->tx_buf_count += dst_count;
|
||||
|
||||
} else {
|
||||
/* Same clock rate.
|
||||
* Just copy the samples to tx_buffer.
|
||||
*/
|
||||
pjmedia_copy_samples( cport->tx_buf + cport->tx_buf_count,
|
||||
buf, conf->samples_per_frame );
|
||||
cport->tx_buf_count += conf->samples_per_frame;
|
||||
dst_count = conf->samples_per_frame;
|
||||
}
|
||||
|
||||
/* Adjust channels */
|
||||
if (cport->channel_count != conf->channel_count) {
|
||||
pj_int16_t *tx_buf = cport->tx_buf + cport->tx_buf_count;
|
||||
if (conf->channel_count == 1) {
|
||||
pjmedia_convert_channel_1ton(tx_buf, tx_buf,
|
||||
cport->channel_count,
|
||||
dst_count, 0);
|
||||
dst_count *= cport->channel_count;
|
||||
} else { /* cport->channel_count == 1 */
|
||||
pjmedia_convert_channel_nto1(tx_buf, tx_buf,
|
||||
conf->channel_count,
|
||||
dst_count, PJMEDIA_STEREO_MIX, 0);
|
||||
dst_count /= conf->channel_count;
|
||||
}
|
||||
}
|
||||
|
||||
cport->tx_buf_count += dst_count;
|
||||
|
||||
pj_assert(cport->tx_buf_count <= cport->tx_buf_cap);
|
||||
|
||||
/* Transmit while we have enough frame in the tx_buf. */
|
||||
status = PJ_SUCCESS;
|
||||
ts = 0;
|
||||
|
@ -1589,7 +1663,7 @@ static pj_status_t write_port(pjmedia_conf *conf, struct conf_port *cport,
|
|||
|
||||
cport->tx_buf_count -= cport->samples_per_frame;
|
||||
if (cport->tx_buf_count) {
|
||||
pjmedia_copy_samples(cport->tx_buf,
|
||||
pjmedia_move_samples(cport->tx_buf,
|
||||
cport->tx_buf + cport->samples_per_frame,
|
||||
cport->tx_buf_count);
|
||||
}
|
||||
|
@ -1715,8 +1789,8 @@ static pj_status_t get_frame(pjmedia_port *this_port,
|
|||
/* Adjust the RX level from this port
|
||||
* and calculate the average level at the same time.
|
||||
*/
|
||||
for (j=0; j<conf->samples_per_frame; ++j) {
|
||||
if (conf_port->rx_adj_level != NORMAL_LEVEL) {
|
||||
if (conf_port->rx_adj_level != NORMAL_LEVEL) {
|
||||
for (j=0; j<conf->samples_per_frame; ++j) {
|
||||
/* For the level adjustment, we need to store the sample to
|
||||
* a temporary 32bit integer value to avoid overflowing the
|
||||
* 16bit sample storage.
|
||||
|
@ -1736,10 +1810,13 @@ static pj_status_t get_frame(pjmedia_port *this_port,
|
|||
else if (itemp < MIN_LEVEL) itemp = MIN_LEVEL;
|
||||
|
||||
p_in[j] = (pj_int16_t) itemp;
|
||||
level += (p_in[j]>=0? p_in[j] : -p_in[j]);
|
||||
}
|
||||
|
||||
level += (p_in[j]>0? p_in[j] : -p_in[j]);
|
||||
}
|
||||
} else {
|
||||
for (j=0; j<conf->samples_per_frame; ++j) {
|
||||
level += (p_in[j]>=0? p_in[j] : -p_in[j]);
|
||||
}
|
||||
}
|
||||
|
||||
level /= conf->samples_per_frame;
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ SAMPLES = $(BINDIR)\confsample.exe \
|
|||
$(BINDIR)\sndtest.exe \
|
||||
$(BINDIR)\stateful_proxy.exe \
|
||||
$(BINDIR)\stateless_proxy.exe \
|
||||
$(BINDIR)\stereotest.exe \
|
||||
$(BINDIR)\streamutil.exe \
|
||||
$(BINDIR)\strerror.exe \
|
||||
$(BINDIR)\tonegen.exe
|
||||
|
|
|
@ -31,6 +31,7 @@ SAMPLES := confsample \
|
|||
sndtest \
|
||||
stateful_proxy \
|
||||
stateless_proxy \
|
||||
stereotest \
|
||||
streamutil \
|
||||
strerror \
|
||||
tonegen
|
||||
|
|
|
@ -178,6 +178,10 @@ SOURCE=..\src\samples\stateless_proxy.c
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\samples\stereotest.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\samples\streamutil.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
|
@ -175,6 +175,7 @@ static void usage(void)
|
|||
puts (" --dis-codec=name Disable codec (can be specified multiple times)");
|
||||
puts (" --clock-rate=N Override conference bridge clock rate");
|
||||
puts (" --snd-clock-rate=N Override sound device clock rate");
|
||||
puts (" --stereo Audio device and conference bridge opened in stereo mode");
|
||||
puts (" --null-audio Use NULL audio device");
|
||||
puts (" --play-file=file Register WAV file in conference bridge.");
|
||||
puts (" This can be specified multiple times.");
|
||||
|
@ -389,8 +390,8 @@ static pj_status_t parse_args(int argc, char *argv[],
|
|||
OPT_NAMESERVER, OPT_STUN_DOMAIN, OPT_STUN_SRV,
|
||||
OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE,
|
||||
OPT_AUTO_ANSWER, OPT_AUTO_HANGUP, OPT_AUTO_PLAY, OPT_AUTO_LOOP,
|
||||
OPT_AUTO_CONF, OPT_CLOCK_RATE, OPT_SND_CLOCK_RATE, OPT_USE_ICE,
|
||||
OPT_USE_SRTP, OPT_SRTP_SECURE,
|
||||
OPT_AUTO_CONF, OPT_CLOCK_RATE, OPT_SND_CLOCK_RATE, OPT_STEREO,
|
||||
OPT_USE_ICE, OPT_USE_SRTP, OPT_SRTP_SECURE,
|
||||
OPT_PLAY_FILE, OPT_PLAY_TONE, OPT_RTP_PORT, OPT_ADD_CODEC,
|
||||
OPT_ILBC_MODE, OPT_REC_FILE, OPT_AUTO_REC,
|
||||
OPT_COMPLEXITY, OPT_QUALITY, OPT_PTIME, OPT_NO_VAD,
|
||||
|
@ -413,6 +414,7 @@ static pj_status_t parse_args(int argc, char *argv[],
|
|||
{ "version", 0, 0, OPT_VERSION},
|
||||
{ "clock-rate", 1, 0, OPT_CLOCK_RATE},
|
||||
{ "snd-clock-rate", 1, 0, OPT_SND_CLOCK_RATE},
|
||||
{ "stereo", 0, 0, OPT_STEREO},
|
||||
{ "null-audio", 0, 0, OPT_NULL_AUDIO},
|
||||
{ "local-port", 1, 0, OPT_LOCAL_PORT},
|
||||
{ "ip-addr", 1, 0, OPT_IP_ADDR},
|
||||
|
@ -582,6 +584,10 @@ static pj_status_t parse_args(int argc, char *argv[],
|
|||
cfg->media_cfg.snd_clock_rate = lval;
|
||||
break;
|
||||
|
||||
case OPT_STEREO:
|
||||
cfg->media_cfg.channel_count = 2;
|
||||
break;
|
||||
|
||||
case OPT_LOCAL_PORT: /* local-port */
|
||||
lval = pj_strtoul(pj_cstr(&tmp, pj_optarg));
|
||||
if (lval < 0 || lval > 65535) {
|
||||
|
@ -1412,6 +1418,12 @@ static int write_settings(const struct app_config *config,
|
|||
pj_strcat2(&cfg, line);
|
||||
}
|
||||
|
||||
/* Stereo mode. */
|
||||
if (config->media_cfg.channel_count == 2) {
|
||||
pj_ansi_sprintf(line, "--stereo\n");
|
||||
pj_strcat2(&cfg, line);
|
||||
}
|
||||
|
||||
/* quality */
|
||||
if (config->media_cfg.quality != PJSUA_DEFAULT_CODEC_QUALITY) {
|
||||
pj_ansi_sprintf(line, "--quality %d\n",
|
||||
|
@ -2314,10 +2326,11 @@ static void conf_list(void)
|
|||
pj_ansi_sprintf(s, "#%d ", info.listeners[j]);
|
||||
pj_ansi_strcat(txlist, s);
|
||||
}
|
||||
printf("Port #%02d[%2dKHz/%dms] %20.*s transmitting to: %s\n",
|
||||
printf("Port #%02d[%2dKHz/%dms/%d] %20.*s transmitting to: %s\n",
|
||||
info.slot_id,
|
||||
info.clock_rate/1000,
|
||||
info.samples_per_frame * 1000 / info.clock_rate,
|
||||
info.channel_count,
|
||||
(int)info.name.slen,
|
||||
info.name.ptr,
|
||||
txlist);
|
||||
|
|
|
@ -3748,6 +3748,12 @@ struct pjsua_media_config
|
|||
*/
|
||||
unsigned snd_clock_rate;
|
||||
|
||||
/**
|
||||
* Channel count be applied when opening the sound device and
|
||||
* conference bridge.
|
||||
*/
|
||||
unsigned channel_count;
|
||||
|
||||
/**
|
||||
* Specify audio frame ptime. The value here will affect the
|
||||
* samples per frame of both the sound device and the conference
|
||||
|
|
|
@ -163,6 +163,7 @@ PJ_DEF(void) pjsua_media_config_default(pjsua_media_config *cfg)
|
|||
|
||||
cfg->clock_rate = PJSUA_DEFAULT_CLOCK_RATE;
|
||||
cfg->snd_clock_rate = 0;
|
||||
cfg->channel_count = 1;
|
||||
cfg->audio_frame_ptime = PJSUA_DEFAULT_AUDIO_FRAME_PTIME;
|
||||
cfg->max_media_ports = PJSUA_MAX_CONF_PORTS;
|
||||
cfg->has_ioqueue = PJ_TRUE;
|
||||
|
|
|
@ -169,7 +169,7 @@ pj_status_t pjsua_media_subsys_init(const pjsua_media_config *cfg)
|
|||
/* Save additional conference bridge parameters for future
|
||||
* reference.
|
||||
*/
|
||||
pjsua_var.mconf_cfg.channel_count = 1;
|
||||
pjsua_var.mconf_cfg.channel_count = pjsua_var.media_cfg.channel_count;
|
||||
pjsua_var.mconf_cfg.bits_per_sample = 16;
|
||||
pjsua_var.mconf_cfg.samples_per_frame = pjsua_var.media_cfg.clock_rate *
|
||||
pjsua_var.mconf_cfg.channel_count *
|
||||
|
@ -1834,8 +1834,10 @@ PJ_DEF(pj_status_t) pjsua_set_snd_dev( int capture_dev,
|
|||
fps = 1000 / pjsua_var.media_cfg.audio_frame_ptime;
|
||||
status = pjmedia_snd_port_create(pjsua_var.pool, capture_dev,
|
||||
playback_dev,
|
||||
clock_rates[i], 1,
|
||||
clock_rates[i]/fps,
|
||||
clock_rates[i],
|
||||
pjsua_var.media_cfg.channel_count,
|
||||
clock_rates[i]/fps *
|
||||
pjsua_var.media_cfg.channel_count,
|
||||
16, 0, &pjsua_var.snd_port);
|
||||
|
||||
if (status == PJ_SUCCESS) {
|
||||
|
|
Loading…
Reference in New Issue