Discussion:
[pjsip] Please help - wav_writer writing silence when switch to 1 conference bridge PER call (following pjsua-lib-perf FAQ)
Michael Leonard
2016-10-04 11:30:53 UTC
Permalink
Hello everyone

Please help! My wav_writer is just writing silence (of the correct length)
when trying to use pjsua-lib with 1 conference bridge per call, as
explained in the FAQ here:
https://trac.pjsip.org/repos/wiki/FAQ#pjsua-lib-perf. Note that when I use
the default pjsua conference bridge everything works fine for me.

I've saved the code and a log file to a github public gist here:
https://gist.github.com/MikeLeonard/6b8b4986d6529ae751ebd2af5bf4d29f

I would *really* appreciate it if someone could look through
call_media_init function I've written (also pasted below) and tell me what
I'm doing wrong.

If it takes someone a lot of time I'd be happy to buy them a coffee (or
amazon voucher!) to say thank you.

Thanks very much in advance

Mike





*More information:*
..................................................................................................................................................
***I think I've ruled out problems with my setup*
- I'm trying to create a server that makes calls to a regular mobile or
landline from a server (ie no voip phone so no sound device), and records
the speech of the receiver to a wav file.

I'm running this on ubuntu, inside a docker container, on a macbook, and
am making an outbound call to a mobile number via a twilio sip trunk. I'm
also compiling this using C++ (because I need various C++ libraries for
what I have in mind once I get the basics working).

The above setup ALL works fine - I modified samples/simple_pjsua.c and got
a wav_writer and a wav_player working no problem with the default pjsua
conference bridge. So I'm pretty sure the problem is with how I've tried to
follow the pjsua-lib-perf FAQ.


***I can't see any issues in the log file, and I've confirmed the key 'on_'
callbacks all definitely run*
- The log file prints out the following - which to me looks like I've
connected the right ports, but I don't really understand this to be honest
I've just be copying examples:
09:59:05.565 APP .......Call 0 state=CALLING
09:59:05.572 wav_writer.c .......File writer 'testingtesting.wav'
created: samp.rate=16000, bufsize=4KB
09:59:05.572 conference.c .......Port 0 (Master/sound) transmitting to
port 1 (testingtesting.wav)
09:59:05.579 wav_player.c .......File player 'message.wav' created:
samp.rate=16000, ch=1, bufsize=4KB, filesize=56KB
09:59:05.579 conference.c .......Port 2 (message.wav) transmitting to
port 0 (Master/sound)

- I'm just trying one call at the moment - I haven't tried multiple calls
yet.

- I've confirmed that the key callbacks all run: on_call_state,
on_call_media_state,
on_stream_created and on_stream_destroyed

- I've added lots of "if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE,
"STATUS ERROR: ", status);}" into the code, but don't get any "STATUS
ERROR" messages in the log.


***A wav file is indeed written*
- ...it just contains silence. It seems to be silence of the length of the
call however.

I've also tried looping back the audio, and playing a wav file to the
receiver, but I just get silence. These all work in my basic
samples/simple_pjsua.c version with the default pjsua conference bridge.


..................................................................................................................................................
*Key piece of code... see github public gist for full code + log file *
https://gist.github.com/MikeLeonard/6b8b4986d6529ae751ebd2af5bf4d29f

struct call_data {
pj_pool_t *pool;
pjmedia_conf *conf;
pjmedia_port *cport;
pjmedia_port *null;
pjmedia_port *writer;
pjmedia_port *player;
pjmedia_master_port *m;
unsigned int call_slot;
unsigned int writer_slot;
unsigned int player_slot;
};

static void call_media_init(pjsua_call_id call_id){
log_message("RUNNING... call_media_init\n");

pj_pool_t *pool;
struct call_data *cd;
pj_status_t status;

pool = pjsua_pool_create("mycall", 4000, 4000);
cd = PJ_POOL_ZALLOC_T(pool, struct call_data);
cd->pool = pool;

pjsua_call_set_user_data(call_id, (void*)cd);

pjsua_media_config media_cfg;
pjsua_media_config_default(&media_cfg);
status = pjmedia_conf_create(
cd->pool,
media_cfg.max_media_ports, //max media ports
media_cfg.clock_rate,
media_cfg.channel_count,
media_cfg.clock_rate * media_cfg.channel_count *
media_cfg.audio_frame_ptime / 1000, //mconf_cfg.samples_per_frame,
16, //mconf_cfg.bits_per_sample,
PJMEDIA_CONF_NO_DEVICE | PJMEDIA_CONF_NO_MIC, //options
&cd->conf //pointer to conference bridge instance
);
if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE, "STATUS ERROR: ",
status);}
cd->cport = pjmedia_conf_get_master_port(cd->conf);
status = pjmedia_null_port_create(
cd->pool,
media_cfg.clock_rate,
media_cfg.channel_count,
media_cfg.clock_rate * media_cfg.channel_count *
media_cfg.audio_frame_ptime / 1000, //mconf_cfg.samples_per_frame,
16, //mconf_cfg.bits_per_sample,
&cd->null);
if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE, "STATUS ERROR: ",
status);}
status = pjmedia_master_port_create(cd->pool, cd->null, cd->cport, 0,
&cd->m);
if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE, "STATUS ERROR: ",
status);}
status = pjmedia_master_port_start(cd->m);
if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE, "STATUS ERROR: ",
status);}
//todo(mike) handle errors, see pjsua_aud.c





/* wav writer */
status = pjmedia_wav_writer_port_create(
cd->pool,
"testingtesting.wav", //path
media_cfg.clock_rate,
media_cfg.channel_count,
media_cfg.clock_rate * media_cfg.channel_count *
media_cfg.audio_frame_ptime / 1000, //mconf_cfg.samples_per_frame,
16, //mconf_cfg.bits_per_sample,
0, //options
0, //buf_size defaults to 4kb if set to 0
&cd->writer //yes this should be a pjmedia_port **
);
if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE, "STATUS ERROR: ",
status);}
status = pjmedia_conf_add_port(cd->conf, cd->pool, cd->writer, NULL,
&cd->writer_slot);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "STATUS ERROR: ", status);
pjmedia_port_destroy(cd->writer);
}

pjmedia_conf_connect_port(cd->conf, cd->call_slot, cd->writer_slot, 0);





/* wav player */
status = pjmedia_wav_player_port_create(
cd->pool,
"message.wav",
media_cfg.audio_frame_ptime,
0,
0,
&cd->player //yes this should be a pjmedia_port **
);
if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE, "STATUS ERROR: ",
status);}

status = pjmedia_conf_add_port(cd->conf, cd->pool, cd->player, NULL,
&cd->player_slot);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "STATUS ERROR: ", status);
pjmedia_port_destroy(cd->player);
}

pjmedia_conf_connect_port(cd->conf, cd->player_slot, cd->call_slot, 0);



//uncomment to loop back remote audio (also doesn't work)
//pjmedia_conf_connect_port(cd->conf, cd->call_slot, cd->call_slot, 0);
}
Bill Gardner
2016-10-04 13:02:30 UTC
Permalink
Hi Mike,

I don't see any code that connects the stream port (codec, jitter, RTP,
etc) to your conference bridge at call_slot. Is this done elsewhere?

Regards,

Bill
Post by Michael Leonard
Hello everyone
Please help! My wav_writer is just writing silence (of the correct
length) when trying to use pjsua-lib with 1 conference bridge per
https://trac.pjsip.org/repos/wiki/FAQ#pjsua-lib-perf. Note that when I
use the default pjsua conference bridge everything works fine for me.
https://gist.github.com/MikeLeonard/6b8b4986d6529ae751ebd2af5bf4d29f
I would *really* appreciate it if someone could look through
call_media_init function I've written (also pasted below) and tell me
what I'm doing wrong.
If it takes someone a lot of time I'd be happy to buy them a coffee
(or amazon voucher!) to say thank you.
Thanks very much in advance
Mike
*More information:*
..................................................................................................................................................
***I think I've ruled out problems with my setup*
- I'm trying to create a server that makes calls to a regular mobile
or landline from a server (ie no voip phone so no sound device), and
records the speech of the receiver to a wav file.
I'm running this on ubuntu, inside a docker container, on a macbook,
and am making an outbound call to a mobile number via a twilio sip
trunk. I'm also compiling this using C++ (because I need various C++
libraries for what I have in mind once I get the basics working).
The above setup ALL works fine - I modified samples/simple_pjsua.c and
got a wav_writer and a wav_player working no problem with the default
pjsua conference bridge. So I'm pretty sure the problem is with how
I've tried to follow the pjsua-lib-perf FAQ.
***I can't see any issues in the log file, and I've confirmed the key
'on_' callbacks all definitely run*
- The log file prints out the following - which to me looks like I've
connected the right ports, but I don't really understand this to be
09:59:05.565 APP .......Call 0 state=CALLING
09:59:05.572 wav_writer.c .......File writer 'testingtesting.wav'
created: samp.rate=16000, bufsize=4KB
09:59:05.572 conference.c .......Port 0 (Master/sound) transmitting
to port 1 (testingtesting.wav)
samp.rate=16000, ch=1, bufsize=4KB, filesize=56KB
09:59:05.579 conference.c .......Port 2 (message.wav) transmitting
to port 0 (Master/sound)
- I'm just trying one call at the moment - I haven't tried multiple
calls yet.
- I've confirmed that the key callbacks all run: on_call_state,
on_call_media_state, on_stream_created and on_stream_destroyed
- I've added lots of "if (status != PJ_SUCCESS)
{pjsua_perror(THIS_FILE, "STATUS ERROR: ", status);}" into the code,
but don't get any "STATUS ERROR" messages in the log.
***A wav file is indeed written*
- ...it just contains silence. It seems to be silence of the length of
the call however.
I've also tried looping back the audio, and playing a wav file to the
receiver, but I just get silence. These all work in my basic
samples/simple_pjsua.c version with the default pjsua conference bridge.
..................................................................................................................................................
*Key piece of code... see github public gist for full code + log file
*https://gist.github.com/MikeLeonard/6b8b4986d6529ae751ebd2af5bf4d29f
struct call_data {
pj_pool_t *pool;
pjmedia_conf *conf;
pjmedia_port *cport;
pjmedia_port *null;
pjmedia_port *writer;
pjmedia_port *player;
pjmedia_master_port *m;
unsigned int call_slot;
unsigned int writer_slot;
unsigned int player_slot;
};
static void call_media_init(pjsua_call_id call_id){
log_message("RUNNING... call_media_init\n");
pj_pool_t *pool;
struct call_data *cd;
pj_status_t status;
pool = pjsua_pool_create("mycall", 4000, 4000);
cd = PJ_POOL_ZALLOC_T(pool, struct call_data);
cd->pool = pool;
pjsua_call_set_user_data(call_id, (void*)cd);
pjsua_media_config media_cfg;
pjsua_media_config_default(&media_cfg);
status = pjmedia_conf_create(
cd->pool,
media_cfg.max_media_ports, //max media ports
media_cfg.clock_rate,
media_cfg.channel_count,
media_cfg.clock_rate * media_cfg.channel_count *
media_cfg.audio_frame_ptime / 1000, //mconf_cfg.samples_per_frame,
16, //mconf_cfg.bits_per_sample,
PJMEDIA_CONF_NO_DEVICE | PJMEDIA_CONF_NO_MIC, //options
&cd->conf //pointer to conference bridge instance
);
if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE, "STATUS ERROR: ",
status);}
cd->cport = pjmedia_conf_get_master_port(cd->conf);
status = pjmedia_null_port_create(
cd->pool,
media_cfg.clock_rate,
media_cfg.channel_count,
media_cfg.clock_rate * media_cfg.channel_count *
media_cfg.audio_frame_ptime / 1000, //mconf_cfg.samples_per_frame,
16, //mconf_cfg.bits_per_sample,
&cd->null);
if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE, "STATUS ERROR: ",
status);}
status = pjmedia_master_port_create(cd->pool, cd->null, cd->cport, 0,
&cd->m);
if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE, "STATUS ERROR: ",
status);}
status = pjmedia_master_port_start(cd->m);
if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE, "STATUS ERROR: ",
status);}
//todo(mike) handle errors, see pjsua_aud.c
/* wav writer */
status = pjmedia_wav_writer_port_create(
cd->pool,
"testingtesting.wav", //path
media_cfg.clock_rate,
media_cfg.channel_count,
media_cfg.clock_rate * media_cfg.channel_count *
media_cfg.audio_frame_ptime / 1000, //mconf_cfg.samples_per_frame,
16, //mconf_cfg.bits_per_sample,
0, //options
0, //buf_size defaults to 4kb if set to 0
&cd->writer //yes this should be a pjmedia_port **
);
if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE, "STATUS ERROR: ",
status);}
status = pjmedia_conf_add_port(cd->conf, cd->pool, cd->writer, NULL,
&cd->writer_slot);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "STATUS ERROR: ", status);
pjmedia_port_destroy(cd->writer);
}
pjmedia_conf_connect_port(cd->conf, cd->call_slot, cd->writer_slot, 0);
/* wav player */
status = pjmedia_wav_player_port_create(
cd->pool,
"message.wav",
media_cfg.audio_frame_ptime,
0,
0,
&cd->player //yes this should be a pjmedia_port **
);
", status);}
status = pjmedia_conf_add_port(cd->conf, cd->pool, cd->player, NULL,
&cd->player_slot);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "STATUS ERROR: ", status);
pjmedia_port_destroy(cd->player);
}
pjmedia_conf_connect_port(cd->conf, cd->player_slot, cd->call_slot, 0);
//uncomment to loop back remote audio (also doesn't work)
//pjmedia_conf_connect_port(cd->conf, cd->call_slot, cd->call_slot, 0);
}
_______________________________________________
Visit our blog: http://blog.pjsip.org
pjsip mailing list
http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org
Michael Leonard
2016-10-04 13:59:31 UTC
Permalink
Hi Bill. Thanks for the quick response.

