Direct Sound channel, thread fixes
git-svn-id: http://yate.null.ro/svn/yate/trunk@347 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
858e5b893d
commit
ab4ae958d5
|
@ -71,6 +71,10 @@ private:
|
|||
|
||||
using namespace TelEngine;
|
||||
|
||||
#define SOFT_KILLS 5
|
||||
#define HARD_KILLS 5
|
||||
#define KILL_WAIT 32
|
||||
|
||||
#ifdef _WINDOWS
|
||||
DWORD tls_index = ::TlsAlloc();
|
||||
#else
|
||||
|
@ -307,16 +311,18 @@ void ThreadPrivate::killall()
|
|||
{
|
||||
Debug(DebugInfo,"Trying to kill ThreadPrivate '%s' [%p], attempt %d",t->m_name,t,c);
|
||||
tmutex.unlock();
|
||||
bool ok = t->cancel(c > 1);
|
||||
bool ok = t->cancel(c > SOFT_KILLS);
|
||||
if (ok) {
|
||||
// delay a little so threads have a chance to clean up
|
||||
for (int i=0; i<20; i++) {
|
||||
int d = 0;
|
||||
// delay a little (exponentially) so threads have a chance to clean up
|
||||
for (int i=1; i<=KILL_WAIT; i<<=1) {
|
||||
Thread::msleep(i-d);
|
||||
d = i;
|
||||
tmutex.lock();
|
||||
bool done = (t != l->get());
|
||||
tmutex.unlock();
|
||||
if (done)
|
||||
break;
|
||||
Thread::msleep(5);
|
||||
}
|
||||
}
|
||||
tmutex.lock();
|
||||
|
@ -328,10 +334,12 @@ void ThreadPrivate::killall()
|
|||
tmutex.unlock();
|
||||
t->destroy();
|
||||
tmutex.lock();
|
||||
if (t != l->get())
|
||||
c = 1;
|
||||
continue;
|
||||
}
|
||||
Thread::msleep(1);
|
||||
if (++c >= 10) {
|
||||
if (++c >= (SOFT_KILLS+HARD_KILLS)) {
|
||||
Debug(DebugGoOn,"Could not kill %p, will use sledgehammer later.",t);
|
||||
sledgehammer = true;
|
||||
t->m_thread = 0;
|
||||
|
|
|
@ -35,108 +35,124 @@
|
|||
|
||||
using namespace TelEngine;
|
||||
|
||||
// all COM objects are created in this thread's apartment
|
||||
class DSound : public Thread
|
||||
// 20ms chunk, 100ms buffer
|
||||
#define CHUNK_SIZE 320
|
||||
#define MAX_SIZE (5*CHUNK_SIZE)
|
||||
#define BUF_SIZE (4*CHUNK_SIZE)
|
||||
|
||||
class DSoundSource : public DataSource
|
||||
{
|
||||
friend class DSoundRec;
|
||||
public:
|
||||
DSoundSource();
|
||||
~DSoundSource();
|
||||
private:
|
||||
DSoundRec* m_dsound;
|
||||
};
|
||||
|
||||
class DSoundConsumer : public DataConsumer
|
||||
{
|
||||
friend class DSoundPlay;
|
||||
public:
|
||||
DSoundConsumer();
|
||||
~DSoundConsumer();
|
||||
virtual void Consume(const DataBlock &data, unsigned long timeDelta);
|
||||
private:
|
||||
DSoundPlay* m_dsound;
|
||||
};
|
||||
|
||||
// all DirectSound play related objects are created in this thread's apartment
|
||||
class DSoundPlay : public Thread, public Mutex
|
||||
{
|
||||
public:
|
||||
DSound();
|
||||
virtual ~DSound();
|
||||
DSoundPlay(DSoundConsumer* owner, LPGUID device = 0);
|
||||
virtual ~DSoundPlay();
|
||||
virtual void run();
|
||||
virtual void cleanup();
|
||||
bool init();
|
||||
inline LPDIRECTSOUND dsound()
|
||||
inline void terminate()
|
||||
{ m_owner = 0; }
|
||||
inline LPDIRECTSOUND dsound() const
|
||||
{ return m_ds; }
|
||||
inline LPDIRECTSOUNDCAPTURE dcapture()
|
||||
{ return m_dsc; }
|
||||
inline LPDIRECTSOUNDBUFFER buffer() const
|
||||
{ return m_dsb; }
|
||||
void put(const DataBlock& data);
|
||||
private:
|
||||
DSoundConsumer* m_owner;
|
||||
LPGUID m_device;
|
||||
LPDIRECTSOUND m_ds;
|
||||
LPDIRECTSOUNDCAPTURE m_dsc;
|
||||
};
|
||||
|
||||
class SoundSource : public ThreadedSource
|
||||
{
|
||||
public:
|
||||
~SoundSource();
|
||||
virtual void run();
|
||||
inline const String &name()
|
||||
{ return m_name; }
|
||||
private:
|
||||
/*SoundSource(const String &tone);
|
||||
static const Tone *getBlock(const String &tone);
|
||||
String m_name;
|
||||
const Tone *m_tone;
|
||||
DataBlock m_data;
|
||||
unsigned m_brate;
|
||||
unsigned m_total;
|
||||
u_int64_t m_time;*/
|
||||
String m_name;
|
||||
};
|
||||
|
||||
class SoundChan;
|
||||
|
||||
class SoundConsumer : public DataConsumer
|
||||
{
|
||||
public:
|
||||
SoundConsumer(SoundChan *chan,String device = "/dev/dsp"){}
|
||||
|
||||
~SoundConsumer();
|
||||
|
||||
virtual void Consume(const DataBlock &data, unsigned long timeDelta){}
|
||||
|
||||
private:
|
||||
SoundChan *m_chan;
|
||||
unsigned m_total;
|
||||
u_int64_t m_time;
|
||||
};
|
||||
|
||||
class SoundChan : public Channel
|
||||
{
|
||||
public:
|
||||
SoundChan(const String &tone);
|
||||
~SoundChan();
|
||||
LPDIRECTSOUNDBUFFER m_dsb;
|
||||
DataBlock m_buf;
|
||||
};
|
||||
|
||||
// all DirectSound record related objects are created in this thread's apartment
|
||||
class DSoundRec : public Thread
|
||||
{
|
||||
public:
|
||||
DSoundRec(DSoundSource* owner, LPGUID device = 0);
|
||||
virtual ~DSoundRec();
|
||||
virtual void run();
|
||||
virtual void cleanup();
|
||||
bool init();
|
||||
inline void terminate()
|
||||
{ m_owner = 0; Thread::msleep(10); }
|
||||
inline LPDIRECTSOUNDCAPTURE dsound() const
|
||||
{ return m_ds; }
|
||||
inline LPDIRECTSOUNDCAPTUREBUFFER buffer() const
|
||||
{ return m_dsb; }
|
||||
private:
|
||||
DSoundSource* m_owner;
|
||||
LPGUID m_device;
|
||||
LPDIRECTSOUNDCAPTURE m_ds;
|
||||
LPDIRECTSOUNDCAPTUREBUFFER m_dsb;
|
||||
};
|
||||
|
||||
class DSoundChan : public Channel
|
||||
{
|
||||
public:
|
||||
DSoundChan();
|
||||
virtual ~DSoundChan();
|
||||
};
|
||||
|
||||
class AttachHandler : public MessageHandler
|
||||
{
|
||||
public:
|
||||
AttachHandler() : MessageHandler("chan.attach") { }
|
||||
AttachHandler() : MessageHandler("chan.attach")
|
||||
{ }
|
||||
virtual bool received(Message &msg);
|
||||
};
|
||||
|
||||
class SoundDriver : public Driver
|
||||
{
|
||||
friend class DSound;
|
||||
friend class DSoundPlay;
|
||||
friend class DSoundRec;
|
||||
public:
|
||||
SoundDriver();
|
||||
~SoundDriver();
|
||||
virtual void initialize();
|
||||
virtual bool msgExecute(Message& msg, String& dest);
|
||||
inline LPDIRECTSOUND dsound()
|
||||
{ return m_dsound ? m_dsound->dsound() : 0; }
|
||||
inline LPDIRECTSOUNDCAPTURE dcapture()
|
||||
{ return m_dsound ? m_dsound->dcapture() : 0; }
|
||||
protected:
|
||||
void statusModule(String& str);
|
||||
void statusParams(String& str);
|
||||
private:
|
||||
DSound* m_dsound;
|
||||
AttachHandler* m_handler;
|
||||
};
|
||||
|
||||
INIT_PLUGIN(SoundDriver);
|
||||
|
||||
DSound::DSound()
|
||||
: Thread("DirectSound"), m_ds(0), m_dsc(0)
|
||||
DSoundPlay::DSoundPlay(DSoundConsumer* owner, LPGUID device)
|
||||
: Thread("DirectSound Play",High),
|
||||
m_owner(owner), m_device(device), m_ds(0), m_dsb(0)
|
||||
{
|
||||
}
|
||||
|
||||
DSound::~DSound()
|
||||
DSoundPlay::~DSoundPlay()
|
||||
{
|
||||
__plugin.m_dsound = 0;
|
||||
if (m_owner)
|
||||
m_owner->m_dsound = 0;
|
||||
}
|
||||
|
||||
bool DSound::init()
|
||||
bool DSoundPlay::init()
|
||||
{
|
||||
HRESULT hr;
|
||||
if (FAILED(hr = ::CoInitializeEx(NULL,COINIT_MULTITHREADED))) {
|
||||
|
@ -148,37 +164,107 @@ bool DSound::init()
|
|||
Debug(DebugGoOn,"Could not create the DirectSound object, code 0x%X",hr);
|
||||
return false;
|
||||
}
|
||||
if (FAILED(hr = IDirectSound_Initialize(m_ds, 0))) {
|
||||
if (FAILED(hr = m_ds->Initialize(m_device))) {
|
||||
Debug(DebugGoOn,"Could not initialize the DirectSound object, code 0x%X",hr);
|
||||
return false;
|
||||
}
|
||||
if (FAILED(hr = ::CoCreateInstance(CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER,
|
||||
IID_IDirectSoundCapture, (void**)&m_dsc)) || !m_dsc) {
|
||||
Debug(DebugGoOn,"Could not create the DirectSoundCapture object, code 0x%X",hr);
|
||||
HWND wnd = GetForegroundWindow();
|
||||
if (!wnd)
|
||||
wnd = GetDesktopWindow();
|
||||
if (FAILED(hr = m_ds->SetCooperativeLevel(wnd,DSSCL_WRITEPRIMARY))) {
|
||||
Debug(DebugGoOn,"Could not set the DirectSound cooperative level, code 0x%X",hr);
|
||||
return false;
|
||||
}
|
||||
if (FAILED(hr = IDirectSoundCapture_Initialize(m_dsc, 0))) {
|
||||
Debug(DebugGoOn,"Could not initialize the DirectSoundCapture object, code 0x%X",hr);
|
||||
DSBUFFERDESC bdesc;
|
||||
ZeroMemory(&bdesc, sizeof(bdesc));
|
||||
bdesc.dwSize = sizeof(bdesc);
|
||||
bdesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_STICKYFOCUS;
|
||||
// | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLVOLUME
|
||||
if (FAILED(hr = m_ds->CreateSoundBuffer(&bdesc, &m_dsb, NULL)) || !m_dsb) {
|
||||
Debug(DebugGoOn,"Could not create the DirectSound buffer, code 0x%X",hr);
|
||||
return false;
|
||||
}
|
||||
WAVEFORMATEX fmt;
|
||||
fmt.wFormatTag = WAVE_FORMAT_PCM;
|
||||
fmt.nChannels = 1;
|
||||
fmt.nSamplesPerSec = 8000;
|
||||
fmt.nAvgBytesPerSec = 16000;
|
||||
fmt.nBlockAlign = 2;
|
||||
fmt.wBitsPerSample = 16;
|
||||
fmt.cbSize = 0;
|
||||
if (FAILED(hr = m_dsb->SetFormat(&fmt))) {
|
||||
Debug(DebugGoOn,"Could not set the DirectSound buffer format, code 0x%X",hr);
|
||||
return false;
|
||||
}
|
||||
if (FAILED(hr = m_dsb->GetFormat(&fmt,sizeof(fmt),0))) {
|
||||
Debug(DebugGoOn,"Could not get the DirectSound buffer format, code 0x%X",hr);
|
||||
return false;
|
||||
}
|
||||
if ((fmt.wFormatTag != WAVE_FORMAT_PCM) ||
|
||||
(fmt.nChannels != 1) ||
|
||||
(fmt.nSamplesPerSec != 8000) ||
|
||||
(fmt.wBitsPerSample != 16)) {
|
||||
Debug(DebugGoOn,"DirectSound does not support 8000Hz 16bit mono PCM format, "
|
||||
"got fmt=%u, chans=%d samp=%d size=%u",
|
||||
fmt.wFormatTag,fmt.nChannels,fmt.nSamplesPerSec,fmt.wBitsPerSample);
|
||||
return false;
|
||||
}
|
||||
DSBCAPS caps;
|
||||
caps.dwSize = sizeof(caps);
|
||||
#ifdef DEBUG
|
||||
if (SUCCEEDED(m_dsb->GetCaps(&caps)))
|
||||
Debug(DebugInfo,"DirectSound buffer size %u",caps.dwBufferBytes);
|
||||
#endif
|
||||
if (FAILED(hr = m_dsb->Play(0,0,DSBPLAY_LOOPING))) {
|
||||
Debug(DebugGoOn,"Could not play the DirectSound buffer, code 0x%X",hr);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DSound::run()
|
||||
void DSoundPlay::run()
|
||||
{
|
||||
if (!init())
|
||||
return;
|
||||
Debug(DebugInfo,"DirectSound is initialized and running");
|
||||
for (;;) {
|
||||
if (m_owner)
|
||||
m_owner->m_dsound = this;
|
||||
Debug(DebugInfo,"DSoundPlay is initialized and running");
|
||||
while (m_owner) {
|
||||
msleep(1,true);
|
||||
if (m_dsb && (m_buf.length() >= CHUNK_SIZE)) {
|
||||
void* buf = 0;
|
||||
void* buf2 = 0;
|
||||
DWORD len = 0;
|
||||
DWORD len2 = 0;
|
||||
HRESULT hr = m_dsb->Lock(0,CHUNK_SIZE,&buf,&len,&buf2,&len2,DSBLOCK_FROMWRITECURSOR);
|
||||
if (FAILED(hr)) {
|
||||
if ((hr == DSERR_BUFFERLOST) && SUCCEEDED(m_dsb->Restore())) {
|
||||
Debug(DebugAll,"DirectSound buffer lost and restored");
|
||||
m_dsb->Play(0,0,DSBPLAY_LOOPING);
|
||||
}
|
||||
lock();
|
||||
m_buf.clear();
|
||||
unlock();
|
||||
continue;
|
||||
}
|
||||
lock();
|
||||
::memcpy(buf,m_buf.data(),len);
|
||||
if (buf2)
|
||||
::memcpy(buf2,((const char*)m_buf.data())+len,len2);
|
||||
m_dsb->Unlock(buf,len,0,0);
|
||||
m_buf.cut(-CHUNK_SIZE);
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DSound::cleanup()
|
||||
void DSoundPlay::cleanup()
|
||||
{
|
||||
if (m_dsc) {
|
||||
m_dsc->Release();
|
||||
m_dsc = 0;
|
||||
Debug(DebugInfo,"DSoundPlay cleaning up");
|
||||
if (m_dsb) {
|
||||
m_dsb->Stop();
|
||||
m_dsb->Release();
|
||||
m_dsb = 0;
|
||||
}
|
||||
if (m_ds) {
|
||||
m_ds->Release();
|
||||
|
@ -187,78 +273,224 @@ void DSound::cleanup()
|
|||
::CoUninitialize();
|
||||
}
|
||||
|
||||
SoundChan::SoundChan(const String &tone)
|
||||
: Channel(__plugin)
|
||||
void DSoundPlay::put(const DataBlock& data)
|
||||
{
|
||||
Debug(DebugAll,"ToneChan::ToneChan(\"\") [%p]",this);
|
||||
|
||||
DSBUFFERDESC dsbdesc;
|
||||
ZeroMemory(&dsbdesc, sizeof(DSBUFFERDESC));
|
||||
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
|
||||
dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
|
||||
if FAILED(__plugin.dsound()->CreateSoundBuffer(&dsbdesc, &m_dsb, NULL))
|
||||
return;
|
||||
/* ToneSource *t = ToneSource::getTone(tone);
|
||||
if (t) {
|
||||
setSource(t);
|
||||
t->deref();
|
||||
}
|
||||
if (!m_dsb)
|
||||
return;
|
||||
lock();
|
||||
if (m_buf.length() + data.length() <= MAX_SIZE)
|
||||
m_buf += data;
|
||||
#ifdef XDEBUG
|
||||
else
|
||||
Debug(DebugWarn,"No source tone '%s' in ToneChan [%p]",tone.c_str(),this);
|
||||
*/
|
||||
Debug(DebugAll,"DSoundPlay skipped %u bytes, buffer is full",data.length());
|
||||
#endif
|
||||
unlock();
|
||||
}
|
||||
|
||||
SoundChan::~SoundChan()
|
||||
DSoundRec::DSoundRec(DSoundSource* owner, LPGUID device)
|
||||
: Thread("DirectSound Rec"),
|
||||
m_owner(owner), m_device(device), m_ds(0), m_dsb(0)
|
||||
{
|
||||
Debug(DebugAll,"SoundChan::~SoundChan() [%p]",this);
|
||||
}
|
||||
|
||||
DSoundRec::~DSoundRec()
|
||||
{
|
||||
if (m_owner)
|
||||
m_owner->m_dsound = 0;
|
||||
}
|
||||
|
||||
bool DSoundRec::init()
|
||||
{
|
||||
HRESULT hr;
|
||||
if (FAILED(hr = ::CoInitializeEx(NULL,COINIT_MULTITHREADED))) {
|
||||
Debug(DebugGoOn,"Could not initialize the COM library, code 0x%X",hr);
|
||||
return false;
|
||||
}
|
||||
if (FAILED(hr = ::CoCreateInstance(CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER,
|
||||
IID_IDirectSoundCapture, (void**)&m_ds)) || !m_ds) {
|
||||
Debug(DebugGoOn,"Could not create the DirectSoundCapture object, code 0x%X",hr);
|
||||
return false;
|
||||
}
|
||||
if (FAILED(hr = m_ds->Initialize(m_device))) {
|
||||
Debug(DebugGoOn,"Could not initialize the DirectSoundCapture object, code 0x%X",hr);
|
||||
return false;
|
||||
}
|
||||
WAVEFORMATEX fmt;
|
||||
fmt.wFormatTag = WAVE_FORMAT_PCM;
|
||||
fmt.nChannels = 1;
|
||||
fmt.nSamplesPerSec = 8000;
|
||||
fmt.nAvgBytesPerSec = 16000;
|
||||
fmt.nBlockAlign = 2;
|
||||
fmt.wBitsPerSample = 16;
|
||||
fmt.cbSize = 0;
|
||||
DSCBUFFERDESC bdesc;
|
||||
ZeroMemory(&bdesc, sizeof(bdesc));
|
||||
bdesc.dwSize = sizeof(bdesc);
|
||||
bdesc.dwFlags = DSCBCAPS_WAVEMAPPED;
|
||||
bdesc.dwBufferBytes = BUF_SIZE;
|
||||
bdesc.lpwfxFormat = &fmt;
|
||||
if (FAILED(hr = m_ds->CreateCaptureBuffer(&bdesc, &m_dsb, NULL)) || !m_dsb) {
|
||||
Debug(DebugGoOn,"Could not create the DirectSoundCapture buffer, code 0x%X",hr);
|
||||
return false;
|
||||
}
|
||||
if (FAILED(hr = m_dsb->GetFormat(&fmt,sizeof(fmt),0))) {
|
||||
Debug(DebugGoOn,"Could not get the DirectSoundCapture buffer format, code 0x%X",hr);
|
||||
return false;
|
||||
}
|
||||
if ((fmt.wFormatTag != WAVE_FORMAT_PCM) ||
|
||||
(fmt.nChannels != 1) ||
|
||||
(fmt.nSamplesPerSec != 8000) ||
|
||||
(fmt.wBitsPerSample != 16)) {
|
||||
Debug(DebugGoOn,"DirectSoundCapture does not support 8000Hz 16bit mono PCM format, "
|
||||
"got fmt=%u, chans=%d samp=%d size=%u",
|
||||
fmt.wFormatTag,fmt.nChannels,fmt.nSamplesPerSec,fmt.wBitsPerSample);
|
||||
return false;
|
||||
}
|
||||
if (FAILED(hr = m_dsb->Start(DSCBSTART_LOOPING))) {
|
||||
Debug(DebugGoOn,"Could not record to the DirectSoundCapture buffer, code 0x%X",hr);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DSoundRec::run()
|
||||
{
|
||||
if (!init())
|
||||
return;
|
||||
if (m_owner)
|
||||
m_owner->m_dsound = this;
|
||||
Debug(DebugInfo,"DSoundRec is initialized and running");
|
||||
while (m_owner) {
|
||||
msleep(1,true);
|
||||
if (m_dsb) {
|
||||
void* buf = 0;
|
||||
DWORD len = 0;
|
||||
if (FAILED(m_dsb->Lock(0,CHUNK_SIZE,&buf,&len,0,0,0)))
|
||||
continue;
|
||||
DataBlock data(buf,len);
|
||||
m_dsb->Unlock(buf,len,0,0);
|
||||
if (m_owner)
|
||||
m_owner->Forward(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DSoundRec::cleanup()
|
||||
{
|
||||
Debug(DebugInfo,"DSoundRec cleaning up");
|
||||
if (m_dsb) {
|
||||
m_dsb->Stop();
|
||||
m_dsb->Release();
|
||||
m_dsb = 0;
|
||||
}
|
||||
if (m_ds) {
|
||||
m_ds->Release();
|
||||
m_ds = 0;
|
||||
}
|
||||
::CoUninitialize();
|
||||
}
|
||||
|
||||
DSoundSource::DSoundSource()
|
||||
: m_dsound(0)
|
||||
{
|
||||
DSoundRec* ds = new DSoundRec(this);
|
||||
ds->startup();
|
||||
}
|
||||
|
||||
DSoundSource::~DSoundSource()
|
||||
{
|
||||
if (m_dsound)
|
||||
m_dsound->terminate();
|
||||
}
|
||||
|
||||
DSoundConsumer::DSoundConsumer()
|
||||
: m_dsound(0)
|
||||
{
|
||||
DSoundPlay* ds = new DSoundPlay(this);
|
||||
ds->startup();
|
||||
}
|
||||
|
||||
DSoundConsumer::~DSoundConsumer()
|
||||
{
|
||||
if (m_dsound)
|
||||
m_dsound->terminate();
|
||||
}
|
||||
|
||||
void DSoundConsumer::Consume(const DataBlock &data, unsigned long timeDelta)
|
||||
{
|
||||
if (m_dsound)
|
||||
m_dsound->put(data);
|
||||
}
|
||||
|
||||
DSoundChan::DSoundChan()
|
||||
: Channel(__plugin)
|
||||
{
|
||||
Debug(DebugAll,"DSoundChan::DSoundChan() [%p]",this);
|
||||
|
||||
setSource(new DSoundSource);
|
||||
getSource()->deref();
|
||||
setConsumer(new DSoundConsumer);
|
||||
getConsumer()->deref();
|
||||
Thread::msleep(50);
|
||||
}
|
||||
|
||||
DSoundChan::~DSoundChan()
|
||||
{
|
||||
Debug(DebugAll,"DSoundChan::~DSoundChan() [%p]",this);
|
||||
}
|
||||
|
||||
bool AttachHandler::received(Message &msg)
|
||||
{
|
||||
return TRUE;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SoundDriver::msgExecute(Message& msg, String& dest)
|
||||
{
|
||||
/*
|
||||
Channel *dd = static_cast<Channel*>(msg.userData());
|
||||
if (dd) {
|
||||
ToneChan *tc = new ToneChan(dest);
|
||||
if (dd->connect(tc))
|
||||
tc->deref();
|
||||
CallEndpoint* ch = static_cast<CallEndpoint*>(msg.userData());
|
||||
if (ch) {
|
||||
DSoundChan *ds = new DSoundChan;
|
||||
if (ch->connect(ds))
|
||||
ds->deref();
|
||||
else {
|
||||
tc->destruct();
|
||||
ds->destruct();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const char *targ = msg.getValue("target");
|
||||
if (!targ) {
|
||||
Debug(DebugWarn,"Tone outgoing call with no target!");
|
||||
return false;
|
||||
}
|
||||
Message m("call.route");
|
||||
m.addParam("module","tone");
|
||||
m.addParam("caller",dest);
|
||||
m.addParam("called",targ);
|
||||
if (Engine::dispatch(m)) {
|
||||
m = "call.execute";
|
||||
m.addParam("callto",m.retValue());
|
||||
m.retValue().clear();
|
||||
ToneChan *tc = new ToneChan(dest);
|
||||
m.setParam("targetid",tc->id());
|
||||
m.userData(tc);
|
||||
if (Engine::dispatch(m)) {
|
||||
tc->deref();
|
||||
return true;
|
||||
m.addParam("module",name());
|
||||
String callto(msg.getValue("direct"));
|
||||
if (callto.null()) {
|
||||
const char *targ = msg.getValue("target");
|
||||
if (!targ) {
|
||||
Debug(DebugWarn,"DSound outgoing call with no target!");
|
||||
return false;
|
||||
}
|
||||
Debug(DebugWarn,"Tone outgoing call not accepted!");
|
||||
tc->destruct();
|
||||
callto = msg.getValue("caller");
|
||||
if (callto.null())
|
||||
callto << prefix() << dest;
|
||||
m.addParam("called",targ);
|
||||
m.addParam("caller",callto);
|
||||
if (!Engine::dispatch(m)) {
|
||||
Debug(DebugWarn,"DSound outgoing call but no route!");
|
||||
return false;
|
||||
}
|
||||
callto = m.retValue();
|
||||
m.retValue().clear();
|
||||
}
|
||||
else
|
||||
Debug(DebugWarn,"Tone outgoing call but no route!");
|
||||
m = "call.execute";
|
||||
m.addParam("callto",callto);
|
||||
DSoundChan *ds = new DSoundChan;
|
||||
m.setParam("targetid",ds->id());
|
||||
m.userData(ds);
|
||||
if (Engine::dispatch(m)) {
|
||||
ds->deref();
|
||||
return true;
|
||||
}
|
||||
Debug(DebugWarn,"DSound outgoing call not accepted!");
|
||||
ds->destruct();
|
||||
return false;
|
||||
}*/
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -273,7 +505,8 @@ void SoundDriver::statusParams(String& str)
|
|||
}
|
||||
|
||||
SoundDriver::SoundDriver()
|
||||
: Driver("dsound","misc"), m_dsound(0), m_handler(0)
|
||||
: Driver("dsound","misc"),
|
||||
m_handler(0)
|
||||
{
|
||||
Output("Loaded module DirectSound");
|
||||
}
|
||||
|
@ -287,10 +520,6 @@ SoundDriver::~SoundDriver()
|
|||
void SoundDriver::initialize()
|
||||
{
|
||||
Output("Initializing module DirectSound");
|
||||
if (!m_dsound) {
|
||||
m_dsound = new DSound;
|
||||
m_dsound->startup();
|
||||
}
|
||||
setup(0,true); // no need to install notifications
|
||||
Driver::initialize();
|
||||
if (!m_handler) {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* moh.cpp
|
||||
* This file is part of the YATE Project http://YATE.null.ro
|
||||
*
|
||||
* Music (on hold) generator
|
||||
* On hold (music) generator
|
||||
*
|
||||
* Yet Another Telephony Engine - a fully featured software PBX and IVR
|
||||
* Copyright (C) 2004, 2005 Null Team
|
||||
|
@ -345,12 +345,12 @@ bool AttachHandler::received(Message &msg)
|
|||
if (!src.matches(r))
|
||||
return false;
|
||||
src = src.matchString(1);
|
||||
DataEndpoint *dd = static_cast<DataEndpoint *>(msg.userData());
|
||||
if (dd) {
|
||||
CallEndpoint *ch = static_cast<CallEndpoint *>(msg.userData());
|
||||
if (ch) {
|
||||
Lock lock(mutex);
|
||||
MOHSource *t = MOHSource::getSource(src);
|
||||
if (t) {
|
||||
dd->setSource(t);
|
||||
ch->setSource(t);
|
||||
t->deref();
|
||||
// Let the message flow if it wants to attach a consumer too
|
||||
return !msg.getValue("consumer");
|
||||
|
|
|
@ -297,17 +297,17 @@ bool AttachHandler::received(Message &msg)
|
|||
if (!src.matches(r))
|
||||
return false;
|
||||
src = src.matchString(1);
|
||||
DataEndpoint *dd = static_cast<DataEndpoint *>(msg.userData());
|
||||
if (dd) {
|
||||
CallEndpoint *ch = static_cast<CallEndpoint *>(msg.userData());
|
||||
if (ch) {
|
||||
Lock lock(__plugin);
|
||||
ToneSource *t = ToneSource::getTone(src);
|
||||
if (t) {
|
||||
dd->setSource(t);
|
||||
ch->setSource(t);
|
||||
t->deref();
|
||||
// Let the message flow if it wants to attach a consumer too
|
||||
return !msg.getValue("consumer");
|
||||
}
|
||||
Debug(DebugWarn,"No source tone '%s' could be attached to [%p]",src.c_str(),dd);
|
||||
Debug(DebugWarn,"No source tone '%s' could be attached to [%p]",src.c_str(),ch);
|
||||
}
|
||||
else
|
||||
Debug(DebugWarn,"Tone '%s' attach request with no data channel!",src.c_str());
|
||||
|
|
|
@ -35,7 +35,7 @@ using namespace TelEngine;
|
|||
class WaveSource : public ThreadedSource
|
||||
{
|
||||
public:
|
||||
WaveSource(const String& file, Channel* chan, bool autoclose = true);
|
||||
WaveSource(const String& file, CallEndpoint* chan, bool autoclose = true);
|
||||
~WaveSource();
|
||||
virtual void run();
|
||||
virtual void cleanup();
|
||||
|
@ -44,7 +44,7 @@ public:
|
|||
private:
|
||||
void detectAuFormat();
|
||||
void detectWavFormat();
|
||||
Channel* m_chan;
|
||||
CallEndpoint* m_chan;
|
||||
DataBlock m_data;
|
||||
int m_fd;
|
||||
bool m_swap;
|
||||
|
@ -58,13 +58,13 @@ private:
|
|||
class WaveConsumer : public DataConsumer
|
||||
{
|
||||
public:
|
||||
WaveConsumer(const String& file, Channel* chan = 0, unsigned maxlen = 0);
|
||||
WaveConsumer(const String& file, CallEndpoint* chan = 0, unsigned maxlen = 0);
|
||||
~WaveConsumer();
|
||||
virtual void Consume(const DataBlock& data, unsigned long timeDelta);
|
||||
inline void setNotify(const String& id)
|
||||
{ m_id = id; }
|
||||
private:
|
||||
Channel* m_chan;
|
||||
CallEndpoint* m_chan;
|
||||
int m_fd;
|
||||
unsigned m_total;
|
||||
unsigned m_maxlen;
|
||||
|
@ -82,11 +82,11 @@ public:
|
|||
class ConsDisconnector : public Thread
|
||||
{
|
||||
public:
|
||||
ConsDisconnector(Channel* chan, const String& id)
|
||||
ConsDisconnector(CallEndpoint* chan, const String& id)
|
||||
: m_chan(chan), m_id(id) { }
|
||||
virtual void run();
|
||||
private:
|
||||
Channel* m_chan;
|
||||
CallEndpoint* m_chan;
|
||||
String m_id;
|
||||
};
|
||||
|
||||
|
@ -109,7 +109,7 @@ private:
|
|||
|
||||
INIT_PLUGIN(WaveFileDriver);
|
||||
|
||||
WaveSource::WaveSource(const String& file, Channel* chan, bool autoclose)
|
||||
WaveSource::WaveSource(const String& file, CallEndpoint* chan, bool autoclose)
|
||||
: m_chan(chan), m_fd(-1), m_swap(false), m_brate(16000),
|
||||
m_total(0), m_time(0), m_autoclose(autoclose)
|
||||
{
|
||||
|
@ -259,7 +259,7 @@ void WaveSource::cleanup()
|
|||
m_chan->disconnect("eof");
|
||||
}
|
||||
|
||||
WaveConsumer::WaveConsumer(const String& file, Channel* chan, unsigned maxlen)
|
||||
WaveConsumer::WaveConsumer(const String& file, CallEndpoint* chan, unsigned maxlen)
|
||||
: m_chan(chan), m_fd(-1), m_total(0), m_maxlen(maxlen), m_time(0)
|
||||
{
|
||||
Debug(&__plugin,DebugAll,"WaveConsumer::WaveConsumer(\"%s\",%p,%u) [%p]",
|
||||
|
@ -403,7 +403,7 @@ bool AttachHandler::received(Message &msg)
|
|||
|
||||
String ml(msg.getValue("maxlen"));
|
||||
unsigned maxlen = ml.toInteger(0);
|
||||
Channel *ch = static_cast<Channel*>(msg.userData());
|
||||
CallEndpoint *ch = static_cast<CallEndpoint*>(msg.userData());
|
||||
if (!ch) {
|
||||
if (!src.null())
|
||||
Debug(DebugWarn,"Wave source '%s' attach request with no data channel!",src.c_str());
|
||||
|
|
|
@ -426,9 +426,9 @@ void YateSIPEndPoint::run()
|
|||
/* Watch stdin (fd 0) to see when it has input. */
|
||||
for (;;)
|
||||
{
|
||||
/* Wait up to 20000 microseconds. */
|
||||
/* Wait up to 5000 microseconds. */
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 20000;
|
||||
tv.tv_usec = 5000;
|
||||
bool ok = false;
|
||||
m_sock->select(&ok,0,0,&tv);
|
||||
if (ok)
|
||||
|
@ -450,6 +450,8 @@ void YateSIPEndPoint::run()
|
|||
Debug(DebugInfo,"Received short SIP message of %d bytes",res);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
Thread::check();
|
||||
// m_engine->process();
|
||||
SIPEvent* e = m_engine->getEvent();
|
||||
// hack: use a loop so we can use break and continue
|
||||
|
|
|
@ -43,7 +43,7 @@ RSC=rc.exe
|
|||
# PROP Ignore_Export_Lib 1
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_DSOUNDCHAN_EXPORTS" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX- /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_DSOUNDCHAN_EXPORTS" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_DSOUNDCHAN_EXPORTS" /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
|
@ -53,7 +53,7 @@ BSC32=bscmake.exe
|
|||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||
# ADD LINK32 kernel32.lib ole32.lib /nologo /dll /machine:I386 /out:"Release/dsoundchan.yate"
|
||||
# ADD LINK32 kernel32.lib user32.lib ole32.lib /nologo /dll /machine:I386 /out:"Release/dsoundchan.yate"
|
||||
|
||||
!ELSEIF "$(CFG)" == "_dsoundchan - Win32 Debug"
|
||||
|
||||
|
@ -68,8 +68,8 @@ LINK32=link.exe
|
|||
# PROP Intermediate_Dir "Debug\modules"
|
||||
# PROP Ignore_Export_Lib 1
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_DSOUNDCHAN_EXPORTS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX- /Zi /Od /I "." /I ".." /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /FD /GZ /c
|
||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_DSOUNDCHAN_EXPORTS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /Zi /Od /I "." /I ".." /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /FD /GZ /c
|
||||
# SUBTRACT CPP /YX
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
|
@ -80,7 +80,7 @@ BSC32=bscmake.exe
|
|||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 ole32.lib kernel32.lib /nologo /dll /incremental:no /debug /machine:I386 /out:"Debug/dsoundchan.yate" /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib ole32.lib /nologo /dll /incremental:no /debug /machine:I386 /out:"Debug/dsoundchan.yate" /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
|
|
Loading…
Reference in New Issue