Added basic sample rate control in ALSA, OSS, conference and MOH.

git-svn-id: http://voip.null.ro/svn/yate@3161 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2010-03-30 15:06:50 +00:00
parent 2db4b83623
commit 44d5f77989
4 changed files with 73 additions and 47 deletions

View File

@ -77,7 +77,7 @@ private:
class AlsaDevice : public RefObject
{
public:
AlsaDevice(const String& dev, bool init=false);
AlsaDevice(const String& dev, unsigned int rate = 8000);
~AlsaDevice();
bool timePassed(void);
bool open();
@ -85,13 +85,16 @@ public:
int read(void *buffer, int frames);
inline bool closed() const
{ return m_closed; }
int m_fd;
inline unsigned int rate() const
{ return m_rate; }
private:
String m_dev;
int m_fd;
String m_dev;
String m_dev_in;
String m_dev_out;
String m_initdata;
bool m_closed;
unsigned int m_rate;
snd_pcm_t *m_handle_in;
snd_pcm_t *m_handle_out;
u_int64_t m_lastTime;
@ -100,7 +103,7 @@ private:
class AlsaChan : public CallEndpoint
{
public:
AlsaChan(const String& dev);
AlsaChan(const String& dev, unsigned int rate = 8000);
~AlsaChan();
bool init();
virtual void disconnected(bool final, const char *reason);
@ -110,9 +113,10 @@ public:
inline const String& getTarget() const
{ return m_target; }
private:
private:
String m_dev;
String m_target;
unsigned int m_rate;
};
class AlsaHandler : public MessageHandler
@ -166,7 +170,7 @@ AlsaDevice* s_dev = 0;
bool AlsaSource::init()
{
m_brate = 16000;
m_brate = 2 * m_device->rate();
m_total = 0;
start("Alsa Source",Thread::High);
return true;
@ -178,6 +182,8 @@ AlsaSource::AlsaSource(AlsaDevice* dev)
Debug(DebugNote,"AlsaSource::AlsaSource(%p) [%p]",dev,this);
dev->ref();
m_device = dev;
if (dev->rate() != 8000)
m_format << "/" << dev->rate();
}
AlsaSource::~AlsaSource()
@ -238,6 +244,8 @@ AlsaConsumer::AlsaConsumer(AlsaDevice* dev)
Debug(DebugNote,"AlsaConsumer::AlsaConsumer(%p) [%p]",dev,this);
dev->ref();
m_device = dev;
if (dev->rate() != 8000)
m_format << "/" << dev->rate();
}
AlsaConsumer::~AlsaConsumer()
@ -256,11 +264,11 @@ unsigned long AlsaConsumer::Consume(const DataBlock &data, unsigned long tStamp,
}
AlsaChan::AlsaChan(const String& dev)
AlsaChan::AlsaChan(const String& dev, unsigned int rate)
: CallEndpoint("alsa"),
m_dev(dev)
m_dev(dev), m_rate(rate)
{
Debug(DebugNote,"AlsaChan::AlsaChan dev [%s] [%p]",dev.c_str(),this);
Debug(DebugNote,"AlsaChan::AlsaChan('%s',%u) [%p]",dev.c_str(),rate,this);
s_chan = this;
}
@ -277,7 +285,7 @@ bool AlsaChan::init()
{
if (s_dev)
return false;
AlsaDevice* dev = new AlsaDevice(m_dev,true);
AlsaDevice* dev = new AlsaDevice(m_dev,m_rate);
if (dev->closed()) {
dev->deref();
return false;
@ -302,11 +310,11 @@ bool AlsaChan::init()
}
AlsaDevice::AlsaDevice(const String& dev,bool init)
: m_dev(dev), m_dev_in(dev), m_dev_out(dev), m_closed(true),
AlsaDevice::AlsaDevice(const String& dev, unsigned int rate)
: m_dev(dev), m_dev_in(dev), m_dev_out(dev), m_closed(true), m_rate(rate),
m_handle_in(0), m_handle_out(0)
{
Debug(DebugNote,"AlsaDevice::AlsaDevice('%s') [%p]",m_dev.c_str(),this);
Debug(DebugNote,"AlsaDevice::AlsaDevice('%s',%u) [%p]",m_dev.c_str(),rate,this);
if (!s_dev)
s_dev = this;
int p = dev.find('/');
@ -317,16 +325,15 @@ AlsaDevice::AlsaDevice(const String& dev,bool init)
if (m_dev_out.null()) m_dev_out = m_dev_in;
if(q>0) m_initdata = dev.substr(p+2+q);
}
if (init)
open();
open();
};
bool AlsaDevice::open()
{
int err;
snd_pcm_hw_params_t *hw_params = NULL;
unsigned int rate_in=8000;
unsigned int rate_out=8000;
unsigned int rate_in = m_rate;
unsigned int rate_out = m_rate;
int direction=0;
snd_pcm_uframes_t period_size_in = 20 * 4;
snd_pcm_uframes_t buffer_size_in= period_size_in * 16;
@ -346,7 +353,7 @@ bool AlsaDevice::open()
if ((err = snd_pcm_hw_params_any (m_handle_in, hw_params)) < 0) Debug(DebugWarn, "cannot initialize hardware parameter structure (%s)", snd_strerror (err));
if ((err = snd_pcm_hw_params_set_access (m_handle_in, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) Debug(DebugWarn, "cannot set access type (%s)", snd_strerror (err));
if ((err = snd_pcm_hw_params_set_format (m_handle_in, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) Debug(DebugWarn, "cannot set sample format (%s)", snd_strerror (err));
if ((err = snd_pcm_hw_params_set_rate_near (m_handle_in, hw_params, &rate_in, &direction)) < 0) Debug(DebugWarn, "cannot set sample rate (%s)", snd_strerror (err));
if ((err = snd_pcm_hw_params_set_rate_near (m_handle_in, hw_params, &rate_in, &direction)) < 0) Debug(DebugWarn, "cannot set sample rate %u (%s)", m_rate, snd_strerror (err));
if ((err = snd_pcm_hw_params_set_channels (m_handle_in, hw_params, 1)) < 0) Debug(DebugWarn, "cannot set channel count (%s)", snd_strerror (err));
if ((err = snd_pcm_hw_params (m_handle_in, hw_params)) < 0) Debug(DebugWarn, "cannot set parameters (%s)", snd_strerror (err));
snd_pcm_hw_params_free (hw_params);
@ -364,7 +371,7 @@ bool AlsaDevice::open()
if ((err = snd_pcm_hw_params_any (m_handle_out, hw_params)) < 0) Debug(DebugWarn, "cannot initialize hardware parameter structure (%s)", snd_strerror (err));
if ((err = snd_pcm_hw_params_set_access (m_handle_out, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) Debug(DebugWarn, "cannot set access type (%s)", snd_strerror (err));
if ((err = snd_pcm_hw_params_set_format (m_handle_out, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) Debug(DebugWarn, "cannot set sample format (%s)", snd_strerror (err));
if ((err = snd_pcm_hw_params_set_rate_near (m_handle_out, hw_params, &rate_out, 0)) < 0) Debug(DebugWarn, "cannot set sample rate (%s)", snd_strerror (err));
if ((err = snd_pcm_hw_params_set_rate_near (m_handle_out, hw_params, &rate_out, 0)) < 0) Debug(DebugWarn, "cannot set sample rate %u (%s)", m_rate, snd_strerror (err));
if ((err = snd_pcm_hw_params_set_channels (m_handle_out, hw_params, 1)) < 0) Debug(DebugWarn, "cannot set channel count (%s)", snd_strerror (err));
if ((err = snd_pcm_hw_params_set_period_size_near(m_handle_out, hw_params, &period_size_out, &direction)) < 0) Debug(DebugWarn, "cannot set period size (%s)", snd_strerror (err));
if ((err = snd_pcm_hw_params_set_buffer_size_near(m_handle_out, hw_params, &buffer_size_out)) < 0) Debug(DebugWarn, "cannot set buffer size (%s)", snd_strerror (err));
@ -495,7 +502,7 @@ bool AlsaHandler::received(Message &msg)
msg.setParam("error","busy");
return false;
}
AlsaChan *chan = new AlsaChan(dest.matchString(1).c_str());
AlsaChan *chan = new AlsaChan(dest.matchString(1).c_str(),msg.getIntValue("rate",8000));
if (!chan->init())
{
chan->destruct();
@ -642,7 +649,7 @@ bool AttachHandler::received(Message &msg)
return false;
}
AlsaDevice* dev = new AlsaDevice(src ? src : cons,true);
AlsaDevice* dev = new AlsaDevice(src ? src : cons,msg.getIntValue("rate",8000));
if (dev->closed()) {
dev->deref();
return false;

View File

@ -80,7 +80,7 @@ private:
class OssDevice : public RefObject
{
public:
OssDevice(const String& dev);
OssDevice(const String& dev, unsigned int rate = 8000);
~OssDevice();
bool reOpen(int iomode);
bool setPcmFormat();
@ -93,8 +93,11 @@ public:
{ return m_fd < 0; }
inline bool fullDuplex() const
{ return m_fullDuplex; }
private:
inline unsigned int rate() const
{ return m_rate; }
private:
String m_dev;
unsigned int m_rate;
bool m_fullDuplex;
bool m_readMode;
int m_fd;
@ -104,7 +107,7 @@ private:
class OssChan : public CallEndpoint
{
public:
OssChan(const String& dev);
OssChan(const String& dev, unsigned int rate = 8000);
~OssChan();
bool init();
virtual void disconnected(bool final, const char *reason);
@ -114,9 +117,10 @@ public:
inline const String& getTarget() const
{ return m_target; }
private:
private:
String m_dev;
String m_target;
unsigned int m_rate;
};
class OssHandler : public MessageHandler
@ -169,7 +173,7 @@ OssChan *s_chan = 0;
bool OssSource::init()
{
m_brate = 16000;
m_brate = 2 * m_device->rate();
m_total = 0;
if (m_device->setInputMode(false) < 0) {
Debug(DebugWarn, "Unable to set input mode");
@ -185,6 +189,8 @@ OssSource::OssSource(OssDevice* dev)
Debug(DebugAll,"OssSource::OssSource(%p) [%p]",dev,this);
dev->ref();
m_device = dev;
if (dev->rate() != 8000)
m_format << "/" << dev->rate();
}
OssSource::~OssSource()
@ -243,6 +249,7 @@ void OssSource::cleanup()
ThreadedSource::cleanup();
}
bool OssConsumer::init()
{
m_total = 0;
@ -273,6 +280,8 @@ OssConsumer::OssConsumer(OssDevice* dev)
Debug(DebugAll,"OssConsumer::OssConsumer(%p) [%p]",dev,this);
dev->ref();
m_device = dev;
if (dev->rate() != 8000)
m_format << "/" << dev->rate();
}
OssConsumer::~OssConsumer()
@ -291,11 +300,11 @@ unsigned long OssConsumer::Consume(const DataBlock &data, unsigned long tStamp,
}
OssChan::OssChan(const String& dev)
OssChan::OssChan(const String& dev, unsigned int rate)
: CallEndpoint("oss"),
m_dev(dev)
m_dev(dev), m_rate(rate)
{
Debug(DebugAll,"OssChan::OssChan dev [%s] [%p]",dev.c_str(),this);
Debug(DebugAll,"OssChan::OssChan('%s',%u) [%p]",dev.c_str(),rate,this);
s_chan = this;
}
@ -310,7 +319,7 @@ OssChan::~OssChan()
bool OssChan::init()
{
OssDevice* dev = new OssDevice(m_dev);
OssDevice* dev = new OssDevice(m_dev,m_rate);
if (dev->closed()) {
dev->deref();
return false;
@ -353,10 +362,10 @@ void OssChan::answer()
}
OssDevice::OssDevice(const String& dev)
: m_dev(dev), m_fullDuplex(false), m_readMode(true), m_fd(-1)
OssDevice::OssDevice(const String& dev, unsigned int rate)
: m_dev(dev), m_rate(rate), m_fullDuplex(false), m_readMode(true), m_fd(-1)
{
Debug(DebugAll,"OssDevice::OssDevice('%s') [%p]",dev.c_str(),this);
Debug(DebugAll,"OssDevice::OssDevice('%s',%u) [%p]",dev.c_str(),rate,this);
m_fd = ::open(m_dev, O_RDWR|O_NONBLOCK);
if (m_fd < 0) {
Debug(DebugWarn, "Unable to open %s: %s", m_dev.c_str(), ::strerror(errno));
@ -414,16 +423,15 @@ bool OssDevice::setPcmFormat()
return false;
}
// try to set the desired speed (8kHz) and check if it was actually set
int desired = 8000;
fmt = desired;
// try to set the desired speed (8/16/32kHz) and check if it was actually set
fmt = m_rate;
res = ::ioctl(m_fd, SNDCTL_DSP_SPEED, &fmt);
if (res < 0) {
Debug(DebugWarn, "Failed to set audio device speed");
return false;
}
if (fmt != desired)
Debug(DebugWarn, "Requested %d Hz, got %d Hz - sound may be choppy", desired, fmt);
if (fmt != (int)m_rate)
Debug(DebugWarn, "Requested %d Hz, got %d Hz - sound may be choppy", m_rate, fmt);
return true;
}
@ -484,7 +492,7 @@ bool OssHandler::received(Message &msg)
msg.setParam("error","busy");
return false;
}
OssChan *chan = new OssChan(dest.matchString(1).c_str());
OssChan *chan = new OssChan(dest.matchString(1).c_str(),msg.getIntValue("rate",8000));
if (!chan->init())
{
chan->destruct();
@ -630,7 +638,7 @@ bool AttachHandler::received(Message &msg)
return false;
}
OssDevice* dev = new OssDevice(src ? src : cons);
OssDevice* dev = new OssDevice(src ? src : cons,msg.getIntValue("rate",8000));
if (dev->closed()) {
dev->deref();
return false;

View File

@ -154,7 +154,7 @@ public:
ConfConsumer(ConfRoom* room, bool smart = false)
: m_room(room), m_src(0), m_muted(false), m_smart(smart),
m_energy2(ENERGY_MIN), m_noise2(ENERGY_MIN)
{ DDebug(DebugAll,"ConfConsumer::ConfConsumer(%p,%s) [%p]",room,String::boolText(smart),this); }
{ DDebug(DebugAll,"ConfConsumer::ConfConsumer(%p,%s) [%p]",room,String::boolText(smart),this); m_format = room->getFormat(); }
~ConfConsumer()
{ DDebug(DebugAll,"ConfConsumer::~ConfConsumer() [%p]",this); }
virtual unsigned long Consume(const DataBlock& data, unsigned long tStamp, unsigned long flags);
@ -268,6 +268,8 @@ ConfRoom::ConfRoom(const String& name, const NamedList& params)
m_maxusers = params.getIntValue("maxusers",m_maxusers);
m_notify = params.getValue("notify");
m_lonely = params.getBoolValue("lonely");
if (m_rate != 8000)
m_format << "/" << m_rate;
s_rooms.append(this);
// possibly create outgoing call to room record utility channel
setRecording(params);
@ -394,6 +396,7 @@ void ConfRoom::msgStatus(Message& msg)
msg.retValue() << ",room=" << m_name;
msg.retValue() << ",maxusers=" << m_maxusers;
msg.retValue() << ",lonely=" << m_lonely;
msg.retValue() << ",rate=" << m_rate;
msg.retValue() << ",users=" << m_users;
msg.retValue() << ",chans=" << m_chans.count();
if (m_notify)
@ -661,8 +664,10 @@ unsigned int ConfConsumer::noise() const
ConfSource::ConfSource(ConfConsumer* cons)
: m_cons(cons)
{
if (m_cons)
if (m_cons) {
m_format = m_cons->getFormat();
m_cons->m_src = this;
}
}
ConfSource::~ConfSource()

View File

@ -62,7 +62,7 @@ public:
{ return m_name; }
static MOHSource* getSource(String& name, const NamedList& params);
private:
MOHSource(const String &name, const String &command_line);
MOHSource(const String &name, const String &command_line, unsigned int rate = 8000);
String m_name;
String m_command_line;
bool create();
@ -121,11 +121,13 @@ private:
};
MOHSource::MOHSource(const String &name, const String &command_line)
MOHSource::MOHSource(const String &name, const String &command_line, unsigned int rate)
: ThreadedSource("slin"),
m_name(name), m_command_line(command_line), m_swap(false), m_brate(16000)
m_name(name), m_command_line(command_line), m_swap(false), m_brate(2*rate)
{
Debug(DebugAll,"MOHSource::MOHSource(\"%s\", \"%s\") [%p]", name.c_str(), command_line.c_str(), this);
Debug(DebugAll,"MOHSource::MOHSource('%s','%s',%u) [%p]",name.c_str(),command_line.c_str(),rate,this);
if (rate != 8000)
m_format << "/" << rate;
}
MOHSource::~MOHSource()
@ -152,6 +154,10 @@ void MOHSource::destroyed()
MOHSource* MOHSource::getSource(String& name, const NamedList& params)
{
String cmd = s_cfg.getValue("mohs", name);
unsigned int rate = 8000;
// honor the rate only if the command knows about it
if ((cmd.find("${rate}") >= 0) || (cmd.find("${rate$") >= 0))
rate = params.getIntValue("rate",8000);
if (params.replaceParams(cmd) > 0) {
// command is parametrized, suffix name to account for it
name << "-" << cmd.hash();
@ -166,7 +172,7 @@ MOHSource* MOHSource::getSource(String& name, const NamedList& params)
}
}
if (cmd) {
MOHSource *s = new MOHSource(name,cmd);
MOHSource *s = new MOHSource(name,cmd,rate);
if (s->start("MOH Source")) {
sources.append(s);
return s;