Please help - wav_writer writing silence when switch to 1 conference bridge PER call (following pjsua-lib-perf FAQ)

ML
Michael Leonard
Tue, Oct 4, 2016 11:30 AM

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

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); }
BG
Bill Gardner
Tue, Oct 4, 2016 1:02 PM

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/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);
}


Visit our blog: http://blog.pjsip.org

pjsip mailing list
pjsip@lists.pjsip.org
http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org

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/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); > } > > > _______________________________________________ > Visit our blog: http://blog.pjsip.org > > pjsip mailing list > pjsip@lists.pjsip.org > http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org
ML
Michael Leonard
Tue, Oct 4, 2016 1:59 PM

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

On 4 October 2016 at 14:02, Bill Gardner billg@wavearts.com 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/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);
}


Visit our blog: http://blog.pjsip.org

pjsip mailing listpjsip@lists.pjsip.orghttp://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org


Visit our blog: http://blog.pjsip.org

pjsip mailing list
pjsip@lists.pjsip.org
http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org

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@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 On 4 October 2016 at 14:02, Bill Gardner <billg@wavearts.com> 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/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); > } > > > _______________________________________________ > Visit our blog: http://blog.pjsip.org > > pjsip mailing listpjsip@lists.pjsip.orghttp://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org > > > > _______________________________________________ > Visit our blog: http://blog.pjsip.org > > pjsip mailing list > pjsip@lists.pjsip.org > http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org > >
BG
Bill Gardner
Tue, Oct 4, 2016 3:25 PM

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

On 10/4/2016 9:59 AM, Michael Leonard wrote:

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@XXXXXX.pstn.twilio.com
mailto:sip%3A%2B447XXXXXXXX@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

On 4 October 2016 at 14:02, Bill Gardner <billg@wavearts.com
mailto:billg@wavearts.com> 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
 <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
 <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
 <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

 pjsip mailing list
 pjsip@lists.pjsip.org <mailto: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 pjsip@lists.pjsip.org
 <mailto: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
pjsip@lists.pjsip.org
http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org

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 On 10/4/2016 9:59 AM, Michael Leonard wrote: > 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@XXXXXX.pstn.twilio.com > <mailto:sip%3A%2B447XXXXXXXX@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 > > On 4 October 2016 at 14:02, Bill Gardner <billg@wavearts.com > <mailto:billg@wavearts.com>> 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 >> <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 >> <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 >> <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 >> >> pjsip mailing list >> pjsip@lists.pjsip.org <mailto: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 pjsip@lists.pjsip.org > <mailto: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 > pjsip@lists.pjsip.org > http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org