I'm not sure if you saw it: my entire code is in one file called
whole_app.c which is included in the gist (scroll to the bottom to see the
file: https://gist.github.com/MikeLeonard/6b8b4986d6529ae751ebd2af5bf4d29f)

I'm using pjmedia_conf_add_port inside of on_stream_created, which (I
think) adds the stream port (p_port) to the conference bridge (cd->conf)
and saves the slot number into &cd->call_slot.

static void on_stream_created(pjsua_call_id call_id,
pjmedia_stream *strm,
unsigned stream_idx,
pjmedia_port **p_port){
log_message("RUNNING... on_stream_created\n");
struct call_data *cd;
cd = (struct call_data*) pjsua_call_get_user_data(call_id);
if (!cd)
return;
pjmedia_conf_add_port(cd->conf, cd->pool, *p_port, NULL, &cd->call_slot);
}

Elsewhere in call_media_init which is called when the call state is
'CALLING', I'm running the following:
pjmedia_conf_connect_port(cd->conf, cd->call_slot, cd->writer_slot, 0);
//flow audio from call to writer
pjmedia_conf_connect_port(cd->conf, cd->player_slot, cd->call_slot, 0);
//flow wav reader audio to call
... to connect the call_slot to the writer_slot and the player_slot.

Do I need to make another connection? Perhaps to connect the master port
and/or the null port to one or more of these? I'm afraid that I haven't
been able to really get to grips with these two ports, I don't really
understand what they are for. (I've just read that I need them when there's
no sound device in order to drive the get_frame and put_frame callbacks -
plus the FAQ uses them).

Thanks again for the help

Mike

.............................................................................................................................................................................
Also, I've just realised a potential problem: on_stream_created is called
AFTER the call state is 'CALLING' (which calls my call_media_init
function)... so I guess that call_media_init is trying to connect things to
call_slot BEFORE call_slot is set by pjmedia_conf_add_port inside of
on_stream_created. I couldn't really tell from the FAQ exactly where I
should put these functions - do you know where I've gone wrong?

UPDATE: Nope. I've just tried changing it so that call_media_init is called
when the MEDIA state is 'ACTIVE' instead of when the call state is CALLING,
so that call_media_init is called after on_stream_created (which
calls pjmedia_conf_add_port(cd->conf, cd->pool, *p_port, NULL,
&cd->call_slot)). However I get the same silence.

Anyway, the cod has some print commands which show the order things run in,
in case that's helpful to you:

/myapp sip:+***@XXXXXX.pstn.twilio.com >> log.txt
WARNING: no real random source present!
RUNNING... on_call_state
Call state is CALLING.
RUNNING... call_media_init
RUNNING... on_call_state
RUNNING... on_stream_created
RUNNING... on_call_media_state
Media state is ACTIVE.
RUNNING... on_call_state
RUNNING... on_call_state
RUNNING... on_call_state
Call state is CONFIRMED.
RUNNING... on_call_state
Call state is DISCONNECTED.
RUNNING... call_media_deinit
Called call_media_deinit.
RUNNING... on_stream_destroyed
^C


Thanks

