audio frames filled with 0 in port added to conference bridge (modified simple_pjsua application, C, Linux)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Dear all,
I use a Linux platform and my aim was to modify simple_pjsua program to 
check if I have understood pj_port behaviour, but my modified program 
doesn't work as I expected, so I ask here if anyone could help me in 
understanding my mistakes, also thinking that this could help other 
peoples to understand pj_port behaviour.

As you can see by reading my code at the end of this email, I have 
substituted audio devices with "null sound device" (masterport with a 
null upstream and downstream connected to port0 of conference bridge), 
thinking it will act as a data-pump for added ports connected to port 0 
of conference bridge, by delivering a proper clock to force data flow.

Then I have created my bidirectional ussd_port, with callbacks needed to 
provide frame flow. Both callbacks have an instruction to log a single 
sample from frame buffer (thinking it should change from a sound frame 
to another), frame buffer size and an index (P, G) to track which 
callback is currently running.

I have finally added my port to a free slot of conference bridge. Than I 
have connected this slot to port 0 in both direction.

As you can see I have also bridged (though a global buffer copied by 
callbacks) audio data flow coming from remote user agent to send 
received frames back to remote user agent, thinking I would be able to 
hear the echo of my voice in remote user agent.

When I start this program, it seems to correctly establish a sip 
communication with remote user-agent (Linphone rings and shows 
communication is on). Callbacks logs shows that my ussd_port is 
correctly clocked, since there is a trace of callbacks activity, as I 
expected.

....
09:30:08.374 myapp  P size:640 b:0
09:30:08.374 myapp  G size:640 b:0
09:30:08.393 myapp  P size:640 b:0
09:30:08.394 myapp  G size:640 b:0
....

But received audio data frames are filled only with zeros, even when I 
speak in remote user-agent microphone. I can see microphone audio bar 
movement in Linphone, but I don't see any movements in Linphone's 
speaker bar and I don't hear any sound either, in remote user agent!

I have also tried to force a noise in remote user-agent by modified 
outgoing frames sent by put_frame callback, but still I heard nothing in 
remote user-agent speaker, nor its speaker sound bar seems to move.

To see if communication was correctly established, I made an attempt by 
adding dmft tone capture callback in my program, and I can see that my 
program correctly capture key pressed in remote user-agent

What is wrong in my code? Why audio frames are always zeroed?

For shortness, I haven't reported all simple_pjsua.c program code, but 
just a bit of it to show where I have inserted my code I have also 
reported port creation function code and get/put callback code. To write 
my code I have been inspired by sinewave.c example. From sinewave.c I 
have just copied but not fully understood lines marked with "///".

Thank you in advance to anyone that will give me any suggestion!
Best regards from Italy!
Silvio

------------------------------
PS: Here is my C code:
------------------------------

int main(int argc, char *argv[])
{
  .......
  .......

  /* Init pjsua */
  {
     pjsua_config cfg;
     pjsua_logging_config log_cfg;
     pjsua_config_default(&cfg);
     cfg.cb.on_incoming_call = &on_incoming_call;
     cfg.cb.on_call_media_state = &on_call_media_state;
     cfg.cb.on_call_state = &on_call_state;
     pjsua_logging_config_default(&log_cfg);
     log_cfg.console_level = 5;
     status = pjsua_init(&cfg, &log_cfg, NULL);
     if (status != PJ_SUCCESS) error_exit("Error in pjsua_init()", status);
  }

  /* I have added this code */
  {
     PJ_LOG(3,(THIS_FILE, "conf bridge active port number %d", 
pjsua_conf_get_active_ports()));

     // Create master port, connecting port0 of the conference bridge to 
a null port
     // null port is upstream port, conference bridge port0 is connected 
to downstream port
     // Null sound device will act as a frame streaming engine for other 
ports connected to
     // conference bridge, by clocking associated callbacks
     pjsua_set_null_snd_dev();
     PJ_LOG(3,(THIS_FILE, "null snd device set, conf bridge active port 
number %d", pjsua_conf_get_active_ports()));

     // Create pool for application
     pj_pool_t *app_pool;
     app_pool = pjsua_pool_create("app_pool", 1000, 1000); // TODO 
capire cosa bisogna mettere

     // Create bidirectional media port
     pjmedia_port *ussd_port;
     status = create_ussd_port(app_pool, &ussd_port);
     if (status != PJ_SUCCESS) error_exit("Error unable to create ussd 
port", status);
     PJ_LOG(3,(THIS_FILE, "ussd, bidirectional user space sound device 
port, created"));

     // ask for a free slots in conference bridge
     pjsua_conf_port_id ussd_conf_slot_id;

     // add ussd port to conference bridge
     // pj_status_t pjsua_conf_add_port (pj_pool_t *pool, pjmedia_port 
*port, pjsua_conf_port_id *p_id)
     status = pjsua_conf_add_port(app_pool, ussd_port, &ussd_conf_slot_id);
     if (status != PJ_SUCCESS) error_exit("Error unable to add ussd port 
to conference bridge", status);

     // from now the conference port slot connected to ussd will be 
identified by ussd_conf_slot_id
     PJ_LOG(3,(THIS_FILE, "ussd port added to conf bridge, conf bridge 
active port number %d", pjsua_conf_get_active_ports()));

     // ussd port has been created and added to a slot of conf bridge, 
but there isn't any data flow yet
     // since it is not connected: so now we need to connect ussd conf 
slot to port 0 of conference bridge,
     // providing a connection for each data direction
     status = pjsua_conf_connect(0, ussd_conf_slot_id);
     if (status != PJ_SUCCESS) error_exit("Error unable to connect -> 
ussd port to conference bridge", status);
     status = pjsua_conf_connect(ussd_conf_slot_id,0);
     if (status != PJ_SUCCESS) error_exit("Error unable to connect <- 
ussd port to conference bridge", status);

     PJ_LOG(3,(THIS_FILE, "ussd port connected to conf bridge: 
bidirectional ussd data flow is up"));
  }
  /* end of my added code */

  /* Add UDP transport */
  {
     pjsua_transport_config cfg;
     pjsua_transport_config_default(&cfg);
     cfg.port = MY_UDP_PORT;
     status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &cfg, NULL);
     if (status != PJ_SUCCESS) error_exit("Error creating transport", 
status);
  }
  ....
  ....
}


/* I have added a global buffer and costants */

pj_int16_t g_buf[AUDIO_SPF+2]; // just a little bigger than needed
// audio bits per sample
#define AUDIO_BPS  16
// audio channels number
#define AUDIO_CHN   1
// audio samples per second
#define AUDIO_SPS   16000
// audio sample per frame
#define AUDIO_SPF  320

/* I have also added these functions: */

/* callback */
static pj_status_t ussd_get_frame (pjmedia_port *port, pjmedia_frame *frame)
{
     /* a sound frame requires is trasferred from g_buf to port */
     pj_int16_t *samples = frame->buf;
     pj_memcpy(frame->buf, g_microphone_buf, frame->size);
     frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
     PJ_LOG(3,(THIS_FILE, "P size:%d b:%d",frame->size,samples[10])); // 
test
     return PJ_SUCCESS;
}

/* callback */
static pj_status_t ussd_put_frame (pjmedia_port *port, pjmedia_frame *frame)
{
     /* a sound frame requires is trasferred from port to g_buf */
     pj_int16_t *samples = frame->buf;
     pj_memcpy(g_buf, frame->buf, frame->size);
     PJ_LOG(3,(THIS_FILE, "G size:%d b:%d",frame->size,samples[10])); // 
test
     return PJ_SUCCESS;
}

/* Create ussd bidirectional port */
static pj_status_t create_ussd_port(pj_pool_t *pool, pjmedia_port **p_port)
{
     pjmedia_port *port;
     unsigned     i;
     unsigned     count;
     unsigned    channel_count=AUDIO_CHN;
     unsigned    bits_per_sample=AUDIO_BPS;
     unsigned    sample_per_frame=AUDIO_SPF;
     unsigned    sampling_rate=AUDIO_SPS;
     pj_str_t     name;

     PJ_ASSERT_RETURN(pool && channel_count > 0 && channel_count <= 2, 
PJ_EINVAL); ///

     port = pj_pool_zalloc(pool, sizeof(pjmedia_port));
     PJ_ASSERT_RETURN(port != NULL, PJ_ENOMEM); ///

     // Fill in port info.
     name = pj_str("ussd");
     pjmedia_port_info_init(    &port->info, // (pjmedia_port_info *)
                             &name,
                             PJMEDIA_SIG_CLASS_PORT_AUD('s', 'i'), /// 
(unsigned) signature
                             sampling_rate, // (unsigned) clock rate
                             channel_count, // (unsigned) channel count
                             bits_per_sample, // (unsigned) bits_per_sample,
                             sample_per_frame); // (unsigned) 
samples_per_frame

     // Set the functions to feed ussd frame in both direction
     port->get_frame = &ussd_get_frame;
     port->put_frame = &ussd_put_frame;

     *p_port = port;
     return PJ_SUCCESS;
}




[Index of Archives]     [Asterisk Users]     [Asterisk App Development]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [Linux API]
  Powered by Linux