Author: sayer
Date: 2010-05-02 02:19:39 +0200 (Sun, 02 May 2010)
New Revision: 1884

Modified:
   trunk/apps/dsm/mods/mod_conference/ModConference.cpp
   trunk/apps/dsm/mods/mod_conference/ModConference.h
   trunk/apps/dsm/mods/mod_conference/Readme.mod_conference.txt
Log:
teejoin/teeleave actions - feed input audio (speak) to a second conference 
channel, additionally to playlist one

Modified: trunk/apps/dsm/mods/mod_conference/ModConference.cpp
===================================================================
--- trunk/apps/dsm/mods/mod_conference/ModConference.cpp        2010-05-01 
23:29:23 UTC (rev 1883)
+++ trunk/apps/dsm/mods/mod_conference/ModConference.cpp        2010-05-02 
00:19:39 UTC (rev 1884)
@@ -43,6 +43,8 @@
   DEF_CMD("conference.rejoin", ConfRejoinAction);
   DEF_CMD("conference.postEvent", ConfPostEventAction);
   DEF_CMD("conference.setPlayoutType", ConfSetPlayoutTypeAction);
+  DEF_CMD("conference.teejoin", ConfTeeJoinAction);
+  DEF_CMD("conference.teeleave", ConfTeeLeaveAction);
 
 } MOD_ACTIONEXPORT_END;
 
@@ -57,6 +59,35 @@
   chan.reset(channel);
 }
 
+DSMTeeConfChannel::DSMTeeConfChannel(AmConferenceChannel* channel) 
+  : chan(channel) { 
+  audio_queue.setOwning(false);
+}
+
+DSMTeeConfChannel::~DSMTeeConfChannel() {
+}
+
+void DSMTeeConfChannel::release() {
+  chan.reset(NULL);
+}
+
+void DSMTeeConfChannel::reset(AmConferenceChannel* channel) {
+  chan.reset(channel);
+}
+
+AmAudio* DSMTeeConfChannel::setupAudio(AmAudio* out) {
+  DBG("out == %p, chan.get == %p\n", out, chan.get());
+  if (!chan.get() || !out)
+    return NULL;
+
+  // send input audio (speak) to conf channel
+  audio_queue.pushAudio(chan.get(), AmAudioQueue::InputQueue, 
AmAudioQueue::Back, true /* write */, false /* read */);
+  // send input audio (speak) to out
+  audio_queue.pushAudio(out, AmAudioQueue::InputQueue, AmAudioQueue::Back, 
true /* write */, false /* read */);
+
+  return &audio_queue;
+}
+
 CONST_ACTION_2P(ConfPostEventAction, ',', true);
 EXEC_ACTION_START(ConfPostEventAction) {
   string channel_id = resolveVars(par1, sess, sc_sess, event_params);
@@ -139,29 +170,30 @@
     sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
   }
 } EXEC_ACTION_END;
-
-static DSMConfChannel* getDSMConfChannel(DSMSession* sc_sess) {
-  if (sc_sess->avar.find(CONF_AKEY_CHANNEL) == sc_sess->avar.end()) {
+ 
+template<class T> 
+static T* getDSMConfChannel(DSMSession* sc_sess, const char* key_name) {
+  if (sc_sess->avar.find(key_name) == sc_sess->avar.end()) {
     return NULL;
   }
-  ArgObject* ao = NULL; DSMConfChannel* res = NULL;
+  ArgObject* ao = NULL; T* res = NULL;
   try {
-    if (!isArgAObject(sc_sess->avar[CONF_AKEY_CHANNEL])) {
+    if (!isArgAObject(sc_sess->avar[key_name])) {
       return NULL;
     }
-    ao = sc_sess->avar[CONF_AKEY_CHANNEL].asObject();
+    ao = sc_sess->avar[key_name].asObject();
   } catch (...){
     return NULL;
   }
 
-  if (NULL == ao || NULL == (res = dynamic_cast<DSMConfChannel*>(ao))) {
+  if (NULL == ao || NULL == (res = dynamic_cast<T*>(ao))) {
     return NULL;
   }
   return res;
 }
 
 EXEC_ACTION_START(ConfLeaveAction) {
-  DSMConfChannel* chan = getDSMConfChannel(sc_sess);
+  DSMConfChannel* chan = getDSMConfChannel<DSMConfChannel>(sc_sess, 
CONF_AKEY_CHANNEL);
   if (NULL == chan) {
     WARN("app error: trying to leave conference, but channel not found\n");
     sc_sess->SET_ERRNO(DSM_ERRNO_SCRIPT);
@@ -178,7 +210,7 @@
   string channel_id = resolveVars(par1, sess, sc_sess, event_params);
   string mode = resolveVars(par2, sess, sc_sess, event_params);
 
-  DSMConfChannel* chan = getDSMConfChannel(sc_sess);
+  DSMConfChannel* chan = getDSMConfChannel<DSMConfChannel>(sc_sess, 
CONF_AKEY_CHANNEL);
   if (NULL == chan) {
     WARN("app error: trying to rejoin conference, but channel not found\n");
   } else {
@@ -201,3 +233,96 @@
   else 
     sess->RTPStream()->setPlayoutType(SIMPLE_PLAYOUT);
 } EXEC_ACTION_END;
+
+
+CONST_ACTION_2P(ConfTeeJoinAction, ',', true);
+EXEC_ACTION_START(ConfTeeJoinAction) {
+  string channel_id = resolveVars(par1, sess, sc_sess, event_params);
+  string conf_varname = resolveVars(par2, sess, sc_sess, event_params);
+  if (conf_varname.empty()) 
+    conf_varname = CONF_AKEY_DEF_TEECHANNEL;
+
+  DBG("Speaking also in conference '%s' (with cvar '%s')\n",
+      channel_id.c_str(), conf_varname.c_str());
+
+  DSMTeeConfChannel* chan = 
+    getDSMConfChannel<DSMTeeConfChannel>(sc_sess, conf_varname.c_str());
+  if (NULL == chan) {
+    DBG("not previously in tee-channel, creating new\n");
+    AmConferenceChannel* conf_channel = 
AmConferenceStatus::getChannel(channel_id, 
+                                                                      
sess->getLocalTag());
+    if (NULL == conf_channel) {
+      ERROR("obtaining conference channel\n");
+      throw DSMException("conference");
+    }
+
+    chan = new DSMTeeConfChannel(conf_channel);
+    // remember DSMTeeConfChannel in session avar
+    AmArg c_arg;
+    c_arg.setBorrowedPointer(chan);
+    sc_sess->avar[conf_varname] = c_arg;
+    
+    // add to garbage collector
+    sc_sess->transferOwnership(chan);
+
+    // link channel audio before session's input (usually playlist)
+    AmAudio* chan_audio = chan->setupAudio(sess->getInput());
+    if (chan_audio == NULL) {
+      ERROR("tee channel audio setup failed\n");
+      throw DSMException("conference");
+    } 
+
+    sess->setInput(chan_audio);    
+
+  } else {
+    DBG("previously already in tee-channel, resetting\n");
+
+    // temporarily switch back to playlist, 
+    // while we are releasing the old channel
+    sc_sess->setInputPlaylist();
+
+    AmConferenceChannel* conf_channel = 
AmConferenceStatus::getChannel(channel_id, 
+                                                                      
sess->getLocalTag());
+    if (NULL == conf_channel) {
+      ERROR("obtaining conference channel\n");
+      throw DSMException("conference");
+      return false;
+    }
+
+    chan->reset(conf_channel);
+
+    // link channel audio before session's input (usually playlist)
+    AmAudio* chan_audio = chan->setupAudio(sess->getInput());
+    if (chan_audio == NULL) {
+      ERROR("tee channel audio setup failed\n");
+      throw DSMException("conference");
+    } 
+
+    sess->setInput(chan_audio);    
+  }
+  
+} EXEC_ACTION_END;
+
+
+EXEC_ACTION_START(ConfTeeLeaveAction) {
+  string conf_varname = resolveVars(arg, sess, sc_sess, event_params);
+  if (conf_varname.empty()) 
+    conf_varname = CONF_AKEY_DEF_TEECHANNEL;
+
+  DSMTeeConfChannel* chan = 
+    getDSMConfChannel<DSMTeeConfChannel>(sc_sess, conf_varname.c_str());
+  if (NULL == chan) {
+    WARN("app error: trying to leave tee conference, but channel not found\n");
+    sc_sess->SET_ERRNO(DSM_ERRNO_SCRIPT);
+    sc_sess->SET_STRERROR("trying to leave tee conference, but channel not 
found");
+    return false;
+  }
+
+  // for safety, set back playlist to in/out
+  sc_sess->setInOutPlaylist();
+
+  // release conf channel 
+  chan->release();
+
+  sc_sess->CLR_ERRNO;
+} EXEC_ACTION_END;

Modified: trunk/apps/dsm/mods/mod_conference/ModConference.h
===================================================================
--- trunk/apps/dsm/mods/mod_conference/ModConference.h  2010-05-01 23:29:23 UTC 
(rev 1883)
+++ trunk/apps/dsm/mods/mod_conference/ModConference.h  2010-05-02 00:19:39 UTC 
(rev 1884)
@@ -29,14 +29,17 @@
 #include "DSMModule.h"
 #include "AmConferenceStatus.h"
 #include "DSMSession.h"
+#include "AmAdvancedAudio.h"
 
 #include <memory>
 #define MOD_CLS_NAME ConfModule
 
 DECLARE_MODULE(MOD_CLS_NAME);
 
-#define CONF_AKEY_CHANNEL "conf.chan" 
+#define CONF_AKEY_CHANNEL        "conf.chan" 
+#define CONF_AKEY_DEF_TEECHANNEL "conf.teechan" 
 
+/** holds a conference channel  */
 class DSMConfChannel 
 : public DSMDisposable,
   public ArgObject {
@@ -47,7 +50,22 @@
   ~DSMConfChannel() { }
   void release();
   void reset(AmConferenceChannel* channel);
+};
 
+/** hold conference channel and audio queue */
+class DSMTeeConfChannel
+: public DSMDisposable,
+  public ArgObject {
+  std::auto_ptr<AmConferenceChannel> chan;
+  AmAudioQueue audio_queue;
+
+ public:
+  DSMTeeConfChannel(AmConferenceChannel* channel);
+  ~DSMTeeConfChannel();
+
+  void release();
+  void reset(AmConferenceChannel* channel);
+  AmAudio* setupAudio(AmAudio* out);
 };
 
 DEF_ACTION_2P(ConfJoinAction);
@@ -56,4 +74,6 @@
 DEF_ACTION_2P(ConfPostEventAction);
 DEF_ACTION_1P(ConfSetPlayoutTypeAction);
 
+DEF_ACTION_2P(ConfTeeJoinAction);
+DEF_ACTION_1P(ConfTeeLeaveAction);
 #endif

Modified: trunk/apps/dsm/mods/mod_conference/Readme.mod_conference.txt
===================================================================
--- trunk/apps/dsm/mods/mod_conference/Readme.mod_conference.txt        
2010-05-01 23:29:23 UTC (rev 1883)
+++ trunk/apps/dsm/mods/mod_conference/Readme.mod_conference.txt        
2010-05-02 00:19:39 UTC (rev 1884)
@@ -16,3 +16,16 @@
 
  conference.setPlayoutType(string type)
    where type is one of ["adaptive", "jb", "simple"]
+
+conference.teejoin(string roomname [, string avar_id])
+   - speak also to conference with roomname
+   - avar_id is the name in which conference channel is stored 
+   - if this is called in the beginning of a call (sessionStart event, 
+     or initial state enter block), call setPlaylistInOut before 
+     conference.teejoin (teejoin uses input to connect to audio queue,
+     which is normally set only after running sessionStart event in 
+     inital state)
+
+conference.teeleave([string avar_id])
+   - leave tee conference (release conf channel)
+   - resets playlist as input and output

_______________________________________________
Semsdev mailing list
[email protected]
http://lists.iptel.org/mailman/listinfo/semsdev

Reply via email to