Mike
Post by Bill Gardner
Hi Mike,
I don't see any code that connects the stream port (codec, jitter, RTP,
etc) to your conference bridge at call_slot. Is this done elsewhere?
Regards,
Bill
Hello everyone
Please help! My wav_writer is just writing silence (of the correct length)
when trying to use pjsua-lib with 1 conference bridge per call, as
explained in the FAQ here: https://trac.pjsip.org/repos/
wiki/FAQ#pjsua-lib-perf. Note that when I use the default pjsua
conference bridge everything works fine for me.
https://gist.github.com/MikeLeonard/6b8b4986d6529ae751ebd2af5bf4d29f
I would *really* appreciate it if someone could look through
call_media_init function I've written (also pasted below) and tell me what
I'm doing wrong.
If it takes someone a lot of time I'd be happy to buy them a coffee (or
amazon voucher!) to say thank you.
Thanks very much in advance
Mike
*More information:*
............................................................
............................................................
..........................
***I think I've ruled out problems with my setup*
- I'm trying to create a server that makes calls to a regular mobile or
landline from a server (ie no voip phone so no sound device), and records
the speech of the receiver to a wav file.
I'm running this on ubuntu, inside a docker container, on a macbook, and
am making an outbound call to a mobile number via a twilio sip trunk. I'm
also compiling this using C++ (because I need various C++ libraries for
what I have in mind once I get the basics working).
The above setup ALL works fine - I modified samples/simple_pjsua.c and got
a wav_writer and a wav_player working no problem with the default pjsua
conference bridge. So I'm pretty sure the problem is with how I've tried to
follow the pjsua-lib-perf FAQ.
***I can't see any issues in the log file, and I've confirmed the key
'on_' callbacks all definitely run*
- The log file prints out the following - which to me looks like I've
connected the right ports, but I don't really understand this to be honest
09:59:05.565 APP .......Call 0 state=CALLING
09:59:05.572 wav_writer.c .......File writer 'testingtesting.wav'
created: samp.rate=16000, bufsize=4KB
09:59:05.572 conference.c .......Port 0 (Master/sound) transmitting to
port 1 (testingtesting.wav)
samp.rate=16000, ch=1, bufsize=4KB, filesize=56KB
09:59:05.579 conference.c .......Port 2 (message.wav) transmitting to
port 0 (Master/sound)
- I'm just trying one call at the moment - I haven't tried multiple calls
yet.
- I've confirmed that the key callbacks all run: on_call_state, on_call_media_state,
on_stream_created and on_stream_destroyed
- I've added lots of "if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE,
"STATUS ERROR: ", status);}" into the code, but don't get any "STATUS
ERROR" messages in the log.
***A wav file is indeed written*
- ...it just contains silence. It seems to be silence of the length of the
call however.
I've also tried looping back the audio, and playing a wav file to the
receiver, but I just get silence. These all work in my basic
samples/simple_pjsua.c version with the default pjsua conference bridge.
............................................................
............................................................
..........................
*Key piece of code... see github public gist for full code + log file *
https://gist.github.com/MikeLeonard/6b8b4986d6529ae751ebd2af5bf4d29f
struct call_data {
pj_pool_t *pool;
pjmedia_conf *conf;
pjmedia_port *cport;
pjmedia_port *null;
pjmedia_port *writer;
pjmedia_port *player;
pjmedia_master_port *m;
unsigned int call_slot;
unsigned int writer_slot;
unsigned int player_slot;
};
static void call_media_init(pjsua_call_id call_id){
log_message("RUNNING... call_media_init\n");
pj_pool_t *pool;
struct call_data *cd;
pj_status_t status;
pool = pjsua_pool_create("mycall", 4000, 4000);
cd = PJ_POOL_ZALLOC_T(pool, struct call_data);
cd->pool = pool;
pjsua_call_set_user_data(call_id, (void*)cd);
pjsua_media_config media_cfg;
pjsua_media_config_default(&media_cfg);
status = pjmedia_conf_create(
cd->pool,
media_cfg.max_media_ports, //max media ports
media_cfg.clock_rate,
media_cfg.channel_count,
media_cfg.clock_rate * media_cfg.channel_count *
media_cfg.audio_frame_ptime / 1000, //mconf_cfg.samples_per_frame,
16, //mconf_cfg.bits_per_sample,
PJMEDIA_CONF_NO_DEVICE | PJMEDIA_CONF_NO_MIC, //options
&cd->conf //pointer to conference bridge instance
);
if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE, "STATUS ERROR: ",
status);}
cd->cport = pjmedia_conf_get_master_port(cd->conf);
status = pjmedia_null_port_create(
cd->pool,
media_cfg.clock_rate,
media_cfg.channel_count,
media_cfg.clock_rate * media_cfg.channel_count *
media_cfg.audio_frame_ptime / 1000, //mconf_cfg.samples_per_frame,
16, //mconf_cfg.bits_per_sample,
&cd->null);
if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE, "STATUS ERROR: ",
status);}
status = pjmedia_master_port_create(cd->pool, cd->null, cd->cport, 0,
&cd->m);
if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE, "STATUS ERROR: ",
status);}
status = pjmedia_master_port_start(cd->m);
if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE, "STATUS ERROR: ",
status);}
//todo(mike) handle errors, see pjsua_aud.c
/* wav writer */
status = pjmedia_wav_writer_port_create(
cd->pool,
"testingtesting.wav", //path
media_cfg.clock_rate,
media_cfg.channel_count,
media_cfg.clock_rate * media_cfg.channel_count *
media_cfg.audio_frame_ptime / 1000, //mconf_cfg.samples_per_frame,
16, //mconf_cfg.bits_per_sample,
0, //options
0, //buf_size defaults to 4kb if set to 0
&cd->writer //yes this should be a pjmedia_port **
);
if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE, "STATUS ERROR: ",
status);}
status = pjmedia_conf_add_port(cd->conf, cd->pool, cd->writer, NULL,
&cd->writer_slot);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "STATUS ERROR: ", status);
pjmedia_port_destroy(cd->writer);
}
pjmedia_conf_connect_port(cd->conf, cd->call_slot, cd->writer_slot, 0);
/* wav player */
status = pjmedia_wav_player_port_create(
cd->pool,
"message.wav",
media_cfg.audio_frame_ptime,
0,
0,
&cd->player //yes this should be a pjmedia_port **
);
if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE, "STATUS ERROR: ",
status);}
status = pjmedia_conf_add_port(cd->conf, cd->pool, cd->player, NULL,
&cd->player_slot);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "STATUS ERROR: ", status);
pjmedia_port_destroy(cd->player);
}
pjmedia_conf_connect_port(cd->conf, cd->player_slot, cd->call_slot, 0);
//uncomment to loop back remote audio (also doesn't work)
//pjmedia_conf_connect_port(cd->conf, cd->call_slot, cd->call_slot, 0);
}
_______________________________________________
Visit our blog: http://blog.pjsip.org
_______________________________________________
Visit our blog: http://blog.pjsip.org
pjsip mailing list
http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org
Bill Gardner
2016-10-04 15:25:59 UTC
Permalink
Hi Mike,

