From adc44f323e5bd18b4c62398d1f9ecf88bb06a996 Mon Sep 17 00:00:00 2001 From: Stefan Sayer Date: Mon, 16 Apr 2012 15:31:02 +0200 Subject: [PATCH] dsm: several enhancements (playSilence, rtpTimeout/conference events, processing SDP from module) based on a patch by Emil Kroymann Conflicts: apps/dsm/DSMCall.cpp apps/dsm/DSMCall.h apps/dsm/DSMSession.h apps/dsm/DSMStateEngine.h apps/dsm/SystemDSM.cpp apps/dsm/SystemDSM.h doc/dsm/dsm_syntax.txt Conflicts: doc/dsm/dsm_syntax.txt --- apps/dsm/DSMCall.cpp | 49 +++++++++++++++++++++++++++++++++---- apps/dsm/DSMCall.h | 6 +++-- apps/dsm/DSMCoreModule.cpp | 28 +++++++++++++++++++++ apps/dsm/DSMCoreModule.h | 3 +++ apps/dsm/DSMModule.h | 2 ++ apps/dsm/DSMSession.h | 6 +++-- apps/dsm/DSMStateEngine.cpp | 12 +++++++++ apps/dsm/DSMStateEngine.h | 5 ++++ apps/dsm/SystemDSM.cpp | 6 +++-- apps/dsm/SystemDSM.h | 6 +++-- doc/dsm/dsm_syntax.txt | 30 ++++++++++++++++++++++- 11 files changed, 139 insertions(+), 14 deletions(-) diff --git a/apps/dsm/DSMCall.cpp b/apps/dsm/DSMCall.cpp index a996af0b..63af6742 100644 --- a/apps/dsm/DSMCall.cpp +++ b/apps/dsm/DSMCall.cpp @@ -29,6 +29,8 @@ #include "AmUtils.h" #include "AmMediaProcessor.h" #include "DSM.h" +#include "AmConferenceStatus.h" +#include "AmAdvancedAudio.h" #include "AmSipSubscription.h" #include "../apps/jsonrpc/JsonRPCEvents.h" // todo! @@ -385,6 +387,14 @@ void DSMCall::process(AmEvent* event) engine.runEvent(this, this, DSMCondition::PlaylistSeparator, ¶ms); } + ConferenceEvent * conf_ev = dynamic_cast(event); + if (conf_ev) { + map params; + params["type"] = "conference_event"; + params["id"] = int2str(conf_ev->event_id); + engine.runEvent(this, this, DSMCondition::DSMEvent, ¶ms); + } + // todo: give modules the possibility to define/process events JsonRpcEvent* jsonrpc_ev = dynamic_cast(event); if (jsonrpc_ev) { @@ -459,6 +469,15 @@ void DSMCall::process(AmEvent* event) } } + AmRtpTimeoutEvent* timeout_ev = dynamic_cast(event); + if (timeout_ev) { + map params; + params["type"] = "rtp_timeout"; + params["timeout_value"] = int2str(AmConfig::DeadRtpTime); + engine.runEvent(this, this, DSMCondition::RTPTimeout, ¶ms); + return; + } + AmB2BCallerSession::process(event); } @@ -466,13 +485,13 @@ inline UACAuthCred* DSMCall::getCredentials() { return cred.get(); } -void DSMCall::playPrompt(const string& name, bool loop) { +void DSMCall::playPrompt(const string& name, bool loop, bool front) { DBG("playing prompt '%s'\n", name.c_str()); if (prompts->addToPlaylist(name, (long)this, playlist, - /*front =*/ false, loop)) { + front, loop)) { if ((var["prompts.default_fallback"] != "yes") || default_prompts->addToPlaylist(name, (long)this, playlist, - /*front =*/ false, loop)) { + front, loop)) { DBG("checked [%p]\n", default_prompts); throw DSMException("prompt", "name", name); } else { @@ -489,9 +508,17 @@ void DSMCall::closePlaylist(bool notify) { playlist.close(notify); } -void DSMCall::addToPlaylist(AmPlaylistItem* item) { +void DSMCall::flushPlaylist() { + DBG("flush playlist\n"); + playlist.close(false); +} + +void DSMCall::addToPlaylist(AmPlaylistItem* item, bool front) { DBG("add item to playlist\n"); - playlist.addToPlaylist(item); + if (front) + playlist.addToPlayListFront(item); + else + playlist.addToPlaylist(item); } void DSMCall::playFile(const string& name, bool loop, bool front) { @@ -517,6 +544,18 @@ void DSMCall::playFile(const string& name, bool loop, bool front) { CLR_ERRNO; } +void DSMCall::playSilence(unsigned int length, bool front) { + AmNullAudio* af = new AmNullAudio(); + af->setReadLength(length); + if (front) + playlist.addToPlayListFront(new AmPlaylistItem(af, NULL)); + else + playlist.addToPlaylist(new AmPlaylistItem(af, NULL)); + + audiofiles.push_back(af); + CLR_ERRNO; +} + void DSMCall::recordFile(const string& name) { if (rec_file) stopRecord(); diff --git a/apps/dsm/DSMCall.h b/apps/dsm/DSMCall.h index 7e7405ac..673f1c59 100644 --- a/apps/dsm/DSMCall.h +++ b/apps/dsm/DSMCall.h @@ -97,10 +97,12 @@ public: void setPromptSets(map& new_prompt_sets); // DSMSession interface - void playPrompt(const string& name, bool loop = false); + void playPrompt(const string& name, bool loop = false, bool front = false); void closePlaylist(bool notify); - void addToPlaylist(AmPlaylistItem* item); + void flushPlaylist(); + void addToPlaylist(AmPlaylistItem* item, bool front = false); void playFile(const string& name, bool loop, bool front=false); + void playSilence(unsigned int length, bool front=false); void recordFile(const string& name); unsigned int getRecordLength(); unsigned int getRecordDataSize(); diff --git a/apps/dsm/DSMCoreModule.cpp b/apps/dsm/DSMCoreModule.cpp index 0c9d3a9a..a4c87ce4 100644 --- a/apps/dsm/DSMCoreModule.cpp +++ b/apps/dsm/DSMCoreModule.cpp @@ -55,9 +55,12 @@ DSMAction* DSMCoreModule::getAction(const string& from_str) { DEF_CMD("stop", SCStopAction); DEF_CMD("playPrompt", SCPlayPromptAction); + DEF_CMD("playPromptFront", SCPlayPromptFrontAction); DEF_CMD("playPromptLooped", SCPlayPromptLoopedAction); DEF_CMD("playFile", SCPlayFileAction); DEF_CMD("playFileFront", SCPlayFileFrontAction); + DEF_CMD("playSilence", SCPlaySilenceAction); + DEF_CMD("playSilenceFront", SCPlaySilenceFrontAction); DEF_CMD("recordFile", SCRecordFileAction); DEF_CMD("stopRecord", SCStopRecordAction); DEF_CMD("getRecordLength", SCGetRecordLengthAction); @@ -209,6 +212,9 @@ DSMCondition* DSMCoreModule::getCondition(const string& from_str) { if (cmd == "system") return new TestDSMCondition(params, DSMCondition::System); + if (cmd == "rtpTimeout") + return new TestDSMCondition(params, DSMCondition::RTPTimeout); + return NULL; } @@ -216,6 +222,10 @@ EXEC_ACTION_START(SCPlayPromptAction) { sc_sess->playPrompt(resolveVars(arg, sess, sc_sess, event_params)); } EXEC_ACTION_END; +EXEC_ACTION_START(SCPlayPromptFrontAction) { + sc_sess->playPrompt(resolveVars(arg, sess, sc_sess, event_params), false, true); +} EXEC_ACTION_END; + EXEC_ACTION_START(SCSetPromptsAction) { sc_sess->setPromptSet(resolveVars(arg, sess, sc_sess, event_params)); } EXEC_ACTION_END; @@ -291,6 +301,24 @@ EXEC_ACTION_START(SCPlayFileFrontAction) { loop, true); } EXEC_ACTION_END; +EXEC_ACTION_START(SCPlaySilenceAction) { + int length; + string length_str = resolveVars(arg, sess, sc_sess, event_params); + if (!str2int(length_str, length)) { + throw DSMException("core", "cause", "cannot parse number"); + } + sc_sess->playSilence(length); +} EXEC_ACTION_END; + +EXEC_ACTION_START(SCPlaySilenceFrontAction) { + int length; + string length_str = resolveVars(arg, sess, sc_sess, event_params); + if (!str2int(length_str, length)) { + throw DSMException("core", "cause", "cannot parse number"); + } + sc_sess->playSilence(length, true); +} EXEC_ACTION_END; + EXEC_ACTION_START(SCRecordFileAction) { sc_sess->recordFile(resolveVars(arg, sess, sc_sess, event_params)); } EXEC_ACTION_END; diff --git a/apps/dsm/DSMCoreModule.h b/apps/dsm/DSMCoreModule.h index 6eca3aa3..71565639 100644 --- a/apps/dsm/DSMCoreModule.h +++ b/apps/dsm/DSMCoreModule.h @@ -48,6 +48,7 @@ class DSMCoreModule }; DEF_ACTION_1P(SCPlayPromptAction); +DEF_ACTION_1P(SCPlayPromptFrontAction); DEF_ACTION_1P(SCPlayPromptLoopedAction); DEF_ACTION_1P(SCRecordFileAction); DEF_ACTION_1P(SCStopRecordAction); @@ -98,6 +99,8 @@ DEF_ACTION_2P(SCGetParamAction); DEF_ACTION_2P(SCSetVarAction); DEF_ACTION_2P(SCPlayFileAction); DEF_ACTION_2P(SCPlayFileFrontAction); +DEF_ACTION_1P(SCPlaySilenceAction); +DEF_ACTION_1P(SCPlaySilenceFrontAction); DEF_ACTION_2P(SCPostEventAction); DEF_ACTION_2P(SCB2BConnectCalleeAction); diff --git a/apps/dsm/DSMModule.h b/apps/dsm/DSMModule.h index 9398a3fc..0153971e 100644 --- a/apps/dsm/DSMModule.h +++ b/apps/dsm/DSMModule.h @@ -52,6 +52,8 @@ class DSMModule { virtual int preload() { return 0; } virtual bool onInvite(const AmSipRequest& req, DSMSession* sess) { return true; } virtual void onBeforeDestroy(DSMSession* sc_sess, AmSession* sess) { } + virtual void processSdpOffer(AmSdp& offer) { } + virtual void processSdpAnswer(const AmSdp& offer, AmSdp& answer) { } }; typedef map EventParamT; diff --git a/apps/dsm/DSMSession.h b/apps/dsm/DSMSession.h index d816ab40..b56879df 100644 --- a/apps/dsm/DSMSession.h +++ b/apps/dsm/DSMSession.h @@ -102,8 +102,9 @@ class DSMSession { DSMSession(); virtual ~DSMSession(); - virtual void playPrompt(const string& name, bool loop = false) = 0; + virtual void playPrompt(const string& name, bool loop = false, bool front = false) = 0; virtual void playFile(const string& name, bool loop, bool front = false) = 0; + virtual void playSilence(unsigned int length, bool front = false) = 0; virtual void recordFile(const string& name) = 0; virtual unsigned int getRecordLength() = 0; virtual unsigned int getRecordDataSize() = 0; @@ -112,8 +113,9 @@ class DSMSession { virtual void setInputPlaylist() = 0; virtual void setOutputPlaylist() = 0; - virtual void addToPlaylist(AmPlaylistItem* item) = 0; + virtual void addToPlaylist(AmPlaylistItem* item, bool front = false) = 0; virtual void closePlaylist(bool notify) = 0; + virtual void flushPlaylist() = 0; virtual void setPromptSet(const string& name) = 0; virtual void addSeparator(const string& name, bool front = false) = 0; virtual void connectMedia() = 0; diff --git a/apps/dsm/DSMStateEngine.cpp b/apps/dsm/DSMStateEngine.cpp index f36a2f7e..50c70c2f 100644 --- a/apps/dsm/DSMStateEngine.cpp +++ b/apps/dsm/DSMStateEngine.cpp @@ -224,6 +224,18 @@ void DSMStateEngine::onBeforeDestroy(DSMSession* sc_sess, AmSession* sess) { (*it)->onBeforeDestroy(sc_sess, sess); } +void DSMStateEngine::processSdpOffer(AmSdp& offer) { + for (vector::iterator it = + mods.begin(); it != mods.end(); it++) + (*it)->processSdpOffer(offer); +} + +void DSMStateEngine::processSdpAnswer(const AmSdp& offer, AmSdp& answer) { + for (vector::iterator it = + mods.begin(); it != mods.end(); it++) + (*it)->processSdpAnswer(offer, answer); +} + bool DSMStateEngine::runactions(vector::iterator from, vector::iterator to, AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, diff --git a/apps/dsm/DSMStateEngine.h b/apps/dsm/DSMStateEngine.h index 04d5d6ad..4e3836ff 100644 --- a/apps/dsm/DSMStateEngine.h +++ b/apps/dsm/DSMStateEngine.h @@ -30,6 +30,7 @@ #include "DSMElemContainer.h" #include "AmSipMsg.h" #include "AmArg.h" +#include "AmSdp.h" class AmSession; class DSMSession; @@ -92,6 +93,7 @@ class DSMCondition Reload, System, + RTPTimeout, SIPSubscription }; @@ -286,6 +288,9 @@ class DSMStateEngine { /** @return whether call should be accepted */ bool onInvite(const AmSipRequest& req, DSMSession* sess); void onBeforeDestroy(DSMSession* sc_sess, AmSession* sess); + + void processSdpOffer(AmSdp& offer); + void processSdpAnswer(const AmSdp& offer, AmSdp& answer); }; extern void varPrintArg(const AmArg& a, map& dst, const string& name); diff --git a/apps/dsm/SystemDSM.cpp b/apps/dsm/SystemDSM.cpp index 22ebd149..ef0f9551 100644 --- a/apps/dsm/SystemDSM.cpp +++ b/apps/dsm/SystemDSM.cpp @@ -170,8 +170,9 @@ void SystemDSM::_func { \ throw DSMException("core", "cause", "not implemented"); \ } -NOT_IMPLEMENTED(playPrompt(const string& name, bool loop)); +NOT_IMPLEMENTED(playPrompt(const string& name, bool loop, bool front)); NOT_IMPLEMENTED(playFile(const string& name, bool loop, bool front)); +NOT_IMPLEMENTED(playSilence(unsigned int length, bool front)); NOT_IMPLEMENTED(recordFile(const string& name)); NOT_IMPLEMENTED_UINT(getRecordLength()); NOT_IMPLEMENTED_UINT(getRecordDataSize()); @@ -180,7 +181,8 @@ NOT_IMPLEMENTED(setInOutPlaylist()); NOT_IMPLEMENTED(setInputPlaylist()); NOT_IMPLEMENTED(setOutputPlaylist()); -NOT_IMPLEMENTED(addToPlaylist(AmPlaylistItem* item)); +NOT_IMPLEMENTED(addToPlaylist(AmPlaylistItem* item, bool front)); +NOT_IMPLEMENTED(flushPlaylist()); NOT_IMPLEMENTED(closePlaylist(bool notify)); NOT_IMPLEMENTED(setPromptSet(const string& name)); NOT_IMPLEMENTED(addSeparator(const string& name, bool front)); diff --git a/apps/dsm/SystemDSM.h b/apps/dsm/SystemDSM.h index cb8b2eb7..b4621e30 100644 --- a/apps/dsm/SystemDSM.h +++ b/apps/dsm/SystemDSM.h @@ -52,8 +52,9 @@ class SystemDSM void process(AmEvent* event); // DSMSession interface - void playPrompt(const string& name, bool loop = false); + void playPrompt(const string& name, bool loop = false, bool front = false); void playFile(const string& name, bool loop, bool front = false); + void playSilence(unsigned int length, bool front = false); void recordFile(const string& name); unsigned int getRecordLength(); unsigned int getRecordDataSize(); @@ -62,8 +63,9 @@ class SystemDSM void setInputPlaylist(); void setOutputPlaylist(); - void addToPlaylist(AmPlaylistItem* item); + void addToPlaylist(AmPlaylistItem* item, bool front = false); void closePlaylist(bool notify); + void flushPlaylist(); void setPromptSet(const string& name); void addSeparator(const string& name, bool front = false); void connectMedia(); diff --git a/doc/dsm/dsm_syntax.txt b/doc/dsm/dsm_syntax.txt index 9c1121f3..329fd275 100644 --- a/doc/dsm/dsm_syntax.txt +++ b/doc/dsm/dsm_syntax.txt @@ -113,7 +113,7 @@ Playing prompts and file I/O if $prompts.default_fallback=yes, default prompt set is tried if prompt not found in current prompt set Throws "prompt" exeption with #name if prompt not found. - + playPromptFront(param) - play a prompt at first item in the playlist playPromptLooped(param) setPromptSet(name) @@ -129,6 +129,9 @@ Playing prompts and file I/O position in the playlist, and looped. Throws "file" exeption with #path if file can not be opened + playSilence(millisec) - play silence for millisec ms + playSilenceFront(millisec) - play silence for millisec ms at first position in playlist + recordFile(filename) Throws "file" exeption with #path if file can not be opened for recording @@ -327,6 +330,26 @@ brackets match. keyPress(key) alias to key(#key==key) + remoteDisappeared(expr) + remote end in an established call is unreachable (408/481 received) + parameters: see sipReply (below), except #old_dlg_status + + set #processed="true" if you don't want default behaviour (clear call) + + sessionTimeout(expr) + session expired (SST) + parameters: none + + set #processed="true" if you don't want default behaviour (clear call) + + rtpTimeout(expr) + RTP timeout detected + + #type - "rtp_timeout" + #timeout_value - RTP timeout value (as configured) + + set #processed="true" if you don't want default behaviour (clear call) + invite invite received/sent (only with run_invite_event): parameters: none @@ -424,6 +447,11 @@ subscription - SIP subscription status #result.* or #error.* - response data array (or error data) +conference events: + generic events with + #type - "conference_event" + #id - event ID + Selects ======= selects :