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:+447XXXXXXXX@xxxxxxxxxxxxxxxxxxxxxx >> 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
On 4 October 2016 at 14:02, Bill Gardner <billg@xxxxxxxxxxxx> wrote:
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
On 10/4/2016 7:30 AM, Michael Leonard wrote:
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/ 6b8b4986d6529ae751ebd2af5bf4d2 9f 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=CALLING09:59:05.572 wav_writer.c .......File writer 'testingtesting.wav' created: samp.rate=16000, bufsize=4KB09: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=56KB09: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/ 6b8b4986d6529ae751ebd2af5bf4d2 9f
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 portsmedia_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", //pathmedia_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, //options0, //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 pjsip mailing list pjsip@xxxxxxxxxxxxxxx http://lists.pjsip.org/ mailman/listinfo/pjsip_lists. pjsip.org
_______________________________________________
Visit our blog: http://blog.pjsip.org
pjsip mailing list
pjsip@xxxxxxxxxxxxxxx
http://lists.pjsip.org/mailman/listinfo/pjsip_lists. pjsip.org
_______________________________________________ Visit our blog: http://blog.pjsip.org pjsip mailing list pjsip@xxxxxxxxxxxxxxx http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org