Yes I noticed the github link but didn't dig that far. :-)

Null port and master port are needed to drive the conference bridge and
all media flow but I forget the details. I recall using a null sound
device connected to the bridge master port, not sure if this paradigm
has changed. Given the WAV file is created and has the right amount of
silence, then it seems that media is flowing, so that's good. I'd
consider doing the port connections when the media state goes active,
instead of when call state is "CALLING" which is premature. Seems you
already figured that out. The empty WAV would be explained by connecting
it to the wrong port or connecting them the wrong way (check those
connect calls for source and dest).

I assume the called device is not getting any playback audio either?

You might learn something by enabling the logging in the conference
bridge. I think you have to change a macro and it will generate lots of
log info per packet. Not sure what else to suggest.

Regards,

Bill
Post by Michael Leonard
Hi Bill. Thanks for the quick response.
I'm not sure if you saw it: my entire code is in one file called
whole_app.c which is included in the gist (scroll to the bottom to see
https://gist.github.com/MikeLeonard/6b8b4986d6529ae751ebd2af5bf4d29f)
I'm using pjmedia_conf_add_port inside of on_stream_created, which (I
think) adds the stream port (p_port) to the conference bridge
(cd->conf) and saves the slot number into &cd->call_slot.
static void on_stream_created(pjsua_call_id call_id,
pjmedia_stream *strm,
unsigned stream_idx,
pjmedia_port **p_port){
log_message("RUNNING... on_stream_created\n");
struct call_data *cd;
cd = (struct call_data*) pjsua_call_get_user_data(call_id);
if (!cd)
return;
pjmedia_conf_add_port(cd->conf, cd->pool, *p_port, NULL, &cd->call_slot);
}
Elsewhere in call_media_init which is called when the call state is
pjmedia_conf_connect_port(cd->conf, cd->call_slot, cd->writer_slot,
0); //flow audio from call to writer
pjmedia_conf_connect_port(cd->conf, cd->player_slot, cd->call_slot,
0); //flow wav reader audio to call
... to connect the call_slot to the writer_slot and the player_slot.
Do I need to make another connection? Perhaps to connect the master
port and/or the null port to one or more of these? I'm afraid that I
haven't been able to really get to grips with these two ports, I don't
really understand what they are for. (I've just read that I need them
when there's no sound device in order to drive the get_frame and
put_frame callbacks - plus the FAQ uses them).
Thanks again for the help
Mike
.............................................................................................................................................................................
Also, I've just realised a potential problem: on_stream_created is
called AFTER the call state is 'CALLING' (which calls
my call_media_init function)... so I guess that call_media_init is
trying to connect things to call_slot BEFORE call_slot is set by
pjmedia_conf_add_port inside of on_stream_created. I couldn't really
tell from the FAQ exactly where I should put these functions - do you
know where I've gone wrong?
UPDATE: Nope. I've just tried changing it so that call_media_init is
called when the MEDIA state is 'ACTIVE' instead of when the call state
is CALLING, so that call_media_init is called after on_stream_created
(which calls pjmedia_conf_add_port(cd->conf, cd->pool, *p_port, NULL,
&cd->call_slot)). However I get the same silence.
Anyway, the cod has some print commands which show the order things
WARNING: no real random source present!
RUNNING... on_call_state
Call state is CALLING.
RUNNING... call_media_init
RUNNING... on_call_state
RUNNING... on_stream_created
RUNNING... on_call_media_state
Media state is ACTIVE.
RUNNING... on_call_state
RUNNING... on_call_state
RUNNING... on_call_state
Call state is CONFIRMED.
RUNNING... on_call_state
Call state is DISCONNECTED.
RUNNING... call_media_deinit
Called call_media_deinit.
RUNNING... on_stream_destroyed
^C
Thanks
Mike
Hi Mike,
I don't see any code that connects the stream port (codec, jitter,
RTP, etc) to your conference bridge at call_slot. Is this done
elsewhere?
Regards,
Bill
Post by Michael Leonard
Hello everyone
Please help! My wav_writer is just writing silence (of the
correct length) when trying to use pjsua-lib with 1 conference
https://trac.pjsip.org/repos/wiki/FAQ#pjsua-lib-perf
<https://trac.pjsip.org/repos/wiki/FAQ#pjsua-lib-perf>. Note that
when I use the default pjsua conference bridge everything works
fine for me.
https://gist.github.com/MikeLeonard/6b8b4986d6529ae751ebd2af5bf4d29f
<https://gist.github.com/MikeLeonard/6b8b4986d6529ae751ebd2af5bf4d29f>
I would *really* appreciate it if someone could look through
call_media_init function I've written (also pasted below) and
tell me what I'm doing wrong.
If it takes someone a lot of time I'd be happy to buy them a
coffee (or amazon voucher!) to say thank you.
Thanks very much in advance
Mike
*More information:*
..................................................................................................................................................
***I think I've ruled out problems with my setup*
- I'm trying to create a server that makes calls to a regular
mobile or landline from a server (ie no voip phone so no sound
device), and records the speech of the receiver to a wav file.
I'm running this on ubuntu, inside a docker container, on a
macbook, and am making an outbound call to a mobile number via a
twilio sip trunk. I'm also compiling this using C++ (because I
need various C++ libraries for what I have in mind once I get the
basics working).
The above setup ALL works fine - I modified
samples/simple_pjsua.c and got a wav_writer and a wav_player
working no problem with the default pjsua conference bridge. So
I'm pretty sure the problem is with how I've tried to follow the
pjsua-lib-perf FAQ.
***I can't see any issues in the log file, and I've confirmed the
key 'on_' callbacks all definitely run*
- The log file prints out the following - which to me looks like
I've connected the right ports, but I don't really understand
09:59:05.565 APP .......Call 0 state=CALLING
09:59:05.572 wav_writer.c .......File writer
'testingtesting.wav' created: samp.rate=16000, bufsize=4KB
09:59:05.572 conference.c .......Port 0 (Master/sound)
transmitting to port 1 (testingtesting.wav)
09:59:05.579 wav_player.c .......File player 'message.wav'
created: samp.rate=16000, ch=1, bufsize=4KB, filesize=56KB
09:59:05.579 conference.c .......Port 2 (message.wav)
transmitting to port 0 (Master/sound)
- I'm just trying one call at the moment - I haven't tried
multiple calls yet.
- I've confirmed that the key callbacks all run: on_call_state,
on_call_media_state, on_stream_created and on_stream_destroyed
- I've added lots of "if (status != PJ_SUCCESS)
{pjsua_perror(THIS_FILE, "STATUS ERROR: ", status);}" into the
code, but don't get any "STATUS ERROR" messages in the log.
***A wav file is indeed written*
- ...it just contains silence. It seems to be silence of the
length of the call however.
I've also tried looping back the audio, and playing a wav file to
the receiver, but I just get silence. These all work in my basic
samples/simple_pjsua.c version with the default pjsua conference bridge.
..................................................................................................................................................
*Key piece of code... see github public gist for full code + log file
*https://gist.github.com/MikeLeonard/6b8b4986d6529ae751ebd2af5bf4d29f
<https://gist.github.com/MikeLeonard/6b8b4986d6529ae751ebd2af5bf4d29f>
struct call_data {
pj_pool_t *pool;
pjmedia_conf *conf;
pjmedia_port *cport;
pjmedia_port *null;
pjmedia_port *writer;
pjmedia_port *player;
pjmedia_master_port *m;
unsigned int call_slot;
unsigned int writer_slot;
unsigned int player_slot;
};
static void call_media_init(pjsua_call_id call_id){
log_message("RUNNING... call_media_init\n");
pj_pool_t *pool;
struct call_data *cd;
pj_status_t status;
pool = pjsua_pool_create("mycall", 4000, 4000);
cd = PJ_POOL_ZALLOC_T(pool, struct call_data);
cd->pool = pool;
pjsua_call_set_user_data(call_id, (void*)cd);
pjsua_media_config media_cfg;
pjsua_media_config_default(&media_cfg);
status = pjmedia_conf_create(
cd->pool,
media_cfg.max_media_ports, //max media ports
media_cfg.clock_rate,
media_cfg.channel_count,
media_cfg.clock_rate * media_cfg.channel_count *
media_cfg.audio_frame_ptime / 1000, //mconf_cfg.samples_per_frame,
16, //mconf_cfg.bits_per_sample,
PJMEDIA_CONF_NO_DEVICE | PJMEDIA_CONF_NO_MIC, //options
&cd->conf //pointer to conference bridge instance
);
", status);}
cd->cport = pjmedia_conf_get_master_port(cd->conf);
status = pjmedia_null_port_create(
cd->pool,
media_cfg.clock_rate,
media_cfg.channel_count,
media_cfg.clock_rate * media_cfg.channel_count *
media_cfg.audio_frame_ptime / 1000, //mconf_cfg.samples_per_frame,
16, //mconf_cfg.bits_per_sample,
&cd->null);
", status);}
status = pjmedia_master_port_create(cd->pool, cd->null,
cd->cport, 0, &cd->m);
", status);}
status = pjmedia_master_port_start(cd->m);
", status);}
//todo(mike) handle errors, see pjsua_aud.c
/* wav writer */
status = pjmedia_wav_writer_port_create(
cd->pool,
"testingtesting.wav", //path
media_cfg.clock_rate,
media_cfg.channel_count,
media_cfg.clock_rate * media_cfg.channel_count *
media_cfg.audio_frame_ptime / 1000, //mconf_cfg.samples_per_frame,
16, //mconf_cfg.bits_per_sample,
0, //options
0, //buf_size defaults to 4kb if set to 0
&cd->writer //yes this should be a pjmedia_port **
);
", status);}
status = pjmedia_conf_add_port(cd->conf, cd->pool, cd->writer,
NULL, &cd->writer_slot);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "STATUS ERROR: ", status);
pjmedia_port_destroy(cd->writer);
}
pjmedia_conf_connect_port(cd->conf, cd->call_slot,
cd->writer_slot, 0);
/* wav player */
status = pjmedia_wav_player_port_create(
cd->pool,
"message.wav",
media_cfg.audio_frame_ptime,
0,
0,
&cd->player //yes this should be a pjmedia_port **
);
if (status != PJ_SUCCESS) {pjsua_perror(THIS_FILE, "STATUS
ERROR: ", status);}
status = pjmedia_conf_add_port(cd->conf, cd->pool, cd->player,
NULL, &cd->player_slot);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "STATUS ERROR: ", status);
pjmedia_port_destroy(cd->player);
}
pjmedia_conf_connect_port(cd->conf, cd->player_slot,
cd->call_slot, 0);
//uncomment to loop back remote audio (also doesn't work)
//pjmedia_conf_connect_port(cd->conf, cd->call_slot,
cd->call_slot, 0);
}
_______________________________________________
Visit our blog:http://blog.pjsip.org
pjsip mailing list
http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org
<http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org>
http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org
<http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org>
_______________________________________________
Visit our blog: http://blog.pjsip.org
pjsip mailing list
http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org
Loading...