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:
parent
2db4b83623
commit
44d5f77989
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue