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