diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 28bfcbd3b..1dd8d1c00 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -366,12 +366,16 @@ static void vfu_request(SalOp *op) { L_GET_PRIVATE(mediaSession)->sendVfu(); } -static void dtmf_received(SalOp *op, char dtmf){ -#if 0 - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - if (!call) return; - linphone_call_notify_dtmf_received(call, dtmf); -#endif +static void dtmf_received(SalOp *op, char dtmf) { + LinphonePrivate::CallSession *session = reinterpret_cast(op->get_user_pointer()); + if (!session) + return; + LinphonePrivate::MediaSession *mediaSession = dynamic_cast(session); + if (!mediaSession) { + ms_warning("DTMF received but no MediaSession!"); + return; + } + L_GET_PRIVATE(mediaSession)->dtmfReceived(dtmf); } static void call_refer_received(SalOp *op, const SalAddress *referto){ diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 0ff3d58a4..8acfc076f 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -51,37 +51,18 @@ L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(Call, /* TODO: all the fields need to be removed */ struct _LinphoneCore *core; LinphoneErrorInfo *ei; - SalMediaDescription *localdesc; - SalMediaDescription *resultdesc; - struct _LinphoneCallLog *log; LinphonePrivate::SalOp *op; - LinphonePrivate::SalOp *ping_op; LinphoneCallState transfer_state; /*idle if no transfer*/ struct _AudioStream *audiostream; /**/ - struct _VideoStream *videostream; - struct _TextStream *textstream; MSAudioEndpoint *endpoint; /*used for conferencing*/ char *refer_to; - LinphoneCallParams *params; - LinphoneCallParams *current_params; - LinphoneCallParams *remote_params; - LinphoneCallStats *audio_stats; - LinphoneCallStats *video_stats; - LinphoneCallStats *text_stats; LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/ LinphoneCall *transfer_target;/*if this call received a transfer request, then transfer_target points to the new call created to the refer target */ LinphonePlayer *player; - char *dtmf_sequence; /*DTMF sequence needed to be sent using #dtmfs_timer*/ - belle_sip_source_t *dtmfs_timer; /*DTMF timer needed to send a DTMF sequence*/ LinphoneChatRoom *chat_room; LinphoneConference *conf_ref; /**> Point on the associated conference if this call is part of a conference. NULL instead. */ bool_t refer_pending; bool_t defer_update; - bool_t was_automatically_paused; - bool_t paused_by_app; - bool_t broken; /*set to TRUE when the call is in broken state due to network disconnection or transport */ - bool_t need_localip_refresh; - bool_t reinvite_on_cancel_response_requested; bool_t non_op_error; /*set when the LinphoneErrorInfo was set at higher level than sal*/ ) @@ -106,34 +87,10 @@ static void _linphone_call_destructor (LinphoneCall *call) { call->remoteAddressCache = nullptr; } bctbx_list_free_with_data(call->callbacks, (bctbx_list_free_func)linphone_call_cbs_unref); - if (call->audio_stats) { - linphone_call_stats_unref(call->audio_stats); - call->audio_stats = nullptr; - } - if (call->video_stats) { - linphone_call_stats_unref(call->video_stats); - call->video_stats = nullptr; - } - if (call->text_stats) { - linphone_call_stats_unref(call->text_stats); - call->text_stats = nullptr; - } if (call->op) { call->op->release(); call->op=nullptr; } - if (call->resultdesc) { - sal_media_description_unref(call->resultdesc); - call->resultdesc=nullptr; - } - if (call->localdesc) { - sal_media_description_unref(call->localdesc); - call->localdesc=nullptr; - } - if (call->ping_op) { - call->ping_op->release(); - call->ping_op=nullptr; - } if (call->refer_to){ ms_free(call->refer_to); call->refer_to=nullptr; @@ -146,25 +103,6 @@ static void _linphone_call_destructor (LinphoneCall *call) { linphone_call_unref(call->transfer_target); call->transfer_target=nullptr; } - if (call->log) { - linphone_call_log_unref(call->log); - call->log=nullptr; - } - if (call->dtmfs_timer) { - linphone_call_cancel_dtmfs(call); - } - if (call->params){ - linphone_call_params_unref(call->params); - call->params=nullptr; - } - if (call->current_params){ - linphone_call_params_unref(call->current_params); - call->current_params=nullptr; - } - if (call->remote_params) { - linphone_call_params_unref(call->remote_params); - call->remote_params=nullptr; - } if (call->ei) linphone_error_info_unref(call->ei); } @@ -191,18 +129,6 @@ void linphone_call_set_state (LinphoneCall *call, LinphoneCallState cstate, cons void linphone_call_init_media_streams (LinphoneCall *call) {} -#if 0 -static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'}; - -static void linphone_core_dtmf_received (LinphoneCall *call, int dtmf) { - if (dtmf<0 || dtmf>15){ - ms_warning("Bad dtmf value %i",dtmf); - return; - } - linphone_call_notify_dtmf_received(call, dtmf_tab[dtmf]); -} -#endif - /*This function is not static because used internally in linphone-daemon project*/ void _post_configure_audio_stream (AudioStream *st, LinphoneCore *lc, bool_t muted) {} @@ -259,41 +185,6 @@ void linphone_call_set_transfer_state (LinphoneCall *call, LinphoneCallState sta void _linphone_call_set_new_params (LinphoneCall *call, const LinphoneCallParams *params) {} -#if 0 -static int send_dtmf_handler (void *data, unsigned int revents) { - LinphoneCall *call = (LinphoneCall*)data; - /*By default we send DTMF RFC2833 if we do not have enabled SIP_INFO but we can also send RFC2833 and SIP_INFO*/ - if (linphone_core_get_use_rfc2833_for_dtmf(call->core)!=0 || linphone_core_get_use_info_for_dtmf(call->core)==0) - { - /* In Band DTMF */ - if (call->audiostream){ - audio_stream_send_dtmf(call->audiostream,*call->dtmf_sequence); - } - else - { - ms_error("Cannot send RFC2833 DTMF when we are not in communication."); - return FALSE; - } - } - if (linphone_core_get_use_info_for_dtmf(call->core)!=0){ - /* Out of Band DTMF (use INFO method) */ - sal_call_send_dtmf(call->op,*call->dtmf_sequence); - } - - /*this check is needed because linphone_call_send_dtmf does not set the timer since its a single character*/ - if (call->dtmfs_timer) { - memmove(call->dtmf_sequence, call->dtmf_sequence+1, strlen(call->dtmf_sequence)); - } - /* continue only if the dtmf sequence is not empty*/ - if (call->dtmf_sequence && *call->dtmf_sequence!='\0') { - return TRUE; - } else { - linphone_call_cancel_dtmfs(call); - return FALSE; - } -} -#endif - /* Internal version that does not play tone indication*/ int _linphone_call_pause (LinphoneCall *call) { return 0; @@ -607,54 +498,25 @@ void linphone_call_zoom (LinphoneCall *call, float zoom_factor, float cx, float } LinphoneStatus linphone_call_send_dtmf (LinphoneCall *call, char dtmf) { -#if 0 - if (!call){ - ms_warning("linphone_call_send_dtmf(): invalid call, canceling DTMF."); + if (!call) { + ms_warning("linphone_call_send_dtmf(): invalid call, canceling DTMF"); return -1; } - call->dtmf_sequence = &dtmf; - send_dtmf_handler(call,0); - call->dtmf_sequence = nullptr; - return 0; -#else - return 0; -#endif + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->sendDtmf(dtmf); } LinphoneStatus linphone_call_send_dtmfs (LinphoneCall *call, const char *dtmfs) { -#if 0 - if (!call){ - ms_warning("linphone_call_send_dtmfs(): invalid call, canceling DTMF sequence."); + if (!call) { + ms_warning("linphone_call_send_dtmfs(): invalid call, canceling DTMF sequence"); return -1; } - if (call->dtmfs_timer){ - ms_warning("linphone_call_send_dtmfs(): a DTMF sequence is already in place, canceling DTMF sequence."); - return -2; - } - if (dtmfs) { - int delay_ms = lp_config_get_int(call->core->config,"net","dtmf_delay_ms",200); - call->dtmf_sequence = ms_strdup(dtmfs); - call->dtmfs_timer = sal_create_timer(call->core->sal, send_dtmf_handler, call, delay_ms, "DTMF sequence timer"); - } - return 0; -#else - return 0; -#endif + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->sendDtmfs(dtmfs); } void linphone_call_cancel_dtmfs (LinphoneCall *call) { -#if 0 - /*nothing to do*/ - if (!call || !call->dtmfs_timer) return; - - sal_cancel_timer(call->core->sal, call->dtmfs_timer); - belle_sip_object_unref(call->dtmfs_timer); - call->dtmfs_timer = nullptr; - if (call->dtmf_sequence) { - ms_free(call->dtmf_sequence); - call->dtmf_sequence = nullptr; - } -#endif + if (!call) + return; + L_GET_CPP_PTR_FROM_C_OBJECT(call)->cancelDtmfs(); } bool_t linphone_call_is_in_conference (const LinphoneCall *call) { diff --git a/src/call/call-listener.h b/src/call/call-listener.h index 44f721518..066dd5e07 100644 --- a/src/call/call-listener.h +++ b/src/call/call-listener.h @@ -36,6 +36,7 @@ public: virtual void onCallSetTerminated () = 0; virtual void onCallStateChanged (LinphoneCallState state, const std::string &message) = 0; virtual void onCheckForAcceptation () = 0; + virtual void onDtmfReceived (char dtmf) = 0; virtual void onIncomingCallStarted () = 0; virtual void onIncomingCallToBeAdded () = 0; virtual void onInfoReceived (const LinphoneInfoMessage *im) = 0; diff --git a/src/call/call-p.h b/src/call/call-p.h index 73f985ee2..5d4d87838 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -63,6 +63,7 @@ private: void onCallSetTerminated () override; void onCallStateChanged (LinphoneCallState state, const std::string &message) override; void onCheckForAcceptation () override; + void onDtmfReceived (char dtmf) override; void onIncomingCallStarted () override; void onIncomingCallToBeAdded () override; void onInfoReceived (const LinphoneInfoMessage *im) override; diff --git a/src/call/call.cpp b/src/call/call.cpp index 10367dae7..b41bd6d4b 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -151,6 +151,11 @@ void CallPrivate::onCheckForAcceptation () { bctbx_list_free(copy); } +void CallPrivate::onDtmfReceived (char dtmf) { + L_Q(); + linphone_call_notify_dtmf_received(L_GET_C_BACK_PTR(q), dtmf); +} + void CallPrivate::onIncomingCallStarted () { L_Q(); linphone_core_notify_incoming_call(q->getCore()->getCCore(), L_GET_C_BACK_PTR(q)); @@ -228,6 +233,11 @@ LinphoneStatus Call::acceptUpdate (const MediaSessionParams *msp) { return static_cast(d->getActiveSession().get())->acceptUpdate(msp); } +void Call::cancelDtmfs () { + L_D(); + static_pointer_cast(d->getActiveSession())->cancelDtmfs(); +} + LinphoneStatus Call::decline (LinphoneReason reason) { L_D(); return d->getActiveSession()->decline(reason); @@ -258,6 +268,16 @@ LinphoneStatus Call::resume () { return static_cast(d->getActiveSession().get())->resume(); } +LinphoneStatus Call::sendDtmf (char dtmf) { + L_D(); + return static_pointer_cast(d->getActiveSession())->sendDtmf(dtmf); +} + +LinphoneStatus Call::sendDtmfs (const std::string &dtmfs) { + L_D(); + return static_pointer_cast(d->getActiveSession())->sendDtmfs(dtmfs); +} + void Call::sendVfuRequest () { L_D(); static_cast(d->getActiveSession().get())->sendVfuRequest(); diff --git a/src/call/call.h b/src/call/call.h index 755cb29cb..dad14d183 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -44,12 +44,15 @@ public: LinphoneStatus accept (const MediaSessionParams *msp = nullptr); LinphoneStatus acceptEarlyMedia (const MediaSessionParams *msp = nullptr); LinphoneStatus acceptUpdate (const MediaSessionParams *msp); + void cancelDtmfs (); LinphoneStatus decline (LinphoneReason reason); LinphoneStatus decline (const LinphoneErrorInfo *ei); void oglRender () const; LinphoneStatus pause (); LinphoneStatus redirect (const std::string &redirectUri); LinphoneStatus resume (); + LinphoneStatus sendDtmf (char dtmf); + LinphoneStatus sendDtmfs (const std::string &dtmfs); void sendVfuRequest (); void startRecording (); void stopRecording (); diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 5d50eaa6f..384611bb9 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -164,6 +164,12 @@ void Conference::onCheckForAcceptation (const shared_ptr &ses d->callListener->onCheckForAcceptation(); } +void Conference::onDtmfReceived (const std::shared_ptr &session, char dtmf) { + L_D(); + if (d->callListener) + d->callListener->onDtmfReceived(dtmf); +} + void Conference::onIncomingCallSessionStarted (const shared_ptr &session) { L_D(); if (d->callListener) diff --git a/src/conference/conference.h b/src/conference/conference.h index 2db432305..7c019e045 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -73,6 +73,7 @@ private: void onCallSessionSetTerminated (const std::shared_ptr &session) override; void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) override; void onCheckForAcceptation (const std::shared_ptr &session) override; + void onDtmfReceived (const std::shared_ptr &session, char dtmf) override; void onIncomingCallSessionStarted (const std::shared_ptr &session) override; void onInfoReceived (const std::shared_ptr &session, const LinphoneInfoMessage *im) override; void onEncryptionChanged (const std::shared_ptr &session, bool activated, const std::string &authToken) override; diff --git a/src/conference/session/call-session-listener.h b/src/conference/session/call-session-listener.h index 0259138dd..7ac9b231e 100644 --- a/src/conference/session/call-session-listener.h +++ b/src/conference/session/call-session-listener.h @@ -37,6 +37,7 @@ public: virtual void onCallSessionSetTerminated (const std::shared_ptr &session) = 0; virtual void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) = 0; virtual void onCheckForAcceptation (const std::shared_ptr &session) = 0; + virtual void onDtmfReceived (const std::shared_ptr &session, char dtmf) = 0; virtual void onIncomingCallSessionStarted (const std::shared_ptr &session) = 0; virtual void onInfoReceived (const std::shared_ptr &session, const LinphoneInfoMessage *im) = 0; diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index efcb27718..b93335ca3 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -132,14 +132,6 @@ void CallSessionPrivate::setState(LinphoneCallState newState, const string &mess break; } - if (newState != LinphoneCallStreamsRunning) { -#if 0 // TODO - if (call->dtmfs_timer!=NULL){ - /*cancelling DTMF sequence, if any*/ - linphone_call_cancel_dtmfs(call); - } -#endif - } if (message.empty()) { lError() << "You must fill a reason when changing call state (from " << linphone_call_state_to_string(prevState) << " to " << linphone_call_state_to_string(state) << ")"; diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index b0d9d942a..0514faea2 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -44,10 +44,12 @@ public: void accepted () override; void ackReceived (LinphoneHeaders *headers) override; + void dtmfReceived (char dtmf); bool failure () override; void pausedByRemote (); void remoteRinging () override; void resumed (); + void telephoneEventReceived (int event); void terminated () override; void updated (bool isUpdate); void updating (bool isUpdate) override; @@ -93,14 +95,14 @@ public: private: static OrtpJitterBufferAlgorithm jitterBufferNameToAlgo (const std::string &name); - #ifdef VIDEO_ENABLED - static void videoStreamEventCb (void *userData, const MSFilter *f, const unsigned int eventId, const void *args); - #endif // ifdef VIDEO_ENABLED - #ifdef TEST_EXT_RENDERER - static void extRendererCb (void *userData, const MSPicture *local, const MSPicture *remote); - #endif // ifdef TEST_EXT_RENDERER +#ifdef VIDEO_ENABLED + static void videoStreamEventCb (void *userData, const MSFilter *f, const unsigned int eventId, const void *args); +#endif // ifdef VIDEO_ENABLED +#ifdef TEST_EXT_RENDERER + static void extRendererCb (void *userData, const MSPicture *local, const MSPicture *remote); +#endif // ifdef TEST_EXT_RENDERER static void realTimeTextCharacterReceived (void *userData, MSFilter *f, unsigned int id, void *arg); - + static int sendDtmf (void *data, unsigned int revents); static float aggregateQualityRatings (float audioRating, float videoRating); std::shared_ptr getMe () const; @@ -241,10 +243,11 @@ private: void refreshSockets (); void reinviteToRecoverFromConnectionLoss () override; - #ifdef VIDEO_ENABLED - void videoStreamEventCb (const MSFilter *f, const unsigned int eventId, const void *args); - #endif // ifdef VIDEO_ENABLED +#ifdef VIDEO_ENABLED + void videoStreamEventCb (const MSFilter *f, const unsigned int eventId, const void *args); +#endif // ifdef VIDEO_ENABLED void realTimeTextCharacterReceived (MSFilter *f, unsigned int id, void *arg); + int sendDtmf (); void stunAuthRequestedCb (const char *realm, const char *nonce, const char **username, const char **password, const char **ha1); @@ -283,6 +286,9 @@ private: // The address family to prefer for RTP path, guessed from signaling path. int af; + std::string dtmfSequence; + belle_sip_source_t *dtmfTimer = nullptr; + std::string mediaLocalIp; PortConfig mediaPorts[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; bool needMediaLocalIpRefresh = false; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 8b8ed3962..c08df5b41 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -28,6 +28,7 @@ #include "conference/params/media-session-params-p.h" #include "conference/session/media-session.h" #include "core/core.h" +#include "sal/sal.h" #include "utils/payload-type-handler.h" #include "logger/logger.h" @@ -194,6 +195,12 @@ void MediaSessionPrivate::ackReceived (LinphoneHeaders *headers) { } } +void MediaSessionPrivate::dtmfReceived (char dtmf) { + L_Q(); + if (listener) + listener->onDtmfReceived(q->getSharedFromThis(), dtmf); +} + bool MediaSessionPrivate::failure () { L_Q(); const SalErrorInfo *ei = op->get_error_info(); @@ -323,6 +330,15 @@ void MediaSessionPrivate::resumed () { acceptUpdate(nullptr, LinphoneCallStreamsRunning, "Connected (streams running)"); } +void MediaSessionPrivate::telephoneEventReceived (int event) { + static char dtmfTab[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '#', 'A', 'B', 'C', 'D' }; + if ((event < 0) || (event > 15)) { + lWarning() << "Bad dtmf value " << event; + return; + } + dtmfReceived(dtmfTab[event]); +} + void MediaSessionPrivate::terminated () { stopStreams(); CallSessionPrivate::terminated(); @@ -577,6 +593,11 @@ void MediaSessionPrivate::realTimeTextCharacterReceived (void *userData, MSFilte msp->realTimeTextCharacterReceived(f, id, arg); } +int MediaSessionPrivate::sendDtmf (void *data, unsigned int revents) { + MediaSession *session = reinterpret_cast(data); + return session->getPrivate()->sendDtmf(); +} + // ----------------------------------------------------------------------------- float MediaSessionPrivate::aggregateQualityRatings (float audioRating, float videoRating) { @@ -607,6 +628,8 @@ void MediaSessionPrivate::setState (LinphoneCallState newState, const string &me L_Q(); /* Take a ref on the session otherwise it might get destroyed during the call to setState */ shared_ptr sessionRef = q->getSharedFromThis(); + if ((newState != state) && (newState != LinphoneCallStreamsRunning)) + q->cancelDtmfs(); CallSessionPrivate::setState(newState, message); updateReportingCallState(); } @@ -2194,9 +2217,7 @@ void MediaSessionPrivate::handleStreamEvents (int streamIndex) { if (ms) handleIceEvents(ev); } else if (evt == ORTP_EVENT_TELEPHONE_EVENT) { -#if 0 - linphone_core_dtmf_received(call, evd->info.telephone_event); -#endif + telephoneEventReceived(evd->info.telephone_event); } else if (evt == ORTP_EVENT_NEW_VIDEO_BANDWIDTH_ESTIMATION_AVAILABLE) { lInfo() << "Video bandwidth estimation is " << (int)(evd->info.video_bandwidth_available / 1000.) << " kbit/s"; // TODO @@ -4016,6 +4037,34 @@ void MediaSessionPrivate::realTimeTextCharacterReceived (MSFilter *f, unsigned i } } +int MediaSessionPrivate::sendDtmf () { + L_Q(); + LinphoneCore *lc = q->getCore()->getCCore(); + // By default we send DTMF RFC2833 if we do not have enabled SIP_INFO but we can also send RFC2833 and SIP_INFO + if (linphone_core_get_use_rfc2833_for_dtmf(lc) || !linphone_core_get_use_info_for_dtmf(lc)) { + // In Band DTMF + if (audioStream) + audio_stream_send_dtmf(audioStream, dtmfSequence.front()); + else { + lError() << "Cannot send RFC2833 DTMF when we are not in communication"; + return FALSE; + } + } + if (linphone_core_get_use_info_for_dtmf(lc)) { + // Out of Band DTMF (use INFO method) + op->send_dtmf(dtmfSequence.front()); + } + + dtmfSequence.erase(0, 1); + // Continue only if the dtmf sequence is not empty + if (!dtmfSequence.empty()) + return TRUE; + else { + q->cancelDtmfs(); + return FALSE; + } +} + // ----------------------------------------------------------------------------- void MediaSessionPrivate::stunAuthRequestedCb (const char *realm, const char *nonce, const char **username, const char **password, const char **ha1) { @@ -4094,6 +4143,7 @@ MediaSession::MediaSession (const shared_ptr &core, shared_ptraudioStats) linphone_call_stats_unref(d->audioStats); if (d->videoStats) @@ -4176,7 +4226,16 @@ LinphoneStatus MediaSession::acceptUpdate (const MediaSessionParams *msp) { return CallSession::acceptUpdate(msp); } -// ----------------------------------------------------------------------------- +void MediaSession::cancelDtmfs () { + L_D(); + if (!d->dtmfTimer) + return; + + getCore()->getCCore()->sal->cancel_timer(d->dtmfTimer); + belle_sip_object_unref(d->dtmfTimer); + d->dtmfTimer = nullptr; + d->dtmfSequence.clear(); +} void MediaSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalCallOp *op, const Address &from, const Address &to) { L_D(); @@ -4316,6 +4375,27 @@ LinphoneStatus MediaSession::resume () { return 0; } +LinphoneStatus MediaSession::sendDtmf (char dtmf) { + L_D(); + d->dtmfSequence = dtmf; + d->sendDtmf(); + return 0; +} + +LinphoneStatus MediaSession::sendDtmfs (const std::string &dtmfs) { + L_D(); + if (d->dtmfTimer) { + lWarning() << "MediaSession::sendDtmfs(): a DTMF sequence is already in place, canceling DTMF sequence"; + return -2; + } + if (!dtmfs.empty()) { + int delayMs = lp_config_get_int(linphone_core_get_config(getCore()->getCCore()), "net", "dtmf_delay_ms", 200); + d->dtmfSequence = dtmfs; + d->dtmfTimer = getCore()->getCCore()->sal->create_timer(MediaSessionPrivate::sendDtmf, this, delayMs, "DTMF sequence timer"); + } + return 0; +} + void MediaSession::sendVfuRequest () { #ifdef VIDEO_ENABLED L_D(); diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index 046101931..59688f4db 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -45,12 +45,15 @@ public: LinphoneStatus accept (const MediaSessionParams *msp = nullptr); LinphoneStatus acceptEarlyMedia (const MediaSessionParams *msp = nullptr); LinphoneStatus acceptUpdate (const MediaSessionParams *msp); + void cancelDtmfs (); void configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalCallOp *op, const Address &from, const Address &to) override; void initiateIncoming () override; bool initiateOutgoing () override; void iterate (time_t currentRealTime, bool oneSecondElapsed) override; LinphoneStatus pause (); LinphoneStatus resume (); + LinphoneStatus sendDtmf (char dtmf); + LinphoneStatus sendDtmfs (const std::string &dtmfs); void sendVfuRequest (); void startIncomingNotification () override; int startInvite (const Address *destination, const std::string &subject = "", const Content *content = nullptr) override;