Added basic sample rate control in the DirectSound module, removed chunk and buffer settings as they must be computed from rate.
git-svn-id: http://voip.null.ro/svn/yate@3164 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
42d4dded8f
commit
1bc096fa99
|
@ -4,17 +4,5 @@
|
||||||
; primary: boolean: Use the primary playback sound buffer instead of a secondary
|
; primary: boolean: Use the primary playback sound buffer instead of a secondary
|
||||||
;primary=yes
|
;primary=yes
|
||||||
|
|
||||||
; There is not much tweaking possible with these settings.
|
; rate: int: Default sampling rate used, can be 8000, 16000, 32000
|
||||||
; Some sanity is enforced in code but actual working limits depend on the sound drivers
|
;rate=8000
|
||||||
|
|
||||||
; chunk: int: Number of bytes in the chunk of samples transferred at once
|
|
||||||
;chunk=320
|
|
||||||
|
|
||||||
; minsize: int: Number of bytes in buffer before we start playing back
|
|
||||||
;minsize=640
|
|
||||||
|
|
||||||
; bufsize: int: Bytes allocated for secondary playback and the record buffers
|
|
||||||
;bufsize=1280
|
|
||||||
|
|
||||||
; maxsize: int: Number of buffered bytes when we start dropping chunks
|
|
||||||
;maxsize=1600
|
|
||||||
|
|
|
@ -43,18 +43,14 @@ namespace { // anonymous
|
||||||
// we should use the primary sound buffer else we will lose sound while we have no input focus
|
// we should use the primary sound buffer else we will lose sound while we have no input focus
|
||||||
static bool s_primary = true;
|
static bool s_primary = true;
|
||||||
|
|
||||||
// 20ms minimum chunk, 100ms buffer
|
// default sampling rate
|
||||||
#define CHUNK_SIZE 320
|
static int s_rate = 8000;
|
||||||
static unsigned int s_chunk = CHUNK_SIZE;
|
|
||||||
static unsigned int s_minsize = 2*CHUNK_SIZE;
|
|
||||||
static unsigned int s_bufsize = 4*CHUNK_SIZE;
|
|
||||||
static unsigned int s_maxsize = 5*CHUNK_SIZE;
|
|
||||||
|
|
||||||
class DSoundSource : public DataSource
|
class DSoundSource : public DataSource
|
||||||
{
|
{
|
||||||
friend class DSoundRec;
|
friend class DSoundRec;
|
||||||
public:
|
public:
|
||||||
DSoundSource();
|
DSoundSource(int rate = 8000);
|
||||||
~DSoundSource();
|
~DSoundSource();
|
||||||
bool control(NamedList& msg);
|
bool control(NamedList& msg);
|
||||||
private:
|
private:
|
||||||
|
@ -65,7 +61,7 @@ class DSoundConsumer : public DataConsumer
|
||||||
{
|
{
|
||||||
friend class DSoundPlay;
|
friend class DSoundPlay;
|
||||||
public:
|
public:
|
||||||
DSoundConsumer(bool stereo = false);
|
DSoundConsumer(int rate = 8000, bool stereo = false);
|
||||||
~DSoundConsumer();
|
~DSoundConsumer();
|
||||||
virtual unsigned long Consume(const DataBlock &data, unsigned long tStamp, unsigned long flags);
|
virtual unsigned long Consume(const DataBlock &data, unsigned long tStamp, unsigned long flags);
|
||||||
bool control(NamedList& msg);
|
bool control(NamedList& msg);
|
||||||
|
@ -78,7 +74,7 @@ private:
|
||||||
class DSoundPlay : public Thread, public Mutex
|
class DSoundPlay : public Thread, public Mutex
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DSoundPlay(DSoundConsumer* owner, LPGUID device = 0);
|
DSoundPlay(DSoundConsumer* owner, DWORD rate, LPGUID device = 0);
|
||||||
virtual ~DSoundPlay();
|
virtual ~DSoundPlay();
|
||||||
virtual void run();
|
virtual void run();
|
||||||
virtual void cleanup();
|
virtual void cleanup();
|
||||||
|
@ -93,10 +89,12 @@ public:
|
||||||
bool control(NamedList& msg);
|
bool control(NamedList& msg);
|
||||||
private:
|
private:
|
||||||
DSoundConsumer* m_owner;
|
DSoundConsumer* m_owner;
|
||||||
|
DWORD m_rate;
|
||||||
LPGUID m_device;
|
LPGUID m_device;
|
||||||
LPDIRECTSOUND m_ds;
|
LPDIRECTSOUND m_ds;
|
||||||
LPDIRECTSOUNDBUFFER m_dsb;
|
LPDIRECTSOUNDBUFFER m_dsb;
|
||||||
DWORD m_buffSize;
|
DWORD m_buffSize;
|
||||||
|
DWORD m_chunk;
|
||||||
DataBlock m_buf;
|
DataBlock m_buf;
|
||||||
u_int64_t m_start;
|
u_int64_t m_start;
|
||||||
u_int64_t m_total;
|
u_int64_t m_total;
|
||||||
|
@ -106,7 +104,7 @@ private:
|
||||||
class DSoundRec : public Thread
|
class DSoundRec : public Thread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DSoundRec(DSoundSource* owner, LPGUID device = 0);
|
DSoundRec(DSoundSource* owner, DWORD rate, LPGUID device = 0);
|
||||||
virtual ~DSoundRec();
|
virtual ~DSoundRec();
|
||||||
virtual void run();
|
virtual void run();
|
||||||
virtual void cleanup();
|
virtual void cleanup();
|
||||||
|
@ -120,6 +118,7 @@ public:
|
||||||
bool control(NamedList& msg);
|
bool control(NamedList& msg);
|
||||||
private:
|
private:
|
||||||
DSoundSource* m_owner;
|
DSoundSource* m_owner;
|
||||||
|
DWORD m_rate;
|
||||||
LPGUID m_device;
|
LPGUID m_device;
|
||||||
LPDIRECTSOUNDCAPTURE m_ds;
|
LPDIRECTSOUNDCAPTURE m_ds;
|
||||||
LPDIRECTSOUNDCAPTUREBUFFER m_dsb;
|
LPDIRECTSOUNDCAPTUREBUFFER m_dsb;
|
||||||
|
@ -133,7 +132,7 @@ private:
|
||||||
class DSoundChan : public Channel
|
class DSoundChan : public Channel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DSoundChan();
|
DSoundChan(int rate = 8000);
|
||||||
virtual ~DSoundChan();
|
virtual ~DSoundChan();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -162,10 +161,10 @@ private:
|
||||||
INIT_PLUGIN(SoundDriver);
|
INIT_PLUGIN(SoundDriver);
|
||||||
|
|
||||||
|
|
||||||
DSoundPlay::DSoundPlay(DSoundConsumer* owner, LPGUID device)
|
DSoundPlay::DSoundPlay(DSoundConsumer* owner, DWORD rate, LPGUID device)
|
||||||
: Thread("DirectSound Play",High), Mutex(false,"DSoundPlay"),
|
: Thread("DirectSound Play",High), Mutex(false,"DSoundPlay"),
|
||||||
m_owner(0), m_device(device), m_ds(0), m_dsb(0),
|
m_owner(0), m_rate(rate), m_device(device), m_ds(0), m_dsb(0),
|
||||||
m_buffSize(0), m_start(0), m_total(0)
|
m_buffSize(0), m_chunk(320), m_start(0), m_total(0)
|
||||||
{
|
{
|
||||||
if (owner && owner->ref())
|
if (owner && owner->ref())
|
||||||
m_owner = owner;
|
m_owner = owner;
|
||||||
|
@ -205,18 +204,19 @@ bool DSoundPlay::init()
|
||||||
|
|
||||||
// Set channel number depending data
|
// Set channel number depending data
|
||||||
WORD nChannels = 1;
|
WORD nChannels = 1;
|
||||||
DWORD nAvgBytesPerSec = 16000; // nSamplesPerSec * nBlockAlign.
|
DWORD nAvgBytesPerSec = 2 * m_rate; // nSamplesPerSec * nBlockAlign.
|
||||||
WORD nBlockAlign = 2; // nChannels * wBitsPerSample / 8
|
WORD nBlockAlign = 2; // nChannels * wBitsPerSample / 8
|
||||||
if (m_owner && m_owner->m_stereo) {
|
if (m_owner && m_owner->m_stereo) {
|
||||||
nChannels = 2;
|
nChannels = 2;
|
||||||
nAvgBytesPerSec = 32000;
|
nAvgBytesPerSec = 4 * m_rate;
|
||||||
nBlockAlign = 4;
|
nBlockAlign = 4;
|
||||||
}
|
}
|
||||||
|
m_chunk = nChannels * m_rate / 25; // 20ms of 2-byte samples
|
||||||
|
|
||||||
WAVEFORMATEX fmt;
|
WAVEFORMATEX fmt;
|
||||||
fmt.wFormatTag = WAVE_FORMAT_PCM;
|
fmt.wFormatTag = WAVE_FORMAT_PCM;
|
||||||
fmt.nChannels = nChannels;
|
fmt.nChannels = nChannels;
|
||||||
fmt.nSamplesPerSec = 8000;
|
fmt.nSamplesPerSec = m_rate;
|
||||||
fmt.nAvgBytesPerSec = nAvgBytesPerSec;
|
fmt.nAvgBytesPerSec = nAvgBytesPerSec;
|
||||||
fmt.nBlockAlign = nBlockAlign;
|
fmt.nBlockAlign = nBlockAlign;
|
||||||
fmt.wBitsPerSample = 16;
|
fmt.wBitsPerSample = 16;
|
||||||
|
@ -230,7 +230,7 @@ bool DSoundPlay::init()
|
||||||
else {
|
else {
|
||||||
bdesc.dwFlags |= DSBCAPS_GLOBALFOCUS;
|
bdesc.dwFlags |= DSBCAPS_GLOBALFOCUS;
|
||||||
// we have to set format when creating secondary buffers
|
// we have to set format when creating secondary buffers
|
||||||
bdesc.dwBufferBytes = s_bufsize;
|
bdesc.dwBufferBytes = 4*m_chunk;
|
||||||
bdesc.lpwfxFormat = &fmt;
|
bdesc.lpwfxFormat = &fmt;
|
||||||
}
|
}
|
||||||
if (FAILED(hr = m_ds->CreateSoundBuffer(&bdesc, &m_dsb, NULL)) || !m_dsb) {
|
if (FAILED(hr = m_ds->CreateSoundBuffer(&bdesc, &m_dsb, NULL)) || !m_dsb) {
|
||||||
|
@ -248,10 +248,10 @@ bool DSoundPlay::init()
|
||||||
}
|
}
|
||||||
if ((fmt.wFormatTag != WAVE_FORMAT_PCM) ||
|
if ((fmt.wFormatTag != WAVE_FORMAT_PCM) ||
|
||||||
(fmt.nChannels != nChannels) ||
|
(fmt.nChannels != nChannels) ||
|
||||||
(fmt.nSamplesPerSec != 8000) ||
|
(fmt.nSamplesPerSec != m_rate) ||
|
||||||
(fmt.wBitsPerSample != 16)) {
|
(fmt.wBitsPerSample != 16)) {
|
||||||
Debug(DebugGoOn,"DirectSound does not support 8000Hz 16bit %s PCM format, "
|
Debug(DebugGoOn,"DirectSound does not support %dHz 16bit %s PCM format, "
|
||||||
"got fmt=%u, chans=%d samp=%d size=%u",nChannels == 1 ? "mono" : "stereo",
|
"got fmt=%u, chans=%d samp=%d size=%u",m_rate,nChannels == 1 ? "mono" : "stereo",
|
||||||
fmt.wFormatTag,fmt.nChannels,fmt.nSamplesPerSec,fmt.wBitsPerSample);
|
fmt.wFormatTag,fmt.nChannels,fmt.nSamplesPerSec,fmt.wBitsPerSample);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -283,12 +283,12 @@ void DSoundPlay::run()
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
DWORD writeOffs = 0;
|
DWORD writeOffs = 0;
|
||||||
DWORD margin = s_chunk/4;
|
DWORD margin = m_chunk/4;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
while (m_owner->refcount() > 1) {
|
while (m_owner->refcount() > 1) {
|
||||||
msleep(1,true);
|
msleep(1,true);
|
||||||
if (first) {
|
if (first) {
|
||||||
if ((m_buf.length() < s_minsize) || !m_dsb)
|
if ((m_buf.length() < 2*m_chunk) || !m_dsb)
|
||||||
continue;
|
continue;
|
||||||
first = false;
|
first = false;
|
||||||
m_dsb->GetCurrentPosition(NULL,&writeOffs);
|
m_dsb->GetCurrentPosition(NULL,&writeOffs);
|
||||||
|
@ -316,10 +316,10 @@ void DSoundPlay::run()
|
||||||
writeOffs,adjOffs,playPos,writePos);
|
writeOffs,adjOffs,playPos,writePos);
|
||||||
writeOffs = adjOffs;
|
writeOffs = adjOffs;
|
||||||
}
|
}
|
||||||
bool hasData = (m_buf.length() >= s_chunk);
|
bool hasData = (m_buf.length() >= m_chunk);
|
||||||
if (!(adjust || hasData)) {
|
if (!(adjust || hasData)) {
|
||||||
// don't fill the buffer if we still have at least one chunk until underflow
|
// don't fill the buffer if we still have at least one chunk until underflow
|
||||||
if ((m_buffSize + writeOffs - writePos) % m_buffSize >= s_chunk)
|
if ((m_buffSize + writeOffs - writePos) % m_buffSize >= m_chunk)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
void* buf = 0;
|
void* buf = 0;
|
||||||
|
@ -327,13 +327,13 @@ void DSoundPlay::run()
|
||||||
DWORD len = 0;
|
DWORD len = 0;
|
||||||
DWORD len2 = 0;
|
DWORD len2 = 0;
|
||||||
// locking will prevent us to skip ahead and overwrite the play position
|
// locking will prevent us to skip ahead and overwrite the play position
|
||||||
HRESULT hr = m_dsb->Lock(writeOffs,s_chunk,&buf,&len,&buf2,&len2,0);
|
HRESULT hr = m_dsb->Lock(writeOffs,m_chunk,&buf,&len,&buf2,&len2,0);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
writeOffs = 0;
|
writeOffs = 0;
|
||||||
if ((hr == DSERR_BUFFERLOST) && SUCCEEDED(m_dsb->Restore())) {
|
if ((hr == DSERR_BUFFERLOST) && SUCCEEDED(m_dsb->Restore())) {
|
||||||
m_dsb->Play(0,0,DSBPLAY_LOOPING);
|
m_dsb->Play(0,0,DSBPLAY_LOOPING);
|
||||||
m_dsb->GetCurrentPosition(NULL,&writeOffs);
|
m_dsb->GetCurrentPosition(NULL,&writeOffs);
|
||||||
writeOffs = (s_chunk/4 + writeOffs) % m_buffSize;
|
writeOffs = (margin + writeOffs) % m_buffSize;
|
||||||
Debug(&__plugin,DebugAll,"DirectSound buffer lost and restored, playing at %u",
|
Debug(&__plugin,DebugAll,"DirectSound buffer lost and restored, playing at %u",
|
||||||
writeOffs);
|
writeOffs);
|
||||||
}
|
}
|
||||||
|
@ -356,15 +356,15 @@ void DSoundPlay::run()
|
||||||
::memset(buf2,0,len2);
|
::memset(buf2,0,len2);
|
||||||
}
|
}
|
||||||
m_dsb->Unlock(buf,len,buf2,len2);
|
m_dsb->Unlock(buf,len,buf2,len2);
|
||||||
m_total += s_chunk;
|
m_total += m_chunk;
|
||||||
m_buf.cut(-(int)s_chunk);
|
m_buf.cut(-(int)m_chunk);
|
||||||
unlock();
|
unlock();
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (!hasData)
|
if (!hasData)
|
||||||
Debug(&__plugin,DebugInfo,"Underflow, filled %u bytes at %u, p=%u w=%u",
|
Debug(&__plugin,DebugInfo,"Underflow, filled %u bytes at %u, p=%u w=%u",
|
||||||
s_chunk,writeOffs,playPos,writePos);
|
m_chunk,writeOffs,playPos,writePos);
|
||||||
#endif
|
#endif
|
||||||
writeOffs += s_chunk;
|
writeOffs += m_chunk;
|
||||||
if (writeOffs >= m_buffSize)
|
if (writeOffs >= m_buffSize)
|
||||||
writeOffs -= m_buffSize;
|
writeOffs -= m_buffSize;
|
||||||
XDebug(&__plugin,DebugAll,"Locked %p,%d %p,%d",buf,len,buf2,len2);
|
XDebug(&__plugin,DebugAll,"Locked %p,%d %p,%d",buf,len,buf2,len2);
|
||||||
|
@ -420,7 +420,7 @@ void DSoundPlay::put(const DataBlock& data)
|
||||||
if (!m_dsb)
|
if (!m_dsb)
|
||||||
return;
|
return;
|
||||||
lock();
|
lock();
|
||||||
if (m_buf.length() + data.length() <= s_maxsize)
|
if (m_buf.length() + data.length() <= m_buffSize + m_chunk)
|
||||||
m_buf += data;
|
m_buf += data;
|
||||||
else
|
else
|
||||||
Debug(&__plugin,DebugMild,"DSoundPlay skipped %u bytes, buffer is full",data.length());
|
Debug(&__plugin,DebugMild,"DSoundPlay skipped %u bytes, buffer is full",data.length());
|
||||||
|
@ -428,9 +428,9 @@ void DSoundPlay::put(const DataBlock& data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DSoundRec::DSoundRec(DSoundSource* owner, LPGUID device)
|
DSoundRec::DSoundRec(DSoundSource* owner, DWORD rate, LPGUID device)
|
||||||
: Thread("DirectSound Rec",High),
|
: Thread("DirectSound Rec",High),
|
||||||
m_owner(0), m_device(device), m_ds(0), m_dsb(0),
|
m_owner(0), m_rate(rate), m_device(device), m_ds(0), m_dsb(0),
|
||||||
m_buffSize(0), m_readPos(0), m_start(0), m_total(0), m_rshift(0)
|
m_buffSize(0), m_readPos(0), m_start(0), m_total(0), m_rshift(0)
|
||||||
{
|
{
|
||||||
if (owner && owner->ref())
|
if (owner && owner->ref())
|
||||||
|
@ -464,8 +464,8 @@ bool DSoundRec::init()
|
||||||
WAVEFORMATEX fmt;
|
WAVEFORMATEX fmt;
|
||||||
fmt.wFormatTag = WAVE_FORMAT_PCM;
|
fmt.wFormatTag = WAVE_FORMAT_PCM;
|
||||||
fmt.nChannels = 1;
|
fmt.nChannels = 1;
|
||||||
fmt.nSamplesPerSec = 8000;
|
fmt.nSamplesPerSec = m_rate;
|
||||||
fmt.nAvgBytesPerSec = 16000;
|
fmt.nAvgBytesPerSec = 2 * m_rate;
|
||||||
fmt.nBlockAlign = 2;
|
fmt.nBlockAlign = 2;
|
||||||
fmt.wBitsPerSample = 16;
|
fmt.wBitsPerSample = 16;
|
||||||
fmt.cbSize = 0;
|
fmt.cbSize = 0;
|
||||||
|
@ -473,7 +473,7 @@ bool DSoundRec::init()
|
||||||
ZeroMemory(&bdesc, sizeof(bdesc));
|
ZeroMemory(&bdesc, sizeof(bdesc));
|
||||||
bdesc.dwSize = sizeof(bdesc);
|
bdesc.dwSize = sizeof(bdesc);
|
||||||
bdesc.dwFlags = DSCBCAPS_WAVEMAPPED;
|
bdesc.dwFlags = DSCBCAPS_WAVEMAPPED;
|
||||||
bdesc.dwBufferBytes = s_bufsize;
|
bdesc.dwBufferBytes = 4 * m_rate / 25;
|
||||||
bdesc.lpwfxFormat = &fmt;
|
bdesc.lpwfxFormat = &fmt;
|
||||||
if (FAILED(hr = m_ds->CreateCaptureBuffer(&bdesc, &m_dsb, NULL)) || !m_dsb) {
|
if (FAILED(hr = m_ds->CreateCaptureBuffer(&bdesc, &m_dsb, NULL)) || !m_dsb) {
|
||||||
Debug(DebugGoOn,"Could not create the DirectSoundCapture buffer, code 0x%X",hr);
|
Debug(DebugGoOn,"Could not create the DirectSoundCapture buffer, code 0x%X",hr);
|
||||||
|
@ -485,10 +485,10 @@ bool DSoundRec::init()
|
||||||
}
|
}
|
||||||
if ((fmt.wFormatTag != WAVE_FORMAT_PCM) ||
|
if ((fmt.wFormatTag != WAVE_FORMAT_PCM) ||
|
||||||
(fmt.nChannels != 1) ||
|
(fmt.nChannels != 1) ||
|
||||||
(fmt.nSamplesPerSec != 8000) ||
|
(fmt.nSamplesPerSec != m_rate) ||
|
||||||
(fmt.wBitsPerSample != 16)) {
|
(fmt.wBitsPerSample != 16)) {
|
||||||
Debug(DebugGoOn,"DirectSoundCapture does not support 8000Hz 16bit mono PCM format, "
|
Debug(DebugGoOn,"DirectSoundCapture does not support %dHz 16bit mono PCM format, "
|
||||||
"got fmt=%u, chans=%d samp=%d size=%u",
|
"got fmt=%u, chans=%d samp=%d size=%u",m_rate,
|
||||||
fmt.wFormatTag,fmt.nChannels,fmt.nSamplesPerSec,fmt.wBitsPerSample);
|
fmt.wFormatTag,fmt.nChannels,fmt.nSamplesPerSec,fmt.wBitsPerSample);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -512,6 +512,7 @@ void DSoundRec::run()
|
||||||
if (!init())
|
if (!init())
|
||||||
return;
|
return;
|
||||||
Debug(&__plugin,DebugInfo,"DSoundRec is initialized and running");
|
Debug(&__plugin,DebugInfo,"DSoundRec is initialized and running");
|
||||||
|
DWORD chunk = m_rate / 25; // 20ms of 2-byte samples
|
||||||
m_start = Time::now();
|
m_start = Time::now();
|
||||||
if (m_owner)
|
if (m_owner)
|
||||||
m_owner->m_dsound = this;
|
m_owner->m_dsound = this;
|
||||||
|
@ -526,13 +527,13 @@ void DSoundRec::run()
|
||||||
if (pos < m_readPos)
|
if (pos < m_readPos)
|
||||||
pos += m_buffSize;
|
pos += m_buffSize;
|
||||||
pos -= m_readPos;
|
pos -= m_readPos;
|
||||||
if (pos < s_chunk)
|
if (pos < chunk)
|
||||||
continue;
|
continue;
|
||||||
void* buf = 0;
|
void* buf = 0;
|
||||||
void* buf2 = 0;
|
void* buf2 = 0;
|
||||||
DWORD len = 0;
|
DWORD len = 0;
|
||||||
DWORD len2 = 0;
|
DWORD len2 = 0;
|
||||||
if (FAILED(m_dsb->Lock(m_readPos,s_chunk,&buf,&len,&buf2,&len2,0)))
|
if (FAILED(m_dsb->Lock(m_readPos,chunk,&buf,&len,&buf2,&len2,0)))
|
||||||
continue;
|
continue;
|
||||||
DataBlock data(0,len+len2);
|
DataBlock data(0,len+len2);
|
||||||
::memcpy(data.data(),buf,len);
|
::memcpy(data.data(),buf,len);
|
||||||
|
@ -592,10 +593,12 @@ bool DSoundRec::control(TelEngine::NamedList &msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DSoundSource::DSoundSource()
|
DSoundSource::DSoundSource(int rate)
|
||||||
: m_dsound(0)
|
: m_dsound(0)
|
||||||
{
|
{
|
||||||
DSoundRec* ds = new DSoundRec(this);
|
if (rate != 8000)
|
||||||
|
m_format << "/" << rate;
|
||||||
|
DSoundRec* ds = new DSoundRec(this,rate);
|
||||||
ds->startup();
|
ds->startup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,11 +616,13 @@ bool DSoundSource::control(NamedList& msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DSoundConsumer::DSoundConsumer(bool stereo)
|
DSoundConsumer::DSoundConsumer(int rate, bool stereo)
|
||||||
: DataConsumer(stereo ? "2*slin" : "slin"),
|
: DataConsumer(stereo ? "2*slin" : "slin"),
|
||||||
m_dsound(0), m_stereo(stereo)
|
m_dsound(0), m_stereo(stereo)
|
||||||
{
|
{
|
||||||
DSoundPlay* ds = new DSoundPlay(this);
|
if (rate != 8000)
|
||||||
|
m_format << "/" << rate;
|
||||||
|
DSoundPlay* ds = new DSoundPlay(this,rate);
|
||||||
ds->startup();
|
ds->startup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -644,15 +649,15 @@ bool DSoundConsumer::control(NamedList& msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DSoundChan::DSoundChan()
|
DSoundChan::DSoundChan(int rate)
|
||||||
: Channel(__plugin)
|
: Channel(__plugin)
|
||||||
{
|
{
|
||||||
Debug(this,DebugAll,"DSoundChan::DSoundChan() [%p]",this);
|
Debug(this,DebugAll,"DSoundChan::DSoundChan(%d) [%p]",rate,this);
|
||||||
|
|
||||||
setConsumer(new DSoundConsumer);
|
setConsumer(new DSoundConsumer(rate));
|
||||||
getConsumer()->deref();
|
getConsumer()->deref();
|
||||||
Thread::msleep(50);
|
Thread::msleep(50);
|
||||||
setSource(new DSoundSource);
|
setSource(new DSoundSource(rate));
|
||||||
getSource()->deref();
|
getSource()->deref();
|
||||||
Thread::msleep(50);
|
Thread::msleep(50);
|
||||||
}
|
}
|
||||||
|
@ -693,15 +698,17 @@ bool AttachHandler::received(Message &msg)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rate = msg.getIntValue("rate",s_rate);
|
||||||
|
|
||||||
if (cons) {
|
if (cons) {
|
||||||
DSoundConsumer* c = new DSoundConsumer(msg.getBoolValue("stereo"));
|
DSoundConsumer* c = new DSoundConsumer(rate,msg.getBoolValue("stereo"));
|
||||||
dd->setConsumer(c);
|
dd->setConsumer(c);
|
||||||
c->deref();
|
c->deref();
|
||||||
Thread::msleep(50);
|
Thread::msleep(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src) {
|
if (src) {
|
||||||
DSoundSource* s = new DSoundSource;
|
DSoundSource* s = new DSoundSource(rate);
|
||||||
dd->setSource(s);
|
dd->setSource(s);
|
||||||
s->deref();
|
s->deref();
|
||||||
Thread::msleep(50);
|
Thread::msleep(50);
|
||||||
|
@ -717,7 +724,7 @@ bool SoundDriver::msgExecute(Message& msg, String& dest)
|
||||||
{
|
{
|
||||||
CallEndpoint* ch = static_cast<CallEndpoint*>(msg.userData());
|
CallEndpoint* ch = static_cast<CallEndpoint*>(msg.userData());
|
||||||
if (ch) {
|
if (ch) {
|
||||||
DSoundChan *ds = new DSoundChan;
|
DSoundChan *ds = new DSoundChan(msg.getIntValue("rate",s_rate));
|
||||||
if (ch->connect(ds,msg.getValue("reason"))) {
|
if (ch->connect(ds,msg.getValue("reason"))) {
|
||||||
msg.setParam("peerid",ds->id());
|
msg.setParam("peerid",ds->id());
|
||||||
ds->deref();
|
ds->deref();
|
||||||
|
@ -751,7 +758,7 @@ bool SoundDriver::msgExecute(Message& msg, String& dest)
|
||||||
}
|
}
|
||||||
m = "call.execute";
|
m = "call.execute";
|
||||||
m.addParam("callto",callto);
|
m.addParam("callto",callto);
|
||||||
DSoundChan *ds = new DSoundChan;
|
DSoundChan *ds = new DSoundChan(msg.getIntValue("rate",8000));
|
||||||
m.setParam("targetid",ds->id());
|
m.setParam("targetid",ds->id());
|
||||||
m.userData(ds);
|
m.userData(ds);
|
||||||
if (Engine::dispatch(m)) {
|
if (Engine::dispatch(m)) {
|
||||||
|
@ -783,33 +790,11 @@ void SoundDriver::initialize()
|
||||||
Output("Initializing module DirectSound");
|
Output("Initializing module DirectSound");
|
||||||
setup(0,true); // no need to install notifications
|
setup(0,true); // no need to install notifications
|
||||||
Driver::initialize();
|
Driver::initialize();
|
||||||
|
Configuration cfg(Engine::configFile("dsoundchan"));
|
||||||
|
s_rate = cfg.getIntValue("general","rate",8000);
|
||||||
|
// prefer primary buffer as we try to retain control of audio board
|
||||||
|
s_primary = cfg.getBoolValue("general","primary",true);
|
||||||
if (!m_handler) {
|
if (!m_handler) {
|
||||||
Configuration cfg(Engine::configFile("dsoundchan"));
|
|
||||||
s_chunk = cfg.getIntValue("general","chunk",CHUNK_SIZE);
|
|
||||||
// make sure the chunk is even sized and has some decent limits (20-50 ms)
|
|
||||||
s_chunk &= ~1;
|
|
||||||
if (s_chunk < 320)
|
|
||||||
s_chunk = 320;
|
|
||||||
if (s_chunk > 800)
|
|
||||||
s_chunk = 800;
|
|
||||||
s_minsize = cfg.getIntValue("general","minsize",2*s_chunk);
|
|
||||||
s_bufsize = cfg.getIntValue("general","bufsize",4*s_chunk);
|
|
||||||
s_maxsize = cfg.getIntValue("general","maxsize",5*s_chunk);
|
|
||||||
// the buffer MUST hold at least one chunk and about 15ms of audio - we allow 30
|
|
||||||
if (s_bufsize < s_chunk + 480)
|
|
||||||
s_bufsize = s_chunk + 480;
|
|
||||||
// also keep it under 2s and even sized
|
|
||||||
if (s_bufsize > 32000)
|
|
||||||
s_bufsize = 32000;
|
|
||||||
s_bufsize &= ~1;
|
|
||||||
// make sure playback can ever start
|
|
||||||
if (s_minsize > s_bufsize - s_chunk)
|
|
||||||
s_minsize = s_bufsize - s_chunk;
|
|
||||||
// and that we don't do stupid drops
|
|
||||||
if (s_maxsize < s_bufsize + s_chunk)
|
|
||||||
s_maxsize = s_bufsize + s_chunk;
|
|
||||||
// prefer primary buffer as we try to retain control of audio board
|
|
||||||
s_primary = cfg.getBoolValue("general","primary",true);
|
|
||||||
m_handler = new AttachHandler;
|
m_handler = new AttachHandler;
|
||||||
Engine::install(m_handler);
|
Engine::install(m_handler);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue