Last active
October 4, 2016 10:26
-
-
Save mikelnrd/6b8b4986d6529ae751ebd2af5bf4d29f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!//////!!//////!!//////!!//////!!// | |
// Scroll down in this gist to see the run logs and the full entire app as this is just the key snippet where I've likely made a mistake! Thanks :) | |
//!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!////!!//////!!//////!!//////!!//////!!// | |
///////////////////////////////////////////////////////////////////////////////// | |
// key piece of code | |
///////////////////////////////////////////////////////////////////////////////// | |
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); | |
} | |
static void call_media_deinit(pjsua_call_id call_id){ | |
log_message("RUNNING... call_media_deinit\n"); | |
struct call_data *cd; | |
cd = (struct call_data*) pjsua_call_get_user_data(call_id); | |
if (!cd) | |
return; | |
pjmedia_master_port_stop(cd->m); | |
pjmedia_master_port_destroy(cd->m, PJ_FALSE); | |
pjmedia_conf_destroy(cd->conf); | |
pjmedia_port_destroy(cd->null); | |
pjmedia_port_destroy(cd->writer); | |
log_message("Called call_media_deinit.\n"); | |
pjsua_call_set_user_data(call_id, NULL); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
https://trac.pjsip.org/repos/wiki/FAQ#pjsua-lib-perf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
09:59:05.474 os_core_unix.c !pjlib 2.5.5 for POSIX initialized | |
09:59:05.490 sip_endpoint.c .Creating endpoint instance... | |
09:59:05.516 pjlib .select() I/O Queue created (0x26aaae0) | |
09:59:05.517 sip_endpoint.c .Module "mod-msg-print" registered | |
09:59:05.517 sip_transport. .Transport manager created. | |
09:59:05.517 pjsua_core.c .PJSUA state changed: NULL --> CREATED | |
09:59:05.517 sip_endpoint.c .Module "mod-pjsua-log" registered | |
09:59:05.517 sip_endpoint.c .Module "mod-tsx-layer" registered | |
09:59:05.517 sip_endpoint.c .Module "mod-stateful-util" registered | |
09:59:05.517 sip_endpoint.c .Module "mod-ua" registered | |
09:59:05.517 sip_endpoint.c .Module "mod-100rel" registered | |
09:59:05.517 sip_endpoint.c .Module "mod-pjsua" registered | |
09:59:05.528 sip_endpoint.c .Module "mod-invite" registered | |
09:59:05.528 pjlib ..select() I/O Queue created (0x26b6a78) | |
09:59:05.531 sip_endpoint.c .Module "mod-evsub" registered | |
09:59:05.531 sip_endpoint.c .Module "mod-presence" registered | |
09:59:05.531 sip_endpoint.c .Module "mod-mwi" registered | |
09:59:05.531 sip_endpoint.c .Module "mod-refer" registered | |
09:59:05.531 sip_endpoint.c .Module "mod-pjsua-pres" registered | |
09:59:05.531 sip_endpoint.c .Module "mod-pjsua-im" registered | |
09:59:05.531 sip_endpoint.c .Module "mod-pjsua-options" registered | |
09:59:05.531 pjsua_core.c .1 SIP worker threads created | |
09:59:05.531 pjsua_core.c .pjsua version 2.5.5 for Linux-4.4.20/x86_64/glibc-2.19 initialized | |
09:59:05.531 pjsua_core.c .PJSUA state changed: CREATED --> INIT | |
09:59:05.532 pjsua_core.c SIP UDP socket reachable at 172.XX.X.X:5060 | |
09:59:05.532 udp0x26c52b0 SIP UDP transport started, published address is 172.XX.X.X:5060 | |
09:59:05.532 pjsua_core.c PJSUA state changed: INIT --> STARTING | |
09:59:05.532 sip_endpoint.c .Module "mod-unsolicited-mwi" registered | |
09:59:05.533 pjsua_core.c .PJSUA state changed: STARTING --> RUNNING | |
09:59:05.533 pjsua_acc.c Adding account: id=sip:[email protected] | |
09:59:05.533 pjsua_acc.c .Account sip:[email protected] added with id 0 | |
09:59:05.533 pjsua_call.c Making call with acc #0 to sip:[email protected] | |
09:59:05.533 pjsua_media.c .Call 0: initializing media.. | |
09:59:05.533 pjsua_media.c ..RTP socket reachable at 172.XX.X.X:4000 | |
09:59:05.533 pjsua_media.c ..RTCP socket reachable at 172.XX.X.X:4001 | |
09:59:05.533 pjsua_media.c ..Media index 0 selected for audio call 0 | |
09:59:05.562 pjsua_core.c ....TX 918 bytes Request msg INVITE/cseq=16428 (tdta0x26d0b60) to UDP 54.XXX.XX.X:5060: | |
INVITE sip:[email protected] SIP/2.0 | |
Via: SIP/2.0/UDP 172.XX.X.X:5060;rport;branch=z9hG4bKPj2741734a-4b02-4331-871b-cb41d745aa8e | |
Max-Forwards: 70 | |
From: sip:[email protected];tag=75982d61-bd17-4567-8d20-af80f715ac2e | |
To: sip:[email protected] | |
Contact: <sip:[email protected]:5060;ob> | |
Call-ID: cad2b1f2-08a4-43b9-adfa-63a7af1250b3 | |
CSeq: 16428 INVITE | |
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS | |
Supported: replaces, 100rel, timer, norefersub | |
Session-Expires: 1800 | |
Min-SE: 90 | |
Content-Type: application/sdp | |
Content-Length: 289 | |
v=0 | |
o=- 3684563945 3684563945 IN IP4 172.XX.X.X | |
s=pjmedia | |
b=AS:84 | |
t=0 0 | |
a=X-nat:0 | |
m=audio 4000 RTP/AVP 0 8 96 | |
c=IN IP4 172.XX.X.X | |
b=TIAS:64000 | |
a=rtcp:4001 IN IP4 172.XX.X.X | |
a=sendrecv | |
a=rtpmap:0 PCMU/8000 | |
a=rtpmap:8 PCMA/8000 | |
a=rtpmap:96 telephone-event/8000 | |
a=fmtp:96 0-16 | |
--end msg-- | |
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) | |
Press 'h' to hangup all calls, 'q' to quit | |
09:59:05.990 pjsua_core.c .RX 374 bytes Response msg 100/INVITE/cseq=16428 (rdata0x26c6d38) from UDP 54.XXX.XX.X:5060: | |
SIP/2.0 100 Giving a try | |
Via: SIP/2.0/UDP 172.XX.X.X:5060;received=82.X.XX.XXX;rport=57477;branch=z9hG4bKPj2741734a-4b02-4331-871b-cb41d745aa8e | |
From: sip:[email protected];tag=75982d61-bd17-4567-8d20-af80f715ac2e | |
To: sip:[email protected] | |
Call-ID: cad2b1f2-08a4-43b9-adfa-63a7af1250b3 | |
CSeq: 16428 INVITE | |
Server: Twilio Gateway | |
Content-Length: 0 | |
--end msg-- | |
09:59:10.230 pjsua_core.c .RX 945 bytes Response msg 183/INVITE/cseq=16428 (rdata0x7fb4b8000908) from UDP 54.XXX.XX.X:5060: | |
SIP/2.0 183 Session progress | |
CSeq: 16428 INVITE | |
Call-ID: cad2b1f2-08a4-43b9-adfa-63a7af1250b3 | |
From: <sip:[email protected]>;tag=75982d61-bd17-4567-8d20-af80f715ac2e | |
To: <sip:[email protected]>;tag=96764593_6772d868_ea2d552b-fe2b-4932-90e9-c559976ed365 | |
Via: SIP/2.0/UDP 172.XX.X.X:5060;received=82.X.XX.XXX;rport=57477;branch=z9hG4bKPj2741734a-4b02-4331-871b-cb41d745aa8e | |
Record-Route: <sip:54.XXX.XX.X:5060;lr;ftag=75982d61-bd17-4567-8d20-af80f715ac2e;twnat=sip:82.X.XX.XXX:57477> | |
Server: Twilio | |
Contact: <sip:172.XX.X.XXX:5060> | |
Content-Type: application/sdp | |
X-Twilio-CallSid: CA5f210920c6XXXXXXaa4e4bcf5fXXXXXX | |
Content-Length: 280 | |
v=0 | |
o=- 863029107 863029107 IN IP4 54.XXX.XX.XXX | |
s=Twilio Media Gateway | |
c=IN IP4 54.XXX.XX.XXX | |
t=0 0 | |
m=audio 10060 RTP/AVP 0 96 | |
a=rtpmap:0 PCMU/8000 | |
a=rtpmap:96 telephone-event/8000 | |
a=fmtp:96 0-15 | |
a=maxptime:20 | |
a=ptime:20 | |
a=sendrecv | |
a=rtcp:10061 IN IP4 54.XXX.XX.XXX | |
--end msg-- | |
09:59:10.230 APP .....Call 0 state=EARLY | |
09:59:10.230 pjsua_media.c .....Call 0: updating media.. | |
09:59:10.230 pjsua_aud.c ......Audio channel update.. | |
09:59:10.230 strm0x7fb4b800 .......VAD temporarily disabled | |
09:59:10.232 strm0x7fb4b800 .......Encoder stream started | |
09:59:10.233 strm0x7fb4b800 .......Decoder stream started | |
09:59:10.233 pjsua_media.c ......Audio updated, stream #0: PCMU (sendrecv) | |
09:59:10.867 strm0x7fb4b800 !VAD re-enabled | |
09:59:12.876 pjsua_core.c .RX 623 bytes Response msg 180/INVITE/cseq=16428 (rdata0x7fb4b8000908) from UDP 54.XXX.XX.X:5060: | |
SIP/2.0 180 Ringing | |
CSeq: 16428 INVITE | |
Call-ID: cad2b1f2-08a4-43b9-adfa-63a7af1250b3 | |
From: <sip:[email protected]>;tag=75982d61-bd17-4567-8d20-af80f715ac2e | |
To: <sip:[email protected]>;tag=96764593_6772d868_ea2d552b-fe2b-4932-90e9-c559976ed365 | |
Via: SIP/2.0/UDP 172.XX.X.X:5060;received=82.X.XX.XXX;rport=57477;branch=z9hG4bKPj2741734a-4b02-4331-871b-cb41d745aa8e | |
Record-Route: <sip:54.XXX.XX.X:5060;lr;ftag=75982d61-bd17-4567-8d20-af80f715ac2e;twnat=sip:82.X.XX.XXX:57477> | |
Server: Twilio | |
Contact: <sip:172.XX.X.XXX:5060> | |
X-Twilio-CallSid: CA5f210920c6XXXXXXaa4e4bcf5fXXXXXX | |
Content-Length: 0 | |
--end msg-- | |
09:59:12.876 APP .....Call 0 state=EARLY | |
09:59:14.227 pjsua_core.c .RX 931 bytes Response msg 200/INVITE/cseq=16428 (rdata0x7fb4b8000908) from UDP 54.XXX.XX.X:5060: | |
SIP/2.0 200 OK | |
CSeq: 16428 INVITE | |
Call-ID: cad2b1f2-08a4-43b9-adfa-63a7af1250b3 | |
From: <sip:[email protected]>;tag=75982d61-bd17-4567-8d20-af80f715ac2e | |
To: <sip:[email protected]>;tag=96764593_6772d868_ea2d552b-fe2b-4932-90e9-c559976ed365 | |
Via: SIP/2.0/UDP 172.XX.X.X:5060;received=82.X.XX.XXX;rport=57477;branch=z9hG4bKPj2741734a-4b02-4331-871b-cb41d745aa8e | |
Record-Route: <sip:54.XXX.XX.X:5060;lr;ftag=75982d61-bd17-4567-8d20-af80f715ac2e;twnat=sip:82.X.XX.XXX:57477> | |
Server: Twilio | |
Contact: <sip:172.XX.X.XXX:5060> | |
Content-Type: application/sdp | |
X-Twilio-CallSid: CA5f210920c6XXXXXXaa4e4bcf5fXXXXXX | |
Content-Length: 280 | |
v=0 | |
o=- 950195842 950195842 IN IP4 54.XXX.XX.XXX | |
s=Twilio Media Gateway | |
c=IN IP4 54.XXX.XX.XXX | |
t=0 0 | |
m=audio 10060 RTP/AVP 0 96 | |
a=rtpmap:0 PCMU/8000 | |
a=rtpmap:96 telephone-event/8000 | |
a=fmtp:96 0-15 | |
a=maxptime:20 | |
a=ptime:20 | |
a=sendrecv | |
a=rtcp:10061 IN IP4 54.XXX.XX.XXX | |
--end msg-- | |
09:59:14.227 APP .....Call 0 state=CONNECTING | |
09:59:14.227 inv0x26c9548 ....SDP negotiation done, message body is ignored | |
09:59:14.228 pjsua_core.c .....TX 511 bytes Request msg ACK/cseq=16428 (tdta0x7fb4b8009db0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
./myapp sip:[email protected] >> 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma GCC diagnostic ignored "-Wwrite-strings" | |
#include <pjlib.h> | |
#include <pjlib-util.h> | |
#include <pjmedia.h> | |
#include <pjmedia-codec.h> | |
#include <pjsip.h> | |
#include <pjsip_simple.h> | |
#include <pjsip_ua.h> | |
#include <pjsua-lib/pjsua.h> | |
#define THIS_FILE "APP" | |
#define SIP_DOMAIN "example.com" | |
#define SIP_USER "mike" | |
#define SIP_PASSWD "secret" | |
// global helper vars | |
int app_exiting = 0; | |
// struct for app configuration settings | |
struct app_config { | |
char *sip_domain; | |
char *sip_user; | |
char *sip_password; | |
char *phone_number; | |
char *tts; | |
char *tts_file; | |
int record_call; | |
char *record_file; | |
int repetition_limit; | |
int silent_mode; | |
} app_cfg; | |
// helper for logging messages to console (disabled if silent mode is active) | |
static void log_message(char *message) | |
{ | |
if (!app_cfg.silent_mode) | |
{ | |
fprintf(stderr, message); | |
} | |
} | |
// clean application exit | |
static void app_exit(char *message) | |
{ | |
log_message(message); | |
if (!app_exiting) | |
{ | |
app_exiting = 1; | |
log_message("Stopping application ... "); | |
// hangup open calls and stop pjsua | |
pjsua_call_hangup_all(); | |
pjsua_destroy(); | |
log_message("Done.\n"); | |
exit(0); | |
} | |
} | |
// display error and exit application | |
static void error_exit(const char *title, pj_status_t status) | |
{ | |
if (!app_exiting) | |
{ | |
app_exiting = 1; | |
pjsua_perror("SIP Call", title, status); | |
// hangup open calls and stop pjsua | |
pjsua_call_hangup_all(); | |
pjsua_destroy(); | |
exit(1); | |
} | |
} | |
///////////////////////////////////////////////////////////////////////////////// | |
// key piece of code | |
///////////////////////////////////////////////////////////////////////////////// | |
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); | |
} | |
static void call_media_deinit(pjsua_call_id call_id){ | |
log_message("RUNNING... call_media_deinit\n"); | |
struct call_data *cd; | |
cd = (struct call_data*) pjsua_call_get_user_data(call_id); | |
if (!cd) | |
return; | |
pjmedia_master_port_stop(cd->m); | |
pjmedia_master_port_destroy(cd->m, PJ_FALSE); | |
pjmedia_conf_destroy(cd->conf); | |
pjmedia_port_destroy(cd->null); | |
pjmedia_port_destroy(cd->writer); | |
log_message("Called call_media_deinit.\n"); | |
pjsua_call_set_user_data(call_id, NULL); | |
} | |
///////////////////////////////////////////////////////////////////////////////// | |
// on_ functions | |
///////////////////////////////////////////////////////////////////////////////// | |
static void on_call_state(pjsua_call_id call_id, pjsip_event *e){ | |
log_message("RUNNING... on_call_state\n"); | |
pjsua_call_info call_info; | |
pjsua_call_get_info(call_id, &call_info); | |
PJ_LOG(3,(THIS_FILE, "Call %d state=%.*s", call_id, | |
(int)call_info.state_text.slen, | |
call_info.state_text.ptr)); | |
if (call_info.state == PJSIP_INV_STATE_CALLING) { | |
log_message("Call state is CALLING.\n"); | |
call_media_init(call_id); | |
} | |
if (call_info.state == PJSIP_INV_STATE_CONFIRMED) { | |
log_message("Call state is CONFIRMED.\n"); | |
} | |
if (call_info.state == PJSIP_INV_STATE_DISCONNECTED) { | |
log_message("Call state is DISCONNECTED.\n"); | |
call_media_deinit(call_id); | |
} | |
} | |
static void on_call_media_state(pjsua_call_id call_id){ | |
log_message("RUNNING... on_call_media_state\n"); | |
pjsua_call_info call_info; | |
pjsua_call_get_info(call_id, &call_info); | |
if (call_info.media_status == PJSUA_CALL_MEDIA_ACTIVE) { | |
log_message("Media state is ACTIVE.\n"); | |
//call_media_init(call_id); //doesn't work here either! | |
} | |
} | |
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); | |
} | |
static void on_stream_destroyed(pjsua_call_id call_id, | |
pjmedia_stream *strm, | |
unsigned stream_idx){ | |
log_message("RUNNING... on_stream_destroyed\n"); | |
struct call_data *cd; | |
cd = (struct call_data*) pjsua_call_get_user_data(call_id); | |
if (!cd) | |
return; | |
pjmedia_conf_remove_port(cd->conf, cd->call_slot); | |
} | |
///////////////////////////////////////////////////////////////////////////////// | |
// main() | |
///////////////////////////////////////////////////////////////////////////////// | |
//argv[1] may contain URL to call. | |
int main(int argc, char *argv[]){ | |
pjsua_acc_id acc_id; | |
app_cfg.tts_file = "message.wav"; | |
app_cfg.record_call = 1; | |
app_cfg.record_file = "recording.wav"; | |
app_cfg.repetition_limit = 250; | |
app_cfg.silent_mode = 0; | |
pj_status_t status; | |
/* Create pjsua first! */ | |
status = pjsua_create(); | |
if (status != PJ_SUCCESS) error_exit("Error in pjsua_create()", status); | |
/* If argument is specified, it's got to be a valid SIP URL */ | |
if (argc > 1) { | |
status = pjsua_verify_url(argv[1]); | |
if (status != PJ_SUCCESS) error_exit("Invalid URL in argv", status); | |
} else { | |
PJ_LOG(3,(THIS_FILE, "Call %d state=%.*s", status)); | |
} | |
/* Init pjsua */ | |
{ | |
pjsua_config cfg; | |
pjsua_logging_config log_cfg; | |
pjsua_config_default(&cfg); //see pjsua.h | |
//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; | |
cfg.cb.on_stream_created = &on_stream_created; | |
cfg.cb.on_stream_destroyed = &on_stream_destroyed; | |
pjsua_logging_config_default(&log_cfg); | |
log_cfg.console_level = 4; | |
pjsua_media_config media_cfg; | |
pjsua_media_config_default(&media_cfg); | |
//media_cfg.snd_play_latency = 160; //default 2000 | |
//media_cfg.snd_rec_latency = 160; //default 2000 | |
//media_cfg.clock_rate = 16000; | |
//media_cfg.snd_clock_rate = 16000; | |
media_cfg.quality = 10; | |
media_cfg.ec_tail_len = 0; | |
//media_cfg.ptime = 100; //100 milliseconds //default seems to be 20? | |
status = pjsua_init(&cfg, &log_cfg, NULL); | |
if (status != PJ_SUCCESS) error_exit("Error in pjsua_init()", status); | |
} | |
/* Add UDP transport. */ | |
{ | |
pjsua_transport_config cfg; | |
pjsua_transport_config_default(&cfg); | |
cfg.port = 5060; | |
status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &cfg, NULL); | |
if (status != PJ_SUCCESS) error_exit("Error creating transport", status); | |
} | |
/* Initialization is done, now start pjsua */ | |
status = pjsua_start(); | |
if (status != PJ_SUCCESS) error_exit("Error starting pjsua", status); | |
// pjsua_set_null_snd_dev() now not used, because instead using pjsua_set_no_snd_dev() (see below) | |
// disable sound - use null sound device | |
//status = pjsua_set_null_snd_dev(); | |
//if (status != PJ_SUCCESS) error_exit("Error disabling audio", status); | |
pjmedia_port* mainconfbridgeport; | |
mainconfbridgeport = pjsua_set_no_snd_dev(); | |
/* Register to SIP server by creating SIP account. */ | |
{ | |
pjsua_acc_config cfg; | |
pjsua_acc_config_default(&cfg); | |
cfg.id = pj_str("sip:" SIP_USER "@" SIP_DOMAIN); | |
status = pjsua_acc_add(&cfg, PJ_TRUE, &acc_id); | |
if (status != PJ_SUCCESS) error_exit("Error adding account", status); | |
} | |
/* If URL is specified, make call to the URL. */ | |
if (argc > 1) { | |
pj_str_t uri = pj_str(argv[1]); | |
status = pjsua_call_make_call(acc_id, &uri, 0, NULL, NULL, NULL); | |
if (status != PJ_SUCCESS) error_exit("Error making call", status); | |
} | |
//Wait until user press "q" to quit. | |
for (;;) { | |
char option[10]; | |
puts("Press 'h' to hangup all calls, 'q' to quit"); | |
if (fgets(option, sizeof(option), stdin) == NULL) { | |
puts("EOF while reading stdin, will quit now.."); | |
break; | |
} | |
if (option[0] == 'q') | |
break; | |
if (option[0] == 'h') | |
pjsua_call_hangup_all(); | |
} | |
/* Destroy pjsua */ | |
pjsua_destroy(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment