diff options
author | Benny Prijono <bennylp@teluu.com> | 2006-02-21 00:11:18 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2006-02-21 00:11:18 +0000 |
commit | 0d81e067197a673a11e69ed71ac3c52e71fa5cdc (patch) | |
tree | feaae759f2c108fc396b1c73596e96d2d3e84e77 /pjsip/src | |
parent | 295cee81042c609eea993b4f5c292614f979cbaa (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.c | 56 | ||||
-rw-r--r-- | pjsip/src/pjsua/pjsua.h | 28 | ||||
-rw-r--r-- | pjsip/src/pjsua/pjsua_core.c | 91 | ||||
-rw-r--r-- | pjsip/src/pjsua/pjsua_inv.c | 79 |
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")); } } |