[ previous ] [ next ] [ threads ]
 To :  yate@v...
 From :  Maciek Kaminski <maciejka@t...>
 Subject :  echochannel module
 Date :  Mon, 04 Jul 2005 09:52:19 +0200
Echo channel module. Is echos backs what it send to it.

At the moment it uses default(slin) format. As it simply shuffles data 
blocks it should use peer format. Question is how to do it for 
call.execute(chan.attach is simpler I suppose).

mk



/**
 * echo.cpp
 * This file is part of the YATE Project http://YATE.null.ro
 * Copyright (C) 2005 Maciek Kaminski
 *
 * Echo channel
 *
 * Yet Another Telephony Engine - a fully featured software PBX and IVR
 * Copyright (C) 2005 Maciek Kaminski
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include 

#include 

using namespace TelEngine;

class EchoChan : public Channel
{
public:
    EchoChan(const String& name);
    ~EchoChan();
private:
    Message *m_answered;
};

class EchoConfirmator : public Thread
{
public:
  EchoConfirmator(const String &id, const String &targetid) : m_id(id), m_targetid(targetid) {};
  virtual void run();
private:
  String m_id;
  String m_targetid;
};

class EchoSource : public DataSource
{
public:
    ~EchoSource();
};

EchoSource::~EchoSource() {
    Debug("EchoChan", DebugAll,"~EchoSource");
}

class EchoConsumer : public DataConsumer
{
public:
    EchoConsumer(DataSource* source, CallEndpoint* ch)
      : DataConsumer(), m_source(source), m_ch(ch)
        { }
    ~EchoConsumer(); 
    virtual void Consume(const DataBlock& data, unsigned long timeDelta);
private:
    DataSource* m_source;
    CallEndpoint* m_ch;
    DataBlock m_buffer;
};

EchoConsumer::~EchoConsumer() {
    Debug("EchoChan", DebugAll,"~EchoConsumer");
    //m_ch->setSource();
}

class EchoDriver : public Driver
{
public:
    EchoDriver();
    virtual ~EchoDriver();
    virtual void initialize();
    virtual bool msgExecute(Message& msg, String& dest);
};

class AttachHandler : public MessageHandler
{
public:
    AttachHandler() : MessageHandler("chan.attach") { }
    virtual bool received(Message &msg);
};

INIT_PLUGIN(EchoDriver);

void EchoConsumer::Consume(const DataBlock& data, unsigned long timeDelta)
{
    m_timestamp += timeDelta;
    //Debug(DebugAll,"EchoConsumer::Consume %lud, %lud", timeDelta, timeStamp());
    m_source->Forward(data, timeDelta);
}

void EchoConfirmator::run() {
  ::usleep(50);
  Message* m = new Message("call.answered");
  m->addParam("driver","echo");
  m->addParam("id", m_id);
  m->addParam("targetid", m_targetid);
  Engine::enqueue(m);
}

EchoChan::EchoChan(const String& name)
    : Channel(__plugin)
{
    Debug(this,DebugAll,"EchoChan::EchoChan(%s) %s [%p]",name.c_str(),id().c_str(),this);
    EchoSource* source = new EchoSource();
    setSource(source);
    source->deref();
    setConsumer(new EchoConsumer(source, this));
    getConsumer()->deref();
}

EchoChan::~EchoChan()
{
    Debug(this,DebugAll,"EchoChan::~EchoChan() %s [%p]",id().c_str(),this);
    setConsumer();
    setSource();
}

bool EchoDriver::msgExecute(Message& msg, String& dest)
{
    CallEndpoint* ch = static_cast(msg.userData());
    if (ch) {
	EchoChan *c = new EchoChan(dest);
	if (ch->connect(c)) {
            String targetid(msg.getParam("id"));
	    c->deref();
            msg.addParam("driver","echo");
            msg.addParam("targetid", targetid);
	    EchoConfirmator *ec = new EchoConfirmator(c->id(), targetid);
	    if (ec->error()) {
	      Debug(DebugFail,"Error creating confirmator thread %p", ec);
	      delete ec;
	    }
	    else
	      ec->startup();
	    return true;
	}
	else {
	    c->destruct();
	    return false;
	}
    }
    Debug(DebugWarn,"Echo call with no call endpoint!");
    return false;
}

bool AttachHandler::received(Message &msg)
{
    String src(msg.getValue("source"));
    if (src.null())
	return false;
    Regexp r("^echo/$");
    if (!src.matches(r))
	return false;
    CallEndpoint *ch = static_cast(msg.userData());
    if (ch) {
      EchoSource* source = new EchoSource();
      ch->setSource(source);
      source->deref();
      ch->setConsumer(new EchoConsumer(source, ch));
      ch->getConsumer()->deref();
      return true;
    }
    else
	Debug(DebugWarn,"Echo attach request with no data channel!");
    return false;
}


EchoDriver::EchoDriver()
    : Driver("echo", "misc")
{
    Output("Loaded module Echo");
}

EchoDriver::~EchoDriver()
{
    Output("Unloading module Echo");
}

void EchoDriver::initialize()
{
    Output("Initializing module Echo");
    Engine::install(new AttachHandler);
    setup();
}

/* vi: set ts=8 sw=4 sts=4 noet: */