summaryrefslogtreecommitdiff
path: root/pjsip/src
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-02-21 00:11:18 +0000
committerBenny Prijono <bennylp@teluu.com>2006-02-21 00:11:18 +0000
commit0d81e067197a673a11e69ed71ac3c52e71fa5cdc (patch)
treefeaae759f2c108fc396b1c73596e96d2d3e84e77 /pjsip/src
parent295cee81042c609eea993b4f5c292614f979cbaa (diff)
Initial conference implementation
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@205 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip/src')
-rw-r--r--pjsip/src/pjsua/main.c56
-rw-r--r--pjsip/src/pjsua/pjsua.h28
-rw-r--r--pjsip/src/pjsua/pjsua_core.c91
-rw-r--r--pjsip/src/pjsua/pjsua_inv.c79
4 files changed, 208 insertions, 46 deletions
diff --git a/pjsip/src/pjsua/main.c b/pjsip/src/pjsua/main.c
index 66d4de4e..467c5a5a 100644
--- a/pjsip/src/pjsua/main.c
+++ b/pjsip/src/pjsua/main.c
@@ -136,6 +136,11 @@ static void keystroke_help(void)
puts("| ] Select next dialog | t Toggle Online status | d Dump status |");
puts("| [ Select previous dialog | | |");
puts("+-----------------------------------------------------------------------------+");
+ puts("| Conference Command |");
+ puts("| cl List ports |");
+ puts("| cc Connect port |");
+ puts("| cd Disconnect port |");
+ puts("+-----------------------------------------------------------------------------+");
puts("| q QUIT |");
puts("+=============================================================================+");
printf(">>> ");
@@ -254,6 +259,26 @@ static void ui_input_url(const char *title, char *buf, int len,
}
}
+static void conf_list(void)
+{
+ pjmedia_conf_port_info info;
+ struct pjsua_inv_data *inv_data;
+
+ printf("Conference ports:\n");
+
+ inv_data = pjsua.inv_list.next;
+ while (inv_data != &pjsua.inv_list) {
+
+ pjmedia_conf_get_port_info(pjsua.mconf, inv_data->conf_slot, &info);
+
+ printf("Port %2d %.*s\n", inv_data->conf_slot,
+ (int)info.name.slen, info.name.ptr);
+
+ inv_data = inv_data->next;
+ }
+}
+
+
static void ui_console_main(void)
{
char menuin[10];
@@ -395,6 +420,37 @@ static void ui_console_main(void)
pjsua_pres_refresh();
break;
+ case 'c':
+ switch (menuin[1]) {
+ case 'l':
+ conf_list();
+ break;
+ case 'c':
+ case 'd':
+ {
+ char src_port[10], dst_port[10];
+ pj_status_t status;
+
+ if (!simple_input("Connect src port #:", src_port, sizeof(src_port)))
+ break;
+ if (!simple_input("To dst port #:", dst_port, sizeof(dst_port)))
+ break;
+
+ if (menuin[1]=='c') {
+ status = pjmedia_conf_connect_port(pjsua.mconf, atoi(src_port), atoi(dst_port));
+ } else {
+ status = pjmedia_conf_disconnect_port(pjsua.mconf, atoi(src_port), atoi(dst_port));
+ }
+ if (status == PJ_SUCCESS) {
+ puts("Success");
+ } else {
+ puts("ERROR!!");
+ }
+ }
+ break;
+ }
+ break;
+
case 'd':
pjsua_dump();
break;
diff --git a/pjsip/src/pjsua/pjsua.h b/pjsip/src/pjsua/pjsua.h
index 6bd19d57..3afde354 100644
--- a/pjsip/src/pjsua/pjsua.h
+++ b/pjsip/src/pjsua/pjsua.h
@@ -49,6 +49,12 @@ PJ_BEGIN_DECL
*/
#define PJSUA_MAX_BUDDIES 32
+/**
+ * Max simultaneous calls.
+ */
+#define PJSUA_MAX_CALLS 8
+
+
/**
* Structure to be attached to all dialog.
* Given a dialog "dlg", application can retrieve this structure
@@ -58,9 +64,10 @@ struct pjsua_inv_data
{
PJ_DECL_LIST_MEMBER(struct pjsua_inv_data);
- pjsip_inv_session *inv;
- pjmedia_session *session;
- void *mod_data[PJSIP_MAX_MODULE];
+ pjsip_inv_session *inv; /**< The invite session. */
+ pjmedia_session *session; /**< The media session. */
+ unsigned conf_slot; /**< Slot # in conference bridge. */
+ unsigned call_slot; /**< RTP media index in med_sock_use[] */
};
@@ -105,9 +112,16 @@ struct pjsua
/* Media: */
- pjmedia_endpt *med_endpt; /**< Media endpoint. */
- pj_bool_t null_audio;
- pjmedia_sock_info med_skinfo;
+ pjmedia_endpt *med_endpt; /**< Media endpoint. */
+ pjmedia_conf *mconf; /**< Media conference. */
+ pj_bool_t null_audio; /**< Null audio flag. */
+
+
+ /* Since we support simultaneous calls, we need to have multiple
+ * RTP sockets.
+ */
+ pjmedia_sock_info med_sock_info[PJSUA_MAX_CALLS];
+ pj_bool_t med_sock_use[PJSUA_MAX_CALLS];
/* User info: */
@@ -137,7 +151,7 @@ struct pjsua
pjsip_cred_info cred_info[4];
- /* Threading: */
+ /* Threading (optional): */
int thread_cnt; /**< Thread count. */
pj_thread_t *threads[8]; /**< Thread instances. */
diff --git a/pjsip/src/pjsua/pjsua_core.c b/pjsip/src/pjsua/pjsua_core.c
index 75560205..59386d13 100644
--- a/pjsip/src/pjsua/pjsua_core.c
+++ b/pjsip/src/pjsua/pjsua_core.c
@@ -135,7 +135,8 @@ static pj_bool_t mod_pjsua_on_rx_response(pjsip_rx_data *rdata)
/*
* Initialize sockets and optionally get the public address via STUN.
*/
-static pj_status_t init_sockets()
+static pj_status_t init_sockets(pj_bool_t sip,
+ pjmedia_sock_info *skinfo)
{
enum {
RTP_START_PORT = 4000,
@@ -151,22 +152,24 @@ static pj_status_t init_sockets()
pj_uint16_t rtp_port;
pj_sock_t sock[3];
pj_sockaddr_in mapped_addr[3];
- pj_status_t status;
+ pj_status_t status = PJ_SUCCESS;
for (i=0; i<3; ++i)
sock[i] = PJ_INVALID_SOCKET;
- /* Create and bind SIP UDP socket. */
- status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[SIP_SOCK]);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "socket() error", status);
- goto on_error;
- }
+ if (sip) {
+ /* Create and bind SIP UDP socket. */
+ status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[SIP_SOCK]);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "socket() error", status);
+ goto on_error;
+ }
- status = pj_sock_bind_in(sock[SIP_SOCK], 0, pjsua.sip_port);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "bind() error", status);
- goto on_error;
+ status = pj_sock_bind_in(sock[SIP_SOCK], 0, pjsua.sip_port);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "bind() error", status);
+ goto on_error;
+ }
}
/* Initialize start of RTP port to try. */
@@ -229,7 +232,10 @@ static pj_status_t init_sockets()
for (i=0; i<3; ++i)
pj_memcpy(&mapped_addr[i], &addr, sizeof(addr));
- mapped_addr[SIP_SOCK].sin_port = pj_htons((pj_uint16_t)pjsua.sip_port);
+ if (sip)
+ mapped_addr[SIP_SOCK].sin_port = pj_htons((pj_uint16_t)pjsua.sip_port);
+ else
+ mapped_addr[RTP_SOCK].sin_port = pj_htons((pj_uint16_t)rtp_port);
mapped_addr[RTP_SOCK].sin_port = pj_htons((pj_uint16_t)rtp_port);
mapped_addr[RTCP_SOCK].sin_port = pj_htons((pj_uint16_t)(rtp_port+1));
break;
@@ -256,31 +262,37 @@ static pj_status_t init_sockets()
goto on_error;
}
- pjsua.sip_sock = sock[SIP_SOCK];
- pj_memcpy(&pjsua.sip_sock_name, &mapped_addr[SIP_SOCK], sizeof(pj_sockaddr_in));
+ if (sip) {
+ pjsua.sip_sock = sock[SIP_SOCK];
+ pj_memcpy(&pjsua.sip_sock_name, &mapped_addr[SIP_SOCK], sizeof(pj_sockaddr_in));
+ }
- pjsua.med_skinfo.rtp_sock = sock[RTP_SOCK];
- pj_memcpy(&pjsua.med_skinfo.rtp_addr_name,
+ skinfo->rtp_sock = sock[RTP_SOCK];
+ pj_memcpy(&skinfo->rtp_addr_name,
&mapped_addr[RTP_SOCK], sizeof(pj_sockaddr_in));
- pjsua.med_skinfo.rtcp_sock = sock[RTCP_SOCK];
- pj_memcpy(&pjsua.med_skinfo.rtcp_addr_name,
+ skinfo->rtcp_sock = sock[RTCP_SOCK];
+ pj_memcpy(&skinfo->rtcp_addr_name,
&mapped_addr[RTCP_SOCK], sizeof(pj_sockaddr_in));
- PJ_LOG(4,(THIS_FILE, "SIP UDP socket reachable at %s:%d",
- pj_inet_ntoa(pjsua.sip_sock_name.sin_addr),
- pj_ntohs(pjsua.sip_sock_name.sin_port)));
+ if (sip) {
+ PJ_LOG(4,(THIS_FILE, "SIP UDP socket reachable at %s:%d",
+ pj_inet_ntoa(pjsua.sip_sock_name.sin_addr),
+ pj_ntohs(pjsua.sip_sock_name.sin_port)));
+ }
PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s:%d",
- pj_inet_ntoa(pjsua.med_skinfo.rtp_addr_name.sin_addr),
- pj_ntohs(pjsua.med_skinfo.rtp_addr_name.sin_port)));
+ pj_inet_ntoa(skinfo->rtp_addr_name.sin_addr),
+ pj_ntohs(skinfo->rtp_addr_name.sin_port)));
PJ_LOG(4,(THIS_FILE, "RTCP UDP socket reachable at %s:%d",
- pj_inet_ntoa(pjsua.med_skinfo.rtcp_addr_name.sin_addr),
- pj_ntohs(pjsua.med_skinfo.rtcp_addr_name.sin_port)));
+ pj_inet_ntoa(skinfo->rtcp_addr_name.sin_addr),
+ pj_ntohs(skinfo->rtcp_addr_name.sin_port)));
return PJ_SUCCESS;
on_error:
for (i=0; i<3; ++i) {
+ if (sip && i==0)
+ continue;
if (sock[i] != PJ_INVALID_SOCKET)
pj_sock_close(sock[i]);
}
@@ -484,6 +496,17 @@ pj_status_t pjsua_init(void)
return status;
}
+ /* Init conference bridge. */
+
+ status = pjmedia_conf_create(pjsua.pool, 8, 8000, 160, 16, &pjsua.mconf);
+ if (status != PJ_SUCCESS) {
+ pj_caching_pool_destroy(&pjsua.cp);
+ pjsua_perror(THIS_FILE,
+ "Media stack initialization has returned error",
+ status);
+ return status;
+ }
+
/* Init pjmedia-codecs: */
status = pjmedia_codec_init(pjsua.med_endpt);
@@ -510,18 +533,18 @@ pj_status_t pjsua_start(void)
{
int i; /* Must be signed */
pjsip_transport *udp_transport;
- pj_status_t status;
+ pj_status_t status = PJ_SUCCESS;
/* Init sockets (STUN etc): */
-
- status = init_sockets();
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "init_sockets() has returned error",
- status);
- return status;
+ for (i=0; i<PJ_ARRAY_SIZE(pjsua.med_sock_info); ++i) {
+ status = init_sockets(i==0, &pjsua.med_sock_info[i]);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "init_sockets() has returned error",
+ status);
+ return status;
+ }
}
-
/* Add UDP transport: */
{
diff --git a/pjsip/src/pjsua/pjsua_inv.c b/pjsip/src/pjsua/pjsua_inv.c
index bfd714b1..434d0c70 100644
--- a/pjsip/src/pjsua/pjsua_inv.c
+++ b/pjsip/src/pjsua/pjsua_inv.c
@@ -41,12 +41,26 @@ pj_status_t pjsua_invite(const char *cstr_dest_uri,
pjsip_inv_session *inv;
struct pjsua_inv_data *inv_data;
pjsip_tx_data *tdata;
+ int med_sk_index = 0;
pj_status_t status;
/* Convert cstr_dest_uri to dest_uri */
dest_uri = pj_str((char*)cstr_dest_uri);
+ /* Find free socket. */
+ for (med_sk_index=0; med_sk_index<PJSUA_MAX_CALLS; ++med_sk_index) {
+ if (!pjsua.med_sock_use[med_sk_index])
+ break;
+ }
+
+ if (med_sk_index == PJSUA_MAX_CALLS) {
+ PJ_LOG(3,(THIS_FILE, "Error: too many calls!"));
+ return PJ_ETOOMANY;
+ }
+
+ pjsua.med_sock_use[med_sk_index] = 1;
+
/* Create outgoing dialog: */
status = pjsip_dlg_create_uac( pjsip_ua_instance(), &pjsua.local_uri,
@@ -60,7 +74,8 @@ pj_status_t pjsua_invite(const char *cstr_dest_uri,
/* Get media capability from media endpoint: */
status = pjmedia_endpt_create_sdp( pjsua.med_endpt, dlg->pool,
- 1, &pjsua.med_skinfo, &offer);
+ 1, &pjsua.med_sock_info[med_sk_index],
+ &offer);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "pjmedia unable to create SDP", status);
goto on_error;
@@ -79,6 +94,7 @@ pj_status_t pjsua_invite(const char *cstr_dest_uri,
inv_data = pj_pool_zalloc( dlg->pool, sizeof(struct pjsua_inv_data));
inv_data->inv = inv;
+ inv_data->call_slot = med_sk_index;
dlg->mod_data[pjsua.mod.id] = inv_data;
inv->mod_data[pjsua.mod.id] = inv_data;
@@ -129,6 +145,7 @@ pj_status_t pjsua_invite(const char *cstr_dest_uri,
on_error:
PJ_TODO(DESTROY_DIALOG_ON_FAIL);
+ pjsua.med_sock_use[med_sk_index] = 0;
return status;
}
@@ -182,16 +199,33 @@ pj_bool_t pjsua_inv_on_incoming(pjsip_rx_data *rdata)
pjsip_inv_session *inv;
struct pjsua_inv_data *inv_data;
pjmedia_sdp_session *answer;
+ int med_sk_index;
+
+ /* Find free socket. */
+ for (med_sk_index=0; med_sk_index<PJSUA_MAX_CALLS; ++med_sk_index) {
+ if (!pjsua.med_sock_use[med_sk_index])
+ break;
+ }
+
+ if (med_sk_index == PJSUA_MAX_CALLS) {
+ PJ_LOG(3,(THIS_FILE, "Error: too many calls!"));
+ return PJ_TRUE;
+ }
+
+
+ pjsua.med_sock_use[med_sk_index] = 1;
/* Get media capability from media endpoint: */
status = pjmedia_endpt_create_sdp( pjsua.med_endpt, rdata->tp_info.pool,
- 1, &pjsua.med_skinfo, &answer );
+ 1, &pjsua.med_sock_info[med_sk_index],
+ &answer );
if (status != PJ_SUCCESS) {
pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
NULL, NULL);
+ pjsua.med_sock_use[med_sk_index] = 0;
return PJ_TRUE;
}
@@ -199,8 +233,10 @@ pj_bool_t pjsua_inv_on_incoming(pjsip_rx_data *rdata)
status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,
&pjsua.contact_uri, &dlg);
- if (status != PJ_SUCCESS)
+ if (status != PJ_SUCCESS) {
+ pjsua.med_sock_use[med_sk_index] = 0;
return PJ_TRUE;
+ }
/* Create invite session: */
@@ -214,6 +250,7 @@ pj_bool_t pjsua_inv_on_incoming(pjsip_rx_data *rdata)
status = pjsip_dlg_send_response(dlg,
pjsip_rdata_get_tsx(rdata),
response);
+ pjsua.med_sock_use[med_sk_index] = 0;
return PJ_TRUE;
}
@@ -223,6 +260,7 @@ pj_bool_t pjsua_inv_on_incoming(pjsip_rx_data *rdata)
inv_data = pj_pool_zalloc(dlg->pool, sizeof(struct pjsua_inv_data));
inv_data->inv = inv;
+ inv_data->call_slot = inv_data->call_slot = med_sk_index;
dlg->mod_data[pjsua.mod.id] = inv_data;
inv->mod_data[pjsua.mod.id] = inv_data;
@@ -260,7 +298,9 @@ void pjsua_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e)
pj_assert(inv_data != NULL);
if (inv_data && inv_data->session) {
+ pjmedia_conf_remove_port(pjsua.mconf, inv_data->conf_slot);
pjmedia_session_destroy(inv_data->session);
+ pjsua.med_sock_use[inv_data->call_slot] = 0;
inv_data->session = NULL;
PJ_LOG(3,(THIS_FILE,"Media session is destroyed"));
@@ -312,7 +352,9 @@ void pjsua_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status)
inv_data = inv->dlg->mod_data[pjsua.mod.id];
if (inv_data && inv_data->session) {
+ pjmedia_conf_remove_port(pjsua.mconf, inv_data->conf_slot);
pjmedia_session_destroy(inv_data->session);
+ pjsua.med_sock_use[inv_data->call_slot] = 0;
inv_data->session = NULL;
}
@@ -335,14 +377,17 @@ void pjsua_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status)
return;
}
-
/* Create new media session.
* The media session is active immediately.
*/
if (!pjsua.null_audio) {
+ pjmedia_port *media_port;
+ pj_str_t port_name;
+ char tmp[PJSIP_MAX_URL_SIZE];
- status = pjmedia_session_create( pjsua.med_endpt, 1, &pjsua.med_skinfo,
+ status = pjmedia_session_create( pjsua.med_endpt, 1,
+ &pjsua.med_sock_info[inv_data->call_slot],
local_sdp, remote_sdp,
&inv_data->session );
if (status != PJ_SUCCESS) {
@@ -351,6 +396,30 @@ void pjsua_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status)
return;
}
+ pjmedia_session_get_port(inv_data->session, 0, &media_port);
+
+ port_name.ptr = tmp;
+ port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI,
+ inv_data->inv->dlg->remote.info->uri,
+ tmp, sizeof(tmp));
+ if (port_name.slen < 1) {
+ port_name = pj_str("call");
+ }
+ status = pjmedia_conf_add_port( pjsua.mconf, inv->pool,
+ media_port,
+ &port_name,
+ &inv_data->conf_slot);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Unable to create conference slot",
+ status);
+ pjmedia_session_destroy(inv_data->session);
+ inv_data->session = NULL;
+ return;
+ }
+
+ pjmedia_conf_connect_port( pjsua.mconf, 0, inv_data->conf_slot);
+ pjmedia_conf_connect_port( pjsua.mconf, inv_data->conf_slot, 0);
+
PJ_LOG(3,(THIS_FILE,"Media has been started successfully"));
}
}