From 2fe9c7e503a9599ed0361e10bb6ba1c4bf311e4c Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Tue, 26 Dec 2006 00:11:48 +0000 Subject: Added DTMF callback support all the way to PJSUA API (ticket #48) git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@863 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/include/pjmedia/session.h | 23 ++++++++++++++ pjmedia/include/pjmedia/stream.h | 21 +++++++++++++ pjmedia/src/pjmedia/session.c | 17 ++++++++++ pjmedia/src/pjmedia/stream.c | 65 ++++++++++++++++++++++++++++++++------- pjsip-apps/src/pjsua/pjsua_app.c | 8 +++++ pjsip/include/pjsip.h | 4 +-- pjsip/include/pjsua-lib/pjsua.h | 46 +++++++++++++++++++++++++++ pjsip/src/pjsua-lib/pjsua_call.c | 24 +++++++++++++++ pjsip/src/pjsua-lib/pjsua_media.c | 2 +- 9 files changed, 195 insertions(+), 15 deletions(-) diff --git a/pjmedia/include/pjmedia/session.h b/pjmedia/include/pjmedia/session.h index ad490669..b76e4de4 100644 --- a/pjmedia/include/pjmedia/session.h +++ b/pjmedia/include/pjmedia/session.h @@ -320,6 +320,29 @@ PJ_DECL(pj_status_t) pjmedia_session_get_dtmf( pjmedia_session *session, char *ascii_digits, unsigned *size ); +/** + * Set callback to be called upon receiving DTMF digits. If callback is + * registered, the stream will not buffer incoming DTMF but rather call + * the callback as soon as DTMF digit is received completely. + * + * @param session The media session. + * @param index The stream index. + * @param cb Callback to be called upon receiving DTMF digits. + * The DTMF digits will be given to the callback as + * ASCII digits. + * @param user_data User data to be returned back when the callback + * is called. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) +pjmedia_session_set_dtmf_callback(pjmedia_session *session, + unsigned index, + void (*cb)(pjmedia_stream*, + void *user_data, + int digit), + void *user_data); + /** * Destroy media session. * diff --git a/pjmedia/include/pjmedia/stream.h b/pjmedia/include/pjmedia/stream.h index 7a02b72a..2f862f34 100644 --- a/pjmedia/include/pjmedia/stream.h +++ b/pjmedia/include/pjmedia/stream.h @@ -276,6 +276,27 @@ PJ_DECL(pj_status_t) pjmedia_stream_get_dtmf( pjmedia_stream *stream, unsigned *size); +/** + * Set callback to be called upon receiving DTMF digits. If callback is + * registered, the stream will not buffer incoming DTMF but rather call + * the callback as soon as DTMF digit is received completely. + * + * @param stream The media stream. + * @param cb Callback to be called upon receiving DTMF digits. + * The DTMF digits will be given to the callback as + * ASCII digits. + * @param user_data User data to be returned back when the callback + * is called. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) +pjmedia_stream_set_dtmf_callback(pjmedia_stream *stream, + void (*cb)(pjmedia_stream*, + void *user_data, + int digit), + void *user_data); + /** * @} */ diff --git a/pjmedia/src/pjmedia/session.c b/pjmedia/src/pjmedia/session.c index 870576de..8d7aa885 100644 --- a/pjmedia/src/pjmedia/session.c +++ b/pjmedia/src/pjmedia/session.c @@ -733,3 +733,20 @@ PJ_DEF(pj_status_t) pjmedia_session_get_dtmf( pjmedia_session *session, return pjmedia_stream_get_dtmf(session->stream[index], ascii_digits, size); } + +/* + * Install DTMF callback. + */ +PJ_DEF(pj_status_t) +pjmedia_session_set_dtmf_callback(pjmedia_session *session, + unsigned index, + void (*cb)(pjmedia_stream*, + void *user_data, + int digit), + void *user_data) +{ + PJ_ASSERT_RETURN(session && index < session->stream_cnt, PJ_EINVAL); + return pjmedia_stream_set_dtmf_callback(session->stream[index], cb, + user_data); +} + diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c index 905b98ff..0c67a15c 100644 --- a/pjmedia/src/pjmedia/stream.c +++ b/pjmedia/src/pjmedia/stream.c @@ -113,6 +113,10 @@ struct pjmedia_stream pj_uint32_t last_dtmf_dur; /**< Start ts for cur digit. */ unsigned rx_dtmf_count; /**< # of digits in dtmf rx buf.*/ char rx_dtmf_buf[32];/**< Incoming DTMF buffer. */ + + /* DTMF callback */ + void (*dtmf_cb)(pjmedia_stream*, void*, int); + void *dtmf_cb_user_data; }; @@ -379,10 +383,11 @@ static void create_dtmf_payload(pjmedia_stream *stream, stream->tx_dtmf_buf[0].start_ts = cur_ts; pj_mutex_unlock(stream->jb_mutex); - if (stream->tx_dtmf_count) + if (stream->tx_dtmf_count) { PJ_LOG(5,(stream->port.info.name.ptr, "Sending DTMF digit id %c", digitmap[stream->tx_dtmf_buf[0].event])); + } } else if (duration == 0) { PJ_LOG(5,(stream->port.info.name.ptr, "Sending DTMF digit id %c", @@ -663,18 +668,29 @@ static void handle_incoming_dtmf( pjmedia_stream *stream, stream->last_dtmf = event->event; stream->last_dtmf_dur = pj_ntohs(event->duration); - /* By convention, we use jitter buffer's mutex to access shared - * DTMF variables. + /* If DTMF callback is installed, call the callback, otherwise keep + * the DTMF digits in the buffer. */ - pj_mutex_lock(stream->jb_mutex); - if (stream->rx_dtmf_count >= PJ_ARRAY_SIZE(stream->rx_dtmf_buf)) { - /* DTMF digits overflow. Discard the oldest digit. */ - pj_array_erase(stream->rx_dtmf_buf, sizeof(stream->rx_dtmf_buf[0]), - stream->rx_dtmf_count, 0); - --stream->rx_dtmf_count; + if (stream->dtmf_cb) { + + stream->dtmf_cb(stream, stream->dtmf_cb_user_data, + digitmap[event->event]); + + } else { + /* By convention, we use jitter buffer's mutex to access shared + * DTMF variables. + */ + pj_mutex_lock(stream->jb_mutex); + if (stream->rx_dtmf_count >= PJ_ARRAY_SIZE(stream->rx_dtmf_buf)) { + /* DTMF digits overflow. Discard the oldest digit. */ + pj_array_erase(stream->rx_dtmf_buf, + sizeof(stream->rx_dtmf_buf[0]), + stream->rx_dtmf_count, 0); + --stream->rx_dtmf_count; + } + stream->rx_dtmf_buf[stream->rx_dtmf_count++] = digitmap[event->event]; + pj_mutex_unlock(stream->jb_mutex); } - stream->rx_dtmf_buf[stream->rx_dtmf_count++] = digitmap[event->event]; - pj_mutex_unlock(stream->jb_mutex); } @@ -1368,3 +1384,30 @@ PJ_DEF(pj_status_t) pjmedia_stream_get_dtmf( pjmedia_stream *stream, return PJ_SUCCESS; } + + +/* + * Set callback to be called upon receiving DTMF digits. + */ +PJ_DEF(pj_status_t) +pjmedia_stream_set_dtmf_callback(pjmedia_stream *stream, + void (*cb)(pjmedia_stream*, + void *user_data, + int digit), + void *user_data) +{ + PJ_ASSERT_RETURN(stream, PJ_EINVAL); + + /* By convention, we use jitter buffer's mutex to access DTMF + * digits resources. + */ + pj_mutex_lock(stream->jb_mutex); + + stream->dtmf_cb = cb; + stream->dtmf_cb_user_data = user_data; + + pj_mutex_unlock(stream->jb_mutex); + + return PJ_SUCCESS; +} + diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c index be6292ac..24868a9f 100644 --- a/pjsip-apps/src/pjsua/pjsua_app.c +++ b/pjsip-apps/src/pjsua/pjsua_app.c @@ -1622,6 +1622,13 @@ static void on_call_media_state(pjsua_call_id call_id) } } +/* + * DTMF callback. + */ +static void call_on_dtmf_callback(pjsua_call_id call_id, int dtmf) +{ + PJ_LOG(3,(THIS_FILE, "Incoming DTMF on call %d: %c", call_id, dtmf)); +} /* * Handler registration status has changed. @@ -2818,6 +2825,7 @@ pj_status_t app_init(int argc, char *argv[]) app_config.cfg.cb.on_call_state = &on_call_state; app_config.cfg.cb.on_call_media_state = &on_call_media_state; app_config.cfg.cb.on_incoming_call = &on_incoming_call; + app_config.cfg.cb.on_dtmf_digit = &call_on_dtmf_callback; app_config.cfg.cb.on_reg_state = &on_reg_state; app_config.cfg.cb.on_buddy_state = &on_buddy_state; app_config.cfg.cb.on_pager = &on_pager; diff --git a/pjsip/include/pjsip.h b/pjsip/include/pjsip.h index ff6af220..32e27cb2 100644 --- a/pjsip/include/pjsip.h +++ b/pjsip/include/pjsip.h @@ -40,9 +40,7 @@ #include #include #include -#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0 -# include -#endif +#include #include /* Authentication. */ diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index eda850a5..cb8d4643 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -286,11 +286,19 @@ typedef struct pjsua_callback * Notify application when invite state has changed. * Application may then query the call info to get the * detail call states. + * + * @param call_id The call index. + * @param e Event which causes the call state to change. */ void (*on_call_state)(pjsua_call_id call_id, pjsip_event *e); /** * Notify application on incoming call. + * + * @param acc_id The account which match the incoming call. + * @param call_id The call id that has just been created for + * the call. + * @param rdata The incoming INVITE request. */ void (*on_incoming_call)(pjsua_acc_id acc_id, pjsua_call_id call_id, pjsip_rx_data *rdata); @@ -299,15 +307,31 @@ typedef struct pjsua_callback * Notify application when media state in the call has changed. * Normal application would need to implement this callback, e.g. * to connect the call's media to sound device. + * + * @param call_id The call index. */ void (*on_call_media_state)(pjsua_call_id call_id); + /** + * Notify application upon incoming DTMF digits. + * + * @param call_id The call index. + * @param digit DTMF ASCII digit. + */ + void (*on_dtmf_digit)(pjsua_call_id call_id, int digit); + /** * Notify application on call being transfered. * Application can decide to accept/reject transfer request * by setting the code (default is 200). When this callback * is not defined, the default behavior is to accept the * transfer. + * + * @param call_id The call index. + * @param dst The destination where the call will be + * transfered to. + * @param code Status code to be returned for the call transfer + * request. On input, it contains status code 200. */ void (*on_call_transfer_request)(pjsua_call_id call_id, const pj_str_t *dst, @@ -372,12 +396,16 @@ typedef struct pjsua_callback * Notify application when registration status has changed. * Application may then query the account info to get the * registration details. + * + * @param acc_id Account ID. */ void (*on_reg_state)(pjsua_acc_id acc_id); /** * Notify application when the buddy state has changed. * Application may then query the buddy into to get the details. + * + * @param buddy_id The buddy id. */ void (*on_buddy_state)(pjsua_buddy_id buddy_id); @@ -385,6 +413,15 @@ typedef struct pjsua_callback * Notify application on incoming pager (i.e. MESSAGE request). * Argument call_id will be -1 if MESSAGE request is not related to an * existing call. + * + * @param call_id Containts the ID of the call where the IM was + * sent, or PJSUA_INVALID_ID if the IM was sent + * outside call context. + * @param from URI of the sender. + * @param to URI of the destination message. + * @param contact The Contact URI of the sender, if present. + * @param mime_type MIME type of the message. + * @param body The message content. */ void (*on_pager)(pjsua_call_id call_id, const pj_str_t *from, const pj_str_t *to, const pj_str_t *contact, @@ -413,6 +450,15 @@ typedef struct pjsua_callback /** * Notify application about typing indication. + * + * @param call_id Containts the ID of the call where the IM was + * sent, or PJSUA_INVALID_ID if the IM was sent + * outside call context. + * @param from URI of the sender. + * @param to URI of the destination message. + * @param contact The Contact URI of the sender, if present. + * @param is_typing Non-zero if peer is typing, or zero if peer + * has stopped typing a message. */ void (*on_typing)(pjsua_call_id call_id, const pj_str_t *from, const pj_str_t *to, const pj_str_t *contact, diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c index 46abb1f7..b042e935 100644 --- a/pjsip/src/pjsua-lib/pjsua_call.c +++ b/pjsip/src/pjsua-lib/pjsua_call.c @@ -2049,6 +2049,22 @@ static void call_disconnect( pjsip_inv_session *inv, pjsip_inv_send_msg(inv, tdata); } +/* + * DTMF callback from the stream. + */ +static void dtmf_callback(pjmedia_stream *strm, void *user_data, + int digit) +{ + PJ_UNUSED_ARG(strm); + + if (pjsua_var.ua_cfg.cb.on_dtmf_digit) { + pjsua_call_id call_id; + + call_id = (pjsua_call_id)user_data; + pjsua_var.ua_cfg.cb.on_dtmf_digit(call_id, digit); + } +} + /* * Callback to be called when SDP offer/answer negotiation has just completed * in the session. This function will start/update media if negotiation @@ -2188,6 +2204,14 @@ static void pjsua_call_on_media_update(pjsip_inv_session *inv, return; } + /* If DTMF callback is installed by application, install our + * callback to the session. + */ + if (pjsua_var.ua_cfg.cb.on_dtmf_digit) { + pjmedia_session_set_dtmf_callback(call->session, 0, + &dtmf_callback, + (void*)(call->index)); + } /* Get the port interface of the first stream in the session. * We need the port interface to add to the conference bridge. diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c index 3c92c0ea..87d7d6df 100644 --- a/pjsip/src/pjsua-lib/pjsua_media.c +++ b/pjsip/src/pjsua-lib/pjsua_media.c @@ -442,7 +442,7 @@ pj_status_t pjsua_media_subsys_destroy(void) } /* Close media transports */ - for (i=0; i<(int)pjsua_var.ua_cfg.max_calls; ++i) { + for (i=0; iop->destroy)(pjsua_var.calls[i].med_tp); pjsua_var.calls[i].med_tp = NULL; -- cgit v1.2.3