mirror of
https://git.jami.net/savoirfairelinux/jami-daemon.git
synced 2025-08-12 22:09:25 +08:00
Merge branch 'master' into multichannel
Resolved Conflicts: daemon/src/audio/alsa/alsalayer.cpp daemon/src/audio/audioloop.cpp daemon/src/audio/audiortp/audio_rtp_record_handler.cpp daemon/src/audio/codecs/alaw.cpp daemon/src/audio/codecs/audiocodecfactory.cpp daemon/src/audio/codecs/g722.cpp daemon/src/audio/codecs/gsmcodec.cpp daemon/src/audio/codecs/ulaw.cpp daemon/src/audio/dcblocker.cpp daemon/src/audio/mainbuffer.cpp daemon/src/audio/pulseaudio/audiostream.cpp daemon/src/audio/pulseaudio/pulselayer.cpp daemon/src/audio/ringbuffer.cpp daemon/src/audio/samplerateconverter.cpp daemon/src/audio/sound/audiofile.cpp
This commit is contained in:
@ -42,7 +42,7 @@
|
||||
|
||||
#define SFL_ALSA_PERIOD_SIZE 160
|
||||
#define SFL_ALSA_NB_PERIOD 8
|
||||
#define SFL_ALSA_BUFFER_SIZE SFL_ALSA_PERIOD_SIZE*SFL_ALSA_NB_PERIOD
|
||||
#define SFL_ALSA_BUFFER_SIZE SFL_ALSA_PERIOD_SIZE * SFL_ALSA_NB_PERIOD
|
||||
|
||||
class AlsaThread {
|
||||
public:
|
||||
@ -74,6 +74,7 @@ bool AlsaThread::isRunning() const
|
||||
AlsaThread::~AlsaThread()
|
||||
{
|
||||
running_ = false;
|
||||
|
||||
if (thread_)
|
||||
pthread_join(thread_, NULL);
|
||||
}
|
||||
@ -149,7 +150,6 @@ void AlsaThread::run()
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor
|
||||
AlsaLayer::AlsaLayer(const AudioPreference &pref)
|
||||
: indexIn_(pref.getAlsaCardin())
|
||||
, indexOut_(pref.getAlsaCardout())
|
||||
@ -172,7 +172,6 @@ AlsaLayer::AlsaLayer(const AudioPreference &pref)
|
||||
setPlaybackGain(pref.getVolumespkr());
|
||||
}
|
||||
|
||||
// Destructor
|
||||
AlsaLayer::~AlsaLayer()
|
||||
{
|
||||
isStarted_ = false;
|
||||
@ -198,7 +197,7 @@ bool AlsaLayer::openDevice(snd_pcm_t **pcm, const std::string &dev, snd_pcm_stre
|
||||
|
||||
if (err < 0) {
|
||||
ERROR("Alsa: couldn't open device %s : %s", dev.c_str(),
|
||||
snd_strerror(err));
|
||||
snd_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -248,10 +247,6 @@ AlsaLayer::stopStream()
|
||||
flushMain();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////// ALSA PRIVATE FUNCTIONS ////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* GCC extension : statement expression
|
||||
*
|
||||
@ -388,11 +383,12 @@ bool AlsaLayer::alsa_set_params(snd_pcm_t *pcm_handle)
|
||||
ERROR("buffer to small, could not use");
|
||||
return false;
|
||||
}
|
||||
|
||||
#undef HW
|
||||
|
||||
DEBUG("%s using sampling rate %dHz",
|
||||
(snd_pcm_stream(pcm_handle) == SND_PCM_STREAM_PLAYBACK) ? "playback" : "capture",
|
||||
sampleRate_);
|
||||
(snd_pcm_stream(pcm_handle) == SND_PCM_STREAM_PLAYBACK) ? "playback" : "capture",
|
||||
sampleRate_);
|
||||
|
||||
snd_pcm_sw_params_t *swparams = NULL;
|
||||
snd_pcm_sw_params_alloca(&swparams);
|
||||
@ -408,13 +404,14 @@ bool AlsaLayer::alsa_set_params(snd_pcm_t *pcm_handle)
|
||||
#undef TRY
|
||||
}
|
||||
|
||||
//TODO first frame causes broken pipe (underrun) because not enough data are send --> make the handle wait to be ready
|
||||
// TODO first frame causes broken pipe (underrun) because not enough data is sent
|
||||
// we should wait until the handle is ready
|
||||
void
|
||||
AlsaLayer::write(void* buffer, int length, snd_pcm_t * handle)
|
||||
{
|
||||
//Do not waste CPU cycle to handle void
|
||||
// Skip empty buffers
|
||||
if (!length)
|
||||
return;
|
||||
return;
|
||||
|
||||
snd_pcm_uframes_t frames = snd_pcm_bytes_to_frames(handle, length);
|
||||
watchdogTotalCount_++;
|
||||
@ -454,12 +451,14 @@ AlsaLayer::write(void* buffer, int length, snd_pcm_t * handle)
|
||||
ERROR("Writing in state SND_PCM_STATE_SETUP, should be "
|
||||
"SND_PCM_STATE_PREPARED or SND_PCM_STATE_RUNNING");
|
||||
int error = snd_pcm_prepare(handle);
|
||||
|
||||
if (error < 0) {
|
||||
ERROR("Failed to prepare handle: %s", snd_strerror(error));
|
||||
stopPlaybackStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -469,8 +468,9 @@ AlsaLayer::write(void* buffer, int length, snd_pcm_t * handle)
|
||||
break;
|
||||
}
|
||||
|
||||
//Detect when something is going wrong. This can be caused by alsa bugs or faulty encoder on the other side
|
||||
//TODO do something useful instead of just warning and flushing buffers
|
||||
// Detect when something is going wrong. This can be caused by alsa bugs or
|
||||
// faulty encoder on the other side
|
||||
// TODO do something useful instead of just warning and flushing buffers
|
||||
if (watchdogTotalErr_ > 0 && watchdogTotalCount_ / watchdogTotalErr_ >=4 && watchdogTotalCount_ > 50) {
|
||||
ERROR("Alsa: too many errors (%d error on %d frame)",watchdogTotalErr_,watchdogTotalCount_);
|
||||
flushUrgent();
|
||||
@ -539,13 +539,16 @@ namespace {
|
||||
bool safeUpdate(snd_pcm_t *handle, int &samples)
|
||||
{
|
||||
samples = snd_pcm_avail_update(handle);
|
||||
|
||||
if (samples < 0) {
|
||||
samples = snd_pcm_recover(handle, samples, 0);
|
||||
|
||||
if (samples < 0) {
|
||||
ERROR("Got unrecoverable error from snd_pcm_avail_update: %s", snd_strerror(samples));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -553,9 +556,11 @@ std::vector<std::string>
|
||||
getValues(const std::vector<HwIDPair> &deviceMap)
|
||||
{
|
||||
std::vector<std::string> audioDeviceList;
|
||||
|
||||
for (std::vector<HwIDPair>::const_iterator iter = deviceMap.begin();
|
||||
iter != deviceMap.end(); ++iter)
|
||||
audioDeviceList.push_back(iter->second);
|
||||
|
||||
return audioDeviceList;
|
||||
}
|
||||
}
|
||||
@ -600,12 +605,11 @@ AlsaLayer::getAudioDeviceIndexMap(bool getCapture) const
|
||||
|
||||
if (snd_ctl_pcm_info(handle ,pcminfo) < 0) {
|
||||
DEBUG(" Cannot get info");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
DEBUG("card %i : %s [%s]",
|
||||
numCard,
|
||||
snd_ctl_card_info_get_id(info),
|
||||
snd_ctl_card_info_get_name(info));
|
||||
numCard,
|
||||
snd_ctl_card_info_get_id(info),
|
||||
snd_ctl_card_info_get_name(info));
|
||||
std::string description = snd_ctl_card_info_get_name(info);
|
||||
description.append(" - ");
|
||||
description.append(snd_pcm_info_get_name(pcminfo));
|
||||
@ -635,6 +639,7 @@ AlsaLayer::soundCardIndexExists(int card, PCMType stream)
|
||||
name.append(ss.str());
|
||||
|
||||
snd_ctl_t* handle;
|
||||
|
||||
if (snd_ctl_open(&handle, name.c_str(), 0) != 0)
|
||||
return false;
|
||||
|
||||
@ -672,8 +677,10 @@ AlsaLayer::getAudioDeviceName(int index, PCMType type) const
|
||||
case SFL_PCM_PLAYBACK:
|
||||
case SFL_PCM_RINGTONE:
|
||||
return getPlaybackDeviceList().at(index);
|
||||
|
||||
case SFL_PCM_CAPTURE:
|
||||
return getCaptureDeviceList().at(index);
|
||||
|
||||
default:
|
||||
ERROR("Unexpected type %d", type);
|
||||
return "";
|
||||
@ -701,6 +708,7 @@ void AlsaLayer::capture()
|
||||
// TODO: handle ALSA multichannel capture
|
||||
const int toGetBytes = in.samples() * sizeof(SFLAudioSample);
|
||||
SFLAudioSample * const in_ptr = &(*in.getChannel()->begin());
|
||||
|
||||
if (read(in_ptr, toGetBytes) != toGetBytes) {
|
||||
ERROR("ALSA MIC : Couldn't read!");
|
||||
return;
|
||||
@ -725,6 +733,7 @@ void AlsaLayer::playback(int maxSamples)
|
||||
size_t bytesToGet = Manager::instance().getMainBuffer().availableForGet(MainBuffer::DEFAULT_ID);
|
||||
|
||||
const size_t bytesToPut = maxSamples * sizeof(SFLAudioSample);
|
||||
|
||||
// no audio available, play tone or silence
|
||||
if (bytesToGet <= 0) {
|
||||
// FIXME: not thread safe! we only lock the mutex when we get the
|
||||
@ -733,6 +742,7 @@ void AlsaLayer::playback(int maxSamples)
|
||||
AudioLoop *file_tone = Manager::instance().getTelephoneFile();
|
||||
|
||||
AudioBuffer out(maxSamples, 1, sampleRate_);
|
||||
|
||||
if (tone)
|
||||
tone->getNext(out, getPlaybackGain());
|
||||
else if (file_tone && !ringtoneHandle_)
|
||||
@ -747,6 +757,7 @@ void AlsaLayer::playback(int maxSamples)
|
||||
|
||||
double resampleFactor = 1.0;
|
||||
size_t maxNbBytesToGet = bytesToPut;
|
||||
|
||||
if (resample) {
|
||||
resampleFactor = static_cast<double>(sampleRate_) / mainBufferSampleRate;
|
||||
maxNbBytesToGet = bytesToGet / resampleFactor;
|
||||
@ -788,6 +799,7 @@ void AlsaLayer::audioCallback()
|
||||
snd_pcm_wait(playbackHandle_, 20);
|
||||
|
||||
int playbackAvailSmpl = 0;
|
||||
|
||||
if (not safeUpdate(playbackHandle_, playbackAvailSmpl))
|
||||
return;
|
||||
|
||||
@ -811,6 +823,7 @@ void AlsaLayer::audioCallback()
|
||||
if (ringtoneHandle_) {
|
||||
AudioLoop *file_tone = Manager::instance().getTelephoneFile();
|
||||
int ringtoneAvailSmpl = 0;
|
||||
|
||||
if (not safeUpdate(ringtoneHandle_, ringtoneAvailSmpl))
|
||||
return;
|
||||
int ringtoneAvailBytes = ringtoneAvailSmpl * sizeof(SFLAudioSample);
|
||||
@ -836,12 +849,15 @@ void AlsaLayer::updatePreference(AudioPreference &preference, int index, PCMType
|
||||
case SFL_PCM_PLAYBACK:
|
||||
preference.setAlsaCardout(index);
|
||||
break;
|
||||
|
||||
case AudioLayer::SFL_PCM_CAPTURE:
|
||||
preference.setAlsaCardin(index);
|
||||
break;
|
||||
|
||||
case AudioLayer::SFL_PCM_RINGTONE:
|
||||
preference.setAlsaCardring(index);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -100,16 +100,17 @@ AudioLoop::getNext(AudioBuffer& output, unsigned int volume)
|
||||
|
||||
// We want to send values in milisecond
|
||||
int divisor = buffer_->getSampleRate() / 1000;
|
||||
if(divisor == 0) {
|
||||
if (divisor == 0) {
|
||||
ERROR("Error cannot update playback slider, sampling rate is 0");
|
||||
return;
|
||||
}
|
||||
|
||||
if(isRecording_) {
|
||||
if((updatePlaybackScale % 5) == 0) {
|
||||
if (isRecording_) {
|
||||
if ((updatePlaybackScale % 5) == 0) {
|
||||
CallManager *cm = Manager::instance().getClient()->getCallManager();
|
||||
cm->updatePlaybackScale(pos_ / divisor, buf_samples / divisor);
|
||||
}
|
||||
|
||||
updatePlaybackScale++;
|
||||
}
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ namespace {
|
||||
bool
|
||||
nonFilenameCharacter(char c)
|
||||
{
|
||||
return not (std::isalnum(c) or c == '_' or c == '.');
|
||||
return not(std::isalnum(c) or c == '_' or c == '.');
|
||||
}
|
||||
|
||||
// Replace any character that is inappropriate for a filename with '_'
|
||||
@ -200,6 +200,7 @@ bool AudioRecord::openFile()
|
||||
result = setWavFile();
|
||||
} else {
|
||||
DEBUG("Filename already exists, opening it");
|
||||
|
||||
if (fileType_ == FILE_RAW)
|
||||
result = openExistingRawFile();
|
||||
else if (fileType_ == FILE_WAV)
|
||||
@ -242,6 +243,7 @@ bool AudioRecord::toggleRecording()
|
||||
openFile();
|
||||
recordingEnabled_ = true;
|
||||
}
|
||||
|
||||
return recordingEnabled_;
|
||||
}
|
||||
|
||||
@ -266,24 +268,24 @@ bool AudioRecord::setRawFile()
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::string header_to_string(const wavhdr &hdr)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << hdr.riff << "\0 "
|
||||
<< hdr.file_size << " "
|
||||
<< hdr.wave << "\0 "
|
||||
<< hdr.fmt << "\0 "
|
||||
<< hdr.chunk_size << " "
|
||||
<< hdr.format_tag << " "
|
||||
<< hdr.num_chans << " "
|
||||
<< hdr.sample_rate << " "
|
||||
<< hdr.bytes_per_sec << " "
|
||||
<< hdr.bytes_per_samp << " "
|
||||
<< hdr.bits_per_samp << " "
|
||||
<< hdr.data << "\0 "
|
||||
<< hdr.data_length;
|
||||
return ss.str();
|
||||
}
|
||||
std::string header_to_string(const wavhdr &hdr)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << hdr.riff << "\0 "
|
||||
<< hdr.file_size << " "
|
||||
<< hdr.wave << "\0 "
|
||||
<< hdr.fmt << "\0 "
|
||||
<< hdr.chunk_size << " "
|
||||
<< hdr.format_tag << " "
|
||||
<< hdr.num_chans << " "
|
||||
<< hdr.sample_rate << " "
|
||||
<< hdr.bytes_per_sec << " "
|
||||
<< hdr.bytes_per_samp << " "
|
||||
<< hdr.bits_per_samp << " "
|
||||
<< hdr.data << "\0 "
|
||||
<< hdr.data_length;
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioRecord::setWavFile()
|
||||
@ -301,18 +303,19 @@ bool AudioRecord::setWavFile()
|
||||
* write them as arrays since strings enclosed in quotes include a
|
||||
* null character */
|
||||
wavhdr hdr = {{'R', 'I', 'F', 'F'},
|
||||
44,
|
||||
{'W', 'A', 'V', 'E'},
|
||||
{'f','m', 't', ' '},
|
||||
16,
|
||||
1,
|
||||
channels_,
|
||||
sndSmplRate_,
|
||||
-1, /* initialized below */
|
||||
-1, /* initialized below */
|
||||
16,
|
||||
{'d', 'a', 't', 'a'},
|
||||
0};
|
||||
44,
|
||||
{'W', 'A', 'V', 'E'},
|
||||
{'f','m', 't', ' '},
|
||||
16,
|
||||
1,
|
||||
channels_,
|
||||
sndSmplRate_,
|
||||
-1, /* initialized below */
|
||||
-1, /* initialized below */
|
||||
16,
|
||||
{'d', 'a', 't', 'a'},
|
||||
0
|
||||
};
|
||||
|
||||
hdr.bytes_per_samp = channels_ * hdr.bits_per_samp / 8;
|
||||
hdr.bytes_per_sec = hdr.sample_rate * hdr.bytes_per_samp;
|
||||
|
@ -56,8 +56,10 @@ AudioRecorder::AudioRecorder(AudioRecord *arec, MainBuffer *mb) :
|
||||
recorderId_ = id.append(s);
|
||||
}
|
||||
|
||||
AudioRecorder::~AudioRecorder() {
|
||||
AudioRecorder::~AudioRecorder()
|
||||
{
|
||||
running_ = false;
|
||||
|
||||
if (thread_)
|
||||
pthread_join(thread_, NULL);
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ AudioRtpFactory::~AudioRtpFactory()
|
||||
void AudioRtpFactory::initConfig()
|
||||
{
|
||||
DEBUG("AudioRtpFactory: init config");
|
||||
|
||||
if (rtpSession_ != NULL)
|
||||
stop();
|
||||
|
||||
@ -78,18 +79,22 @@ void AudioRtpFactory::initConfig()
|
||||
if (account) {
|
||||
srtpEnabled_ = account->getSrtpEnabled();
|
||||
std::string key(account->getSrtpKeyExchange());
|
||||
|
||||
if (srtpEnabled_) {
|
||||
#if HAVE_ZRTP
|
||||
|
||||
if (key == "sdes")
|
||||
keyExchangeProtocol_ = SDES;
|
||||
else if (key == "zrtp")
|
||||
keyExchangeProtocol_ = ZRTP;
|
||||
|
||||
#else
|
||||
keyExchangeProtocol_ = SDES;
|
||||
keyExchangeProtocol_ = SDES;
|
||||
#endif
|
||||
} else {
|
||||
keyExchangeProtocol_ = NONE;
|
||||
}
|
||||
|
||||
helloHashEnabled_ = account->getZrtpHelloHash();
|
||||
} else {
|
||||
srtpEnabled_ = false;
|
||||
@ -107,14 +112,18 @@ void AudioRtpFactory::initSession()
|
||||
|
||||
switch (keyExchangeProtocol_) {
|
||||
#if HAVE_ZRTP
|
||||
|
||||
case ZRTP:
|
||||
rtpSession_ = new AudioZrtpSession(*ca_, zidFilename);
|
||||
|
||||
// TODO: be careful with that. The hello hash is computed asynchronously. Maybe it's
|
||||
// not even available at that point.
|
||||
if (helloHashEnabled_)
|
||||
ca_->getLocalSDP()->setZrtpHash(static_cast<AudioZrtpSession *>(rtpSession_)->getHelloHash());
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SDES:
|
||||
rtpSession_ = new AudioSrtpSession(*ca_);
|
||||
break;
|
||||
@ -192,6 +201,7 @@ AudioZrtpSession * AudioRtpFactory::getAudioZrtpSession()
|
||||
void AudioRtpFactory::initLocalCryptoInfo()
|
||||
{
|
||||
DEBUG("AudioRtpFactory: Init local crypto info");
|
||||
|
||||
if (rtpSession_ && keyExchangeProtocol_ == SDES) {
|
||||
AudioSrtpSession *srtp = static_cast<AudioSrtpSession*>(rtpSession_);
|
||||
// the context is invalidated and deleted by the call to initLocalCryptoInfo
|
||||
@ -203,6 +213,7 @@ void AudioRtpFactory::initLocalCryptoInfo()
|
||||
void AudioRtpFactory::initLocalCryptoInfoOnOffHold()
|
||||
{
|
||||
DEBUG("AudioRtpFactory: Init local crypto info");
|
||||
|
||||
if (rtpSession_ && keyExchangeProtocol_ == SDES) {
|
||||
AudioSrtpSession *srtp = static_cast<AudioSrtpSession*>(rtpSession_);
|
||||
// the context is invalidated and deleted by the call to initLocalCryptoInfo
|
||||
@ -214,7 +225,7 @@ void AudioRtpFactory::initLocalCryptoInfoOnOffHold()
|
||||
|
||||
void AudioRtpFactory::setRemoteCryptoInfo(SdesNegotiator& nego)
|
||||
{
|
||||
if (rtpSession_ ) {
|
||||
if (rtpSession_) {
|
||||
if (keyExchangeProtocol_ == SDES) {
|
||||
AudioSrtpSession *srtp = static_cast<AudioSrtpSession *>(rtpSession_);
|
||||
srtp->setRemoteCryptoInfo(nego);
|
||||
|
@ -44,37 +44,41 @@
|
||||
namespace sfl {
|
||||
|
||||
#ifdef RECTODISK
|
||||
std::ofstream rtpResampled ("testRtpOutputResampled.raw", std::ifstream::binary);
|
||||
std::ofstream rtpResampled("testRtpOutputResampled.raw", std::ifstream::binary);
|
||||
std::ofstream rtpNotResampled("testRtpOutput.raw", std::ifstream::binary);
|
||||
#endif
|
||||
|
||||
DTMFEvent::DTMFEvent(char digit) : payload(), newevent(true), length(1000)
|
||||
{
|
||||
/*
|
||||
From RFC2833:
|
||||
/*
|
||||
From RFC2833:
|
||||
|
||||
Event encoding (decimal)
|
||||
_________________________
|
||||
0--9 0--9
|
||||
* 10
|
||||
# 11
|
||||
A--D 12--15
|
||||
Flash 16
|
||||
*/
|
||||
Event encoding (decimal)
|
||||
_________________________
|
||||
0--9 0--9
|
||||
* 10
|
||||
# 11
|
||||
A--D 12--15
|
||||
Flash 16
|
||||
*/
|
||||
|
||||
switch (digit) {
|
||||
case '*':
|
||||
digit = 10;
|
||||
break;
|
||||
|
||||
case '#':
|
||||
digit = 11;
|
||||
break;
|
||||
|
||||
case 'A' ... 'D':
|
||||
digit = digit - 'A' + 12;
|
||||
break;
|
||||
|
||||
case '0' ... '9':
|
||||
digit = digit - '0';
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR("Unexpected DTMF %c", digit);
|
||||
}
|
||||
@ -86,7 +90,7 @@ DTMFEvent::DTMFEvent(char digit) : payload(), newevent(true), length(1000)
|
||||
}
|
||||
|
||||
AudioRtpRecord::AudioRtpRecord() :
|
||||
callId_("")
|
||||
callId_("")
|
||||
, codecSampleRate_(0)
|
||||
, dtmfQueue_()
|
||||
, audioCodecs_()
|
||||
@ -134,6 +138,7 @@ AudioRtpRecord::getCurrentCodec() const
|
||||
ERROR("No codec found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return audioCodecs_[currentCodecIndex_];
|
||||
}
|
||||
|
||||
@ -142,6 +147,7 @@ AudioRtpRecord::deleteCodecs()
|
||||
{
|
||||
for (std::vector<AudioCodec *>::iterator i = audioCodecs_.begin(); i != audioCodecs_.end(); ++i)
|
||||
delete *i;
|
||||
|
||||
audioCodecs_.clear();
|
||||
}
|
||||
|
||||
@ -212,10 +218,12 @@ AudioRtpRecordHandler::getCurrentAudioCodecNames()
|
||||
ScopedLock lock(audioRtpRecord_.audioCodecMutex_);
|
||||
{
|
||||
std::string sep = "";
|
||||
|
||||
for (std::vector<AudioCodec*>::const_iterator i = audioRtpRecord_.audioCodecs_.begin();
|
||||
i != audioRtpRecord_.audioCodecs_.end(); ++i) {
|
||||
if (*i)
|
||||
result += sep + (*i)->getMimeSubtype();
|
||||
|
||||
sep = " ";
|
||||
}
|
||||
}
|
||||
@ -230,6 +238,7 @@ void AudioRtpRecordHandler::setRtpMedia(const std::vector<AudioCodec*> &audioCod
|
||||
audioRtpRecord_.deleteCodecs();
|
||||
// Set various codec info to reduce indirection
|
||||
audioRtpRecord_.audioCodecs_ = audioCodecs;
|
||||
|
||||
if (audioCodecs.empty()) {
|
||||
ERROR("Audio codecs empty");
|
||||
return;
|
||||
@ -320,11 +329,13 @@ int AudioRtpRecordHandler::processDataEncode()
|
||||
}
|
||||
|
||||
#if HAVE_SPEEXDSP
|
||||
|
||||
if (Manager::instance().audioPreference.getNoiseReduce()) {
|
||||
ScopedLock lock(audioRtpRecord_.audioProcessMutex_);
|
||||
RETURN_IF_NULL(audioRtpRecord_.noiseSuppressEncode_, 0, "Noise suppressor already destroyed");
|
||||
audioRtpRecord_.noiseSuppressEncode_->process(micData, getCodecFrameSize());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
{ ScopedLock lock(audioRtpRecord_.audioCodecMutex_);
|
||||
@ -341,13 +352,16 @@ void AudioRtpRecordHandler::processDataDecode(unsigned char *spkrData, size_t si
|
||||
{
|
||||
if (audioRtpRecord_.isDead())
|
||||
return;
|
||||
|
||||
if (audioRtpRecord_.decoderPayloadType_ != payloadType) {
|
||||
const bool switched = audioRtpRecord_.tryToSwitchPayloadTypes(payloadType);
|
||||
|
||||
if (not switched) {
|
||||
if (!warningInterval_) {
|
||||
warningInterval_ = 250;
|
||||
WARN("Invalid payload type %d, expected %d", payloadType, audioRtpRecord_.decoderPayloadType_);
|
||||
}
|
||||
|
||||
warningInterval_--;
|
||||
return;
|
||||
}
|
||||
@ -363,11 +377,13 @@ void AudioRtpRecordHandler::processDataDecode(unsigned char *spkrData, size_t si
|
||||
}
|
||||
|
||||
#if HAVE_SPEEXDSP
|
||||
|
||||
if (Manager::instance().audioPreference.getNoiseReduce()) {
|
||||
ScopedLock lock(audioRtpRecord_.audioProcessMutex_);
|
||||
RETURN_IF_NULL(audioRtpRecord_.noiseSuppressDecode_, "Noise suppressor already destroyed");
|
||||
audioRtpRecord_.noiseSuppressDecode_->process(audioRtpRecord_.decData_, getCodecFrameSize());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
audioRtpRecord_.fadeInDecodedData();
|
||||
@ -410,17 +426,22 @@ bool
|
||||
AudioRtpRecordHandler::codecsDiffer(const std::vector<AudioCodec*> &codecs) const
|
||||
{
|
||||
const std::vector<AudioCodec*> ¤t = audioRtpRecord_.audioCodecs_;
|
||||
|
||||
if (codecs.size() != current.size())
|
||||
return true;
|
||||
|
||||
for (std::vector<AudioCodec*>::const_iterator i = codecs.begin(); i != codecs.end(); ++i) {
|
||||
if (*i) {
|
||||
bool matched = false;
|
||||
|
||||
for (std::vector<AudioCodec*>::const_iterator j = current.begin(); !matched and j != current.end(); ++j)
|
||||
matched = (*i)->getPayloadType() == (*j)->getPayloadType();
|
||||
|
||||
if (not matched)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -71,11 +71,13 @@ void AudioRtpSession::updateSessionMedia(const std::vector<AudioCodec*> &audioCo
|
||||
Manager::instance().audioSamplingRateChanged(audioRtpRecord_.codecSampleRate_);
|
||||
|
||||
#if HAVE_SPEEXDSP
|
||||
|
||||
if (lastSamplingRate != audioRtpRecord_.codecSampleRate_) {
|
||||
DEBUG("Update noise suppressor with sampling rate %d and frame size %d",
|
||||
getCodecSampleRate(), getCodecFrameSize());
|
||||
initNoiseSuppress();
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -85,6 +87,7 @@ void AudioRtpSession::setSessionMedia(const std::vector<AudioCodec*> &audioCodec
|
||||
|
||||
// G722 requires timestamp to be incremented at 8kHz
|
||||
const ost::PayloadType payloadType = getEncoderPayloadType();
|
||||
|
||||
if (payloadType == ost::sptG722) {
|
||||
const int G722_RTP_TIME_INCREMENT = 160;
|
||||
timestampIncrement_ = G722_RTP_TIME_INCREMENT;
|
||||
@ -93,7 +96,7 @@ void AudioRtpSession::setSessionMedia(const std::vector<AudioCodec*> &audioCodec
|
||||
|
||||
if (payloadType == ost::sptG722) {
|
||||
const int G722_RTP_CLOCK_RATE = 8000;
|
||||
queue_.setPayloadFormat(ost::DynamicPayloadFormat( payloadType, G722_RTP_CLOCK_RATE));
|
||||
queue_.setPayloadFormat(ost::DynamicPayloadFormat(payloadType, G722_RTP_CLOCK_RATE));
|
||||
} else {
|
||||
if (getHasDynamicPayload())
|
||||
queue_.setPayloadFormat(ost::DynamicPayloadFormat(payloadType, getCodecSampleRate()));
|
||||
@ -125,7 +128,8 @@ void AudioRtpSession::sendDtmfEvent()
|
||||
// Set marker in case this is a new Event
|
||||
if (dtmf.newevent)
|
||||
queue_.setMark(true);
|
||||
queue_.sendImmediate(timestamp_, (const unsigned char *) (& (dtmf.payload)), sizeof (ost::RTPPacket::RFC2833Payload));
|
||||
|
||||
queue_.sendImmediate(timestamp_, (const unsigned char *)(& (dtmf.payload)), sizeof(ost::RTPPacket::RFC2833Payload));
|
||||
|
||||
// This is no longer a new event
|
||||
if (dtmf.newevent) {
|
||||
@ -140,9 +144,11 @@ void AudioRtpSession::sendDtmfEvent()
|
||||
// decrease length remaining to process for this event
|
||||
dtmf.length -= increment;
|
||||
dtmf.payload.duration++;
|
||||
|
||||
// next packet is going to be the last one
|
||||
if ((dtmf.length - increment) < increment)
|
||||
dtmf.payload.ebit = true;
|
||||
|
||||
if (dtmf.length < increment)
|
||||
audioRtpRecord_.dtmfQueue_.pop_front();
|
||||
}
|
||||
@ -200,7 +206,7 @@ void AudioRtpSession::setDestinationIpAddress()
|
||||
|
||||
if (!remote_ip_) {
|
||||
WARN("Target IP address (%s) is not correct!",
|
||||
call_.getLocalSDP()->getRemoteIP().data());
|
||||
call_.getLocalSDP()->getRemoteIP().data());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -276,6 +282,7 @@ AudioRtpSession::AudioRtpSendThread::AudioRtpSendThread(AudioRtpSession &session
|
||||
AudioRtpSession::AudioRtpSendThread::~AudioRtpSendThread()
|
||||
{
|
||||
running_ = false;
|
||||
|
||||
if (thread_)
|
||||
pthread_join(thread_, NULL);
|
||||
}
|
||||
|
@ -47,84 +47,84 @@
|
||||
namespace sfl {
|
||||
|
||||
namespace {
|
||||
std::string
|
||||
encodeBase64(unsigned char *input, int length)
|
||||
{
|
||||
// init decoder
|
||||
BIO *b64 = BIO_new(BIO_f_base64());
|
||||
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||
std::string
|
||||
encodeBase64(unsigned char *input, int length)
|
||||
{
|
||||
// init decoder
|
||||
BIO *b64 = BIO_new(BIO_f_base64());
|
||||
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||
|
||||
// init internal buffer
|
||||
BIO *bmem = BIO_new(BIO_s_mem());
|
||||
// init internal buffer
|
||||
BIO *bmem = BIO_new(BIO_s_mem());
|
||||
|
||||
// create decoder chain
|
||||
b64 = BIO_push(b64, bmem);
|
||||
// create decoder chain
|
||||
b64 = BIO_push(b64, bmem);
|
||||
|
||||
BIO_write(b64, input, length);
|
||||
// BIO_flush (b64);
|
||||
BIO_write(b64, input, length);
|
||||
// BIO_flush (b64);
|
||||
|
||||
// get pointer to data
|
||||
BUF_MEM *bptr = 0;
|
||||
BIO_get_mem_ptr(b64, &bptr);
|
||||
// get pointer to data
|
||||
BUF_MEM *bptr = 0;
|
||||
BIO_get_mem_ptr(b64, &bptr);
|
||||
|
||||
std::string output(bptr->data, bptr->length);
|
||||
std::string output(bptr->data, bptr->length);
|
||||
|
||||
BIO_free_all(bmem);
|
||||
BIO_free_all(bmem);
|
||||
|
||||
return output;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
std::vector<char> decodeBase64(unsigned char *input, int length)
|
||||
{
|
||||
BIO *b64, *bmem;
|
||||
std::vector<char> decodeBase64(unsigned char *input, int length)
|
||||
{
|
||||
BIO *b64, *bmem;
|
||||
|
||||
// init decoder and read-only BIO buffer
|
||||
b64 = BIO_new(BIO_f_base64());
|
||||
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||
// init decoder and read-only BIO buffer
|
||||
b64 = BIO_new(BIO_f_base64());
|
||||
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||
|
||||
// init internal buffer
|
||||
bmem = BIO_new_mem_buf(input, length);
|
||||
// init internal buffer
|
||||
bmem = BIO_new_mem_buf(input, length);
|
||||
|
||||
// create encoder chain
|
||||
bmem = BIO_push(b64, bmem);
|
||||
// create encoder chain
|
||||
bmem = BIO_push(b64, bmem);
|
||||
|
||||
std::vector<char> buffer(length, 0);
|
||||
BIO_read(bmem, &(*buffer.begin()), length);
|
||||
std::vector<char> buffer(length, 0);
|
||||
BIO_read(bmem, &(*buffer.begin()), length);
|
||||
|
||||
BIO_free_all(bmem);
|
||||
BIO_free_all(bmem);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Fills the array dest with length random bytes
|
||||
void bufferFillMasterKey(std::vector<uint8>& dest)
|
||||
{
|
||||
DEBUG("Init local master key");
|
||||
// Fills the array dest with length random bytes
|
||||
void bufferFillMasterKey(std::vector<uint8>& dest)
|
||||
{
|
||||
DEBUG("Init local master key");
|
||||
|
||||
// Allocate memory for key
|
||||
std::vector<unsigned char> random_key(dest.size());
|
||||
// Allocate memory for key
|
||||
std::vector<unsigned char> random_key(dest.size());
|
||||
|
||||
// Generate ryptographically strong pseudo-random bytes
|
||||
if (RAND_bytes(&(*random_key.begin()), dest.size()) != 1)
|
||||
DEBUG("Error occured while generating cryptographically strong pseudo-random key");
|
||||
// Generate ryptographically strong pseudo-random bytes
|
||||
if (RAND_bytes(&(*random_key.begin()), dest.size()) != 1)
|
||||
DEBUG("Error occured while generating cryptographically strong pseudo-random key");
|
||||
|
||||
std::copy(random_key.begin(), random_key.end(), dest.begin());
|
||||
}
|
||||
std::copy(random_key.begin(), random_key.end(), dest.begin());
|
||||
}
|
||||
|
||||
// Fills the array dest with length random bytes
|
||||
void bufferFillMasterSalt(std::vector<uint8>& dest)
|
||||
{
|
||||
DEBUG("Init local master key");
|
||||
// Fills the array dest with length random bytes
|
||||
void bufferFillMasterSalt(std::vector<uint8>& dest)
|
||||
{
|
||||
DEBUG("Init local master key");
|
||||
|
||||
// Allocate memory for key
|
||||
std::vector<unsigned char> random_key(dest.size());
|
||||
// Allocate memory for key
|
||||
std::vector<unsigned char> random_key(dest.size());
|
||||
|
||||
// Generate ryptographically strong pseudo-random bytes
|
||||
if (RAND_bytes(&(*random_key.begin()), dest.size()) != 1)
|
||||
DEBUG("Error occured while generating cryptographically strong pseudo-random key");
|
||||
// Generate ryptographically strong pseudo-random bytes
|
||||
if (RAND_bytes(&(*random_key.begin()), dest.size()) != 1)
|
||||
DEBUG("Error occured while generating cryptographically strong pseudo-random key");
|
||||
|
||||
std::copy(random_key.begin(), random_key.end(), dest.begin());
|
||||
}
|
||||
std::copy(random_key.begin(), random_key.end(), dest.begin());
|
||||
}
|
||||
}
|
||||
|
||||
AudioSrtpSession::AudioSrtpSession(SIPCall &call) :
|
||||
@ -213,6 +213,7 @@ void AudioSrtpSession::setRemoteCryptoInfo(const sfl::SdesNegotiator& nego)
|
||||
|
||||
// init crypto content in Srtp session
|
||||
initializeRemoteCryptoContext();
|
||||
|
||||
if (remoteCryptoCtx_) {
|
||||
setInQueueCryptoContext(remoteCryptoCtx_);
|
||||
}
|
||||
@ -222,7 +223,7 @@ void AudioSrtpSession::setRemoteCryptoInfo(const sfl::SdesNegotiator& nego)
|
||||
}
|
||||
|
||||
namespace {
|
||||
static const size_t BITS_PER_BYTE = 8;
|
||||
static const size_t BITS_PER_BYTE = 8;
|
||||
}
|
||||
|
||||
void AudioSrtpSession::initializeLocalMasterKey()
|
||||
@ -277,18 +278,18 @@ void AudioSrtpSession::initializeRemoteCryptoContext()
|
||||
const CryptoSuiteDefinition &crypto = sfl::CryptoSuites[remoteCryptoSuite_];
|
||||
|
||||
remoteCryptoCtx_ = new ost::CryptoContext(0x0,
|
||||
0, // roc,
|
||||
0L, // keydr,
|
||||
SrtpEncryptionAESCM,
|
||||
SrtpAuthenticationSha1Hmac,
|
||||
&(*remoteMasterKey_.begin()),
|
||||
remoteMasterKey_.size(),
|
||||
&(*remoteMasterSalt_.begin()),
|
||||
remoteMasterSalt_.size(),
|
||||
crypto.encryptionKeyLength / BITS_PER_BYTE,
|
||||
crypto.srtpAuthKeyLength / BITS_PER_BYTE,
|
||||
crypto.masterSaltLength / BITS_PER_BYTE,
|
||||
crypto.srtpAuthTagLength / BITS_PER_BYTE);
|
||||
0, // roc,
|
||||
0L, // keydr,
|
||||
SrtpEncryptionAESCM,
|
||||
SrtpAuthenticationSha1Hmac,
|
||||
&(*remoteMasterKey_.begin()),
|
||||
remoteMasterKey_.size(),
|
||||
&(*remoteMasterSalt_.begin()),
|
||||
remoteMasterSalt_.size(),
|
||||
crypto.encryptionKeyLength / BITS_PER_BYTE,
|
||||
crypto.srtpAuthKeyLength / BITS_PER_BYTE,
|
||||
crypto.masterSaltLength / BITS_PER_BYTE,
|
||||
crypto.srtpAuthTagLength / BITS_PER_BYTE);
|
||||
|
||||
}
|
||||
|
||||
@ -299,18 +300,18 @@ void AudioSrtpSession::initializeLocalCryptoContext()
|
||||
const CryptoSuiteDefinition &crypto = sfl::CryptoSuites[localCryptoSuite_];
|
||||
|
||||
localCryptoCtx_ = new ost::CryptoContext(OutgoingDataQueue::getLocalSSRC(),
|
||||
0, // roc,
|
||||
0L, // keydr,
|
||||
SrtpEncryptionAESCM,
|
||||
SrtpAuthenticationSha1Hmac,
|
||||
&(*localMasterKey_.begin()),
|
||||
localMasterKey_.size(),
|
||||
&(*localMasterSalt_.begin()),
|
||||
localMasterSalt_.size(),
|
||||
crypto.encryptionKeyLength / BITS_PER_BYTE,
|
||||
crypto.srtpAuthKeyLength / BITS_PER_BYTE,
|
||||
crypto.masterSaltLength / BITS_PER_BYTE,
|
||||
crypto.srtpAuthTagLength / BITS_PER_BYTE);
|
||||
0, // roc,
|
||||
0L, // keydr,
|
||||
SrtpEncryptionAESCM,
|
||||
SrtpAuthenticationSha1Hmac,
|
||||
&(*localMasterKey_.begin()),
|
||||
localMasterKey_.size(),
|
||||
&(*localMasterSalt_.begin()),
|
||||
localMasterSalt_.size(),
|
||||
crypto.encryptionKeyLength / BITS_PER_BYTE,
|
||||
crypto.srtpAuthKeyLength / BITS_PER_BYTE,
|
||||
crypto.masterSaltLength / BITS_PER_BYTE,
|
||||
crypto.srtpAuthTagLength / BITS_PER_BYTE);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -43,7 +43,7 @@ AudioSymmetricRtpSession::AudioSymmetricRtpSession(SIPCall &call) :
|
||||
, AudioRtpSession(call, *this)
|
||||
{
|
||||
DEBUG("Setting new RTP session with destination %s:%d",
|
||||
call_.getLocalIp().c_str(), call_.getLocalAudioPort());
|
||||
call_.getLocalIp().c_str(), call_.getLocalAudioPort());
|
||||
audioRtpRecord_.callId_ = call_.getCallId();
|
||||
}
|
||||
|
||||
|
@ -151,12 +151,14 @@ ZrtpSessionCallback::zrtpNegotiationFailed(MessageSeverity severity, int subCode
|
||||
DEBUG("Sent error packet: ");
|
||||
|
||||
std::map<int32, std::string>::const_iterator iter = zrtpMap_.find(subCode);
|
||||
|
||||
if (iter != zrtpMap_.end()) {
|
||||
DEBUG("%s", iter->second.c_str());
|
||||
Manager::instance().getClient()->getCallManager()->zrtpNegotiationFailed(call_.getCallId(), iter->second, "ZRTP");
|
||||
}
|
||||
} else {
|
||||
std::map<int32, std::string>::const_iterator iter = severeMap_.find(subCode);
|
||||
|
||||
if (iter != severeMap_.end()) {
|
||||
DEBUG("%s", iter->second.c_str());
|
||||
Manager::instance().getClient()->getCallManager()->zrtpNegotiationFailed(call_.getCallId(), iter->second, "severe");
|
||||
|
@ -67,6 +67,7 @@ void
|
||||
AudioCodecFactory::setDefaultOrder()
|
||||
{
|
||||
defaultCodecList_.clear();
|
||||
|
||||
for (AudioCodecsMap::const_iterator i = codecsMap_.begin(); i != codecsMap_.end(); ++i)
|
||||
defaultCodecList_.push_back(i->first);
|
||||
}
|
||||
@ -86,6 +87,7 @@ std::vector<int32_t>
|
||||
AudioCodecFactory::getCodecList() const
|
||||
{
|
||||
std::vector<int32_t> list;
|
||||
|
||||
for (AudioCodecsMap::const_iterator iter = codecsMap_.begin(); iter != codecsMap_.end(); ++iter)
|
||||
if (iter->second)
|
||||
list.push_back((int32_t) iter->first);
|
||||
@ -159,7 +161,7 @@ AudioCodecFactory::saveActiveCodecs(const std::vector<std::string>& list)
|
||||
AudioCodecFactory::~AudioCodecFactory()
|
||||
{
|
||||
for (std::vector<AudioCodecHandlePointer>::iterator iter =
|
||||
codecInMemory_.begin(); iter != codecInMemory_.end(); ++iter)
|
||||
codecInMemory_.begin(); iter != codecInMemory_.end(); ++iter)
|
||||
unloadCodec(*iter);
|
||||
}
|
||||
|
||||
@ -237,6 +239,7 @@ AudioCodecFactory::loadCodec(const std::string &path)
|
||||
}
|
||||
|
||||
sfl::AudioCodec *a = static_cast<sfl::AudioCodec *>(createCodec());
|
||||
|
||||
if (a)
|
||||
codecInMemory_.push_back(AudioCodecHandlePointer(a, codecHandle));
|
||||
else
|
||||
@ -250,6 +253,7 @@ void
|
||||
AudioCodecFactory::unloadCodec(AudioCodecHandlePointer &ptr)
|
||||
{
|
||||
destroy_t *destroyCodec = 0;
|
||||
|
||||
if (ptr.second)
|
||||
destroyCodec = (destroy_t*) dlsym(ptr.second, "destroy");
|
||||
|
||||
@ -273,6 +277,7 @@ AudioCodecFactory::instantiateCodec(int payload) const
|
||||
std::vector<AudioCodecHandlePointer>::const_iterator iter;
|
||||
|
||||
sfl::AudioCodec *result = NULL;
|
||||
|
||||
for (iter = codecInMemory_.begin(); iter != codecInMemory_.end(); ++iter) {
|
||||
if (iter->first->getPayloadType() == payload) {
|
||||
create_t* createCodec = (create_t*) dlsym(iter->second , AUDIO_CODEC_ENTRY_SYMBOL);
|
||||
@ -308,26 +313,27 @@ AudioCodecFactory::seemsValid(const std::string &lib)
|
||||
return false;
|
||||
|
||||
static const std::string validCodecs[] = {
|
||||
"ulaw",
|
||||
"alaw",
|
||||
"g722",
|
||||
"g729", //G729 have to be loaded first, if it is valid or not is checked later
|
||||
"opus", //Opus have to be loaded first, if it is valid or not is checked later
|
||||
"opus_stereo",
|
||||
"ulaw",
|
||||
"alaw",
|
||||
"g722",
|
||||
"g729", //G729 have to be loaded first, if it is valid or not is checked later
|
||||
"opus", //Opus have to be loaded first, if it is valid or not is checked later
|
||||
"opus_stereo",
|
||||
#ifdef HAVE_SPEEX_CODEC
|
||||
"speex_nb",
|
||||
"speex_wb",
|
||||
"speex_ub",
|
||||
"speex_nb",
|
||||
"speex_wb",
|
||||
"speex_ub",
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GSM_CODEC
|
||||
"gsm",
|
||||
"gsm",
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_ILBC
|
||||
"ilbc",
|
||||
"ilbc",
|
||||
#endif
|
||||
""};
|
||||
""
|
||||
};
|
||||
|
||||
const std::string name(lib.substr(prefix.length(), len));
|
||||
const std::string *end = validCodecs + ARRAYSIZE(validCodecs);
|
||||
|
@ -41,7 +41,7 @@ class G722 : public sfl::AudioCodec {
|
||||
|
||||
public:
|
||||
G722() : sfl::AudioCodec(9, "G722", 16000, 320, 1), decode_state_(),
|
||||
encode_state_() {
|
||||
encode_state_() {
|
||||
bitrate_ = 64;
|
||||
hasDynamicPayload_ = false;
|
||||
|
||||
@ -61,8 +61,7 @@ class G722 : public sfl::AudioCodec {
|
||||
return out;
|
||||
}
|
||||
|
||||
static void g722_state_init(g722_state_t &state)
|
||||
{
|
||||
static void g722_state_init(g722_state_t &state) {
|
||||
state.itu_test_mode = false;
|
||||
|
||||
// 8 => 64 kbps; 7 => 56 kbps; 6 => 48 kbps
|
||||
@ -102,8 +101,7 @@ class G722 : public sfl::AudioCodec {
|
||||
return INT16_MIN;
|
||||
}
|
||||
|
||||
void block4_encode(int band, int d)
|
||||
{
|
||||
void block4_encode(int band, int d) {
|
||||
int wd1 = 0;
|
||||
int wd2 = 0;
|
||||
int wd3 = 0;
|
||||
@ -207,8 +205,7 @@ class G722 : public sfl::AudioCodec {
|
||||
|
||||
}
|
||||
|
||||
void block4_decode(int band, int d)
|
||||
{
|
||||
void block4_decode(int band, int d) {
|
||||
int wd1 = 0;
|
||||
int wd2 = 0;
|
||||
int wd3 = 0;
|
||||
|
@ -47,22 +47,23 @@ G729::G729() : sfl::AudioCodec(G729_PAYLOAD_TYPE, "G729", 8000, 160, 1),
|
||||
encoder_(0),
|
||||
decoder_(0)
|
||||
{
|
||||
handler_ = dlopen("libbcg729.so.0", RTLD_NOW);
|
||||
if (!handler_)
|
||||
throw std::runtime_error("g729: did not open shared lib");
|
||||
handler_ = dlopen("libbcg729.so.0", RTLD_NOW);
|
||||
|
||||
encoder_ = G729_TYPE_ENCODER dlsym(handler_, "bcg729Encoder");
|
||||
loadError(dlerror());
|
||||
decoder_ = G729_TYPE_DECODER dlsym(handler_, "bcg729Decoder");
|
||||
loadError(dlerror());
|
||||
if (!handler_)
|
||||
throw std::runtime_error("g729: did not open shared lib");
|
||||
|
||||
bcg729DecoderChannelContextStruct*(*decInit)() = G729_TYPE_DECODER_INIT dlsym(handler_, "initBcg729DecoderChannel");
|
||||
loadError(dlerror());
|
||||
bcg729EncoderChannelContextStruct*(*encInit)() = G729_TYPE_ENCODER_INIT dlsym(handler_, "initBcg729EncoderChannel");
|
||||
loadError(dlerror());
|
||||
encoder_ = G729_TYPE_ENCODER dlsym(handler_, "bcg729Encoder");
|
||||
loadError(dlerror());
|
||||
decoder_ = G729_TYPE_DECODER dlsym(handler_, "bcg729Decoder");
|
||||
loadError(dlerror());
|
||||
|
||||
decoderContext_ = (*decInit)();
|
||||
encoderContext_ = (*encInit)();
|
||||
bcg729DecoderChannelContextStruct*(*decInit)() = G729_TYPE_DECODER_INIT dlsym(handler_, "initBcg729DecoderChannel");
|
||||
loadError(dlerror());
|
||||
bcg729EncoderChannelContextStruct*(*encInit)() = G729_TYPE_ENCODER_INIT dlsym(handler_, "initBcg729EncoderChannel");
|
||||
loadError(dlerror());
|
||||
|
||||
decoderContext_ = (*decInit)();
|
||||
encoderContext_ = (*encInit)();
|
||||
}
|
||||
|
||||
G729::~G729()
|
||||
@ -73,22 +74,22 @@ G729::~G729()
|
||||
|
||||
int G729::decode(short *dst, unsigned char *buf, size_t buffer_size)
|
||||
{
|
||||
decoder_(decoderContext_, buf, false, dst);
|
||||
decoder_(decoderContext_, buf + (buffer_size / 2), false, dst + 80);
|
||||
return 160;
|
||||
decoder_(decoderContext_, buf, false, dst);
|
||||
decoder_(decoderContext_, buf + (buffer_size / 2), false, dst + 80);
|
||||
return 160;
|
||||
}
|
||||
|
||||
int G729::encode(unsigned char *dst, short *src, size_t buffer_size)
|
||||
{
|
||||
encoder_(encoderContext_, src, dst);
|
||||
encoder_(encoderContext_, src + (buffer_size / 2), dst + 10);
|
||||
return 20;
|
||||
encoder_(encoderContext_, src, dst);
|
||||
encoder_(encoderContext_, src + (buffer_size / 2), dst + 10);
|
||||
return 20;
|
||||
}
|
||||
|
||||
void G729::loadError(const char *error)
|
||||
{
|
||||
if (error != NULL)
|
||||
throw std::runtime_error("G729 failed to load");
|
||||
if (error != NULL)
|
||||
throw std::runtime_error("G729 failed to load");
|
||||
}
|
||||
|
||||
// cppcheck-suppress unusedFunction
|
||||
|
@ -46,10 +46,10 @@ extern "C" {
|
||||
|
||||
class Gsm : public sfl::AudioCodec {
|
||||
|
||||
public:
|
||||
public:
|
||||
// _payload should be 3
|
||||
Gsm() : sfl::AudioCodec(3, "GSM", 8000, 160, 1),
|
||||
decode_gsmhandle_(NULL), encode_gsmhandle_(NULL) {
|
||||
decode_gsmhandle_(NULL), encode_gsmhandle_(NULL) {
|
||||
bitrate_ = 13.3;
|
||||
hasDynamicPayload_ = false;
|
||||
|
||||
@ -60,8 +60,7 @@ public:
|
||||
throw std::runtime_error("ERROR: encode_gsm_create\n");
|
||||
}
|
||||
|
||||
~Gsm()
|
||||
{
|
||||
~Gsm() {
|
||||
gsm_destroy(decode_gsmhandle_);
|
||||
gsm_destroy(encode_gsmhandle_);
|
||||
}
|
||||
|
@ -41,8 +41,7 @@ class Ilbc: public sfl::AudioCodec {
|
||||
Ilbc() :
|
||||
sfl::AudioCodec(ILBC_PAYLOAD, "iLBC", 8000, ILBC_FRAME_SIZE, 1),
|
||||
ilbc_dec_(),
|
||||
ilbc_enc_()
|
||||
{
|
||||
ilbc_enc_() {
|
||||
bitrate_ = 13.3;
|
||||
|
||||
initDecode(&ilbc_dec_, 20, 1);
|
||||
|
@ -37,34 +37,37 @@ Opus::Opus() : sfl::AudioCodec(PAYLOAD_TYPE, "Opus", CLOCK_RATE, FRAME_SIZE, CHA
|
||||
encoder_(0),
|
||||
decoder_(0)
|
||||
{
|
||||
hasDynamicPayload_ = true;
|
||||
hasDynamicPayload_ = true;
|
||||
|
||||
int err = 0;
|
||||
encoder_ = opus_encoder_create(CLOCK_RATE, CHANNELS, OPUS_APPLICATION_VOIP, &err);
|
||||
if (err)
|
||||
throw std::runtime_error("opus: could not create encoder");
|
||||
int err = 0;
|
||||
encoder_ = opus_encoder_create(CLOCK_RATE, CHANNELS, OPUS_APPLICATION_VOIP, &err);
|
||||
|
||||
decoder_ = opus_decoder_create(CLOCK_RATE, CHANNELS, &err);
|
||||
if (err)
|
||||
throw std::runtime_error("opus: could not create decoder");
|
||||
if (err)
|
||||
throw std::runtime_error("opus: could not create encoder");
|
||||
|
||||
decoder_ = opus_decoder_create(CLOCK_RATE, CHANNELS, &err);
|
||||
|
||||
if (err)
|
||||
throw std::runtime_error("opus: could not create decoder");
|
||||
}
|
||||
|
||||
Opus::~Opus()
|
||||
{
|
||||
if (encoder_)
|
||||
opus_encoder_destroy(encoder_);
|
||||
|
||||
if (decoder_)
|
||||
opus_decoder_destroy(decoder_);
|
||||
}
|
||||
|
||||
int Opus::decode(short *dst, unsigned char *buf, size_t buffer_size)
|
||||
{
|
||||
return opus_decode(decoder_, buf, buffer_size, dst, FRAME_SIZE, 0);
|
||||
return opus_decode(decoder_, buf, buffer_size, dst, FRAME_SIZE, 0);
|
||||
}
|
||||
|
||||
int Opus::encode(unsigned char *dst, short *src, size_t buffer_size)
|
||||
{
|
||||
return opus_encode(encoder_, src, FRAME_SIZE, dst, buffer_size * 2);
|
||||
return opus_encode(encoder_, src, FRAME_SIZE, dst, buffer_size * 2);
|
||||
}
|
||||
|
||||
int Opus::decode(std::vector<std::vector<short> > *dst, unsigned char *buf, size_t buffer_size, size_t dst_offset /* = 0 */)
|
||||
|
@ -44,6 +44,7 @@ void DcBlocker::doProcess(SFLAudioSample *out, SFLAudioSample *in, int samples,
|
||||
for (unsigned i = 0; i < samples; ++i) {
|
||||
state->x_ = in[i];
|
||||
|
||||
|
||||
state->y_ = (SFLAudioSample) ((float) state->x_ - (float) state->xm1_ + 0.9999 * (float) state->y_);
|
||||
state->xm1_ = state->x_;
|
||||
state->ym1_ = state->y_;
|
||||
|
@ -38,26 +38,26 @@
|
||||
namespace {
|
||||
// decimation filter coefficient
|
||||
const float decimationCoefs[] = {-0.09870257, 0.07473655, 0.05616626, 0.04448337, 0.03630817, 0.02944626,
|
||||
0.02244098, 0.01463477, 0.00610982, -0.00266367, -0.01120109, -0.01873722,
|
||||
-0.02373243, -0.02602213, -0.02437806, -0.01869834, -0.00875287, 0.00500204,
|
||||
0.02183252, 0.04065763, 0.06015944, 0.0788299, 0.09518543, 0.10799179,
|
||||
0.1160644, 0.12889288, 0.1160644, 0.10799179, 0.09518543, 0.0788299,
|
||||
0.06015944, 0.04065763, 0.02183252, 0.00500204, -0.00875287, -0.01869834,
|
||||
-0.02437806, -0.02602213, -0.02373243, -0.01873722, -0.01120109, -0.00266367,
|
||||
0.00610982, 0.01463477, 0.02244098, 0.02944626, 0.03630817, 0.04448337,
|
||||
0.05616626, 0.07473655, -0.09870257
|
||||
};
|
||||
0.02244098, 0.01463477, 0.00610982, -0.00266367, -0.01120109, -0.01873722,
|
||||
-0.02373243, -0.02602213, -0.02437806, -0.01869834, -0.00875287, 0.00500204,
|
||||
0.02183252, 0.04065763, 0.06015944, 0.0788299, 0.09518543, 0.10799179,
|
||||
0.1160644, 0.12889288, 0.1160644, 0.10799179, 0.09518543, 0.0788299,
|
||||
0.06015944, 0.04065763, 0.02183252, 0.00500204, -0.00875287, -0.01869834,
|
||||
-0.02437806, -0.02602213, -0.02373243, -0.01873722, -0.01120109, -0.00266367,
|
||||
0.00610982, 0.01463477, 0.02244098, 0.02944626, 0.03630817, 0.04448337,
|
||||
0.05616626, 0.07473655, -0.09870257
|
||||
};
|
||||
std::vector<double> ird(decimationCoefs, decimationCoefs + sizeof(decimationCoefs) /sizeof(float));
|
||||
|
||||
|
||||
// decimation filter coefficient
|
||||
const float bandpassCoefs[] = {0.06278034, -0.0758545, -0.02274943, -0.0084497, 0.0702427, 0.05986113,
|
||||
0.06436469, -0.02412049, -0.03433526, -0.07568665, -0.03214543, -0.07236507,
|
||||
-0.06979052, -0.12446371, -0.05530828, 0.00947243, 0.15294699, 0.17735563,
|
||||
0.15294699, 0.00947243, -0.05530828, -0.12446371, -0.06979052, -0.07236507,
|
||||
-0.03214543, -0.07568665, -0.03433526, -0.02412049, 0.06436469, 0.05986113,
|
||||
0.0702427, -0.0084497, -0.02274943, -0.0758545, 0.06278034
|
||||
};
|
||||
0.06436469, -0.02412049, -0.03433526, -0.07568665, -0.03214543, -0.07236507,
|
||||
-0.06979052, -0.12446371, -0.05530828, 0.00947243, 0.15294699, 0.17735563,
|
||||
0.15294699, 0.00947243, -0.05530828, -0.12446371, -0.06979052, -0.07236507,
|
||||
-0.03214543, -0.07568665, -0.03433526, -0.02412049, 0.06436469, 0.05986113,
|
||||
0.0702427, -0.0084497, -0.02274943, -0.0758545, 0.06278034
|
||||
};
|
||||
std::vector<double> irb(bandpassCoefs, bandpassCoefs + sizeof(bandpassCoefs) / sizeof(float));
|
||||
} // end anonymous namespace
|
||||
|
||||
|
@ -111,6 +111,7 @@ double GainControl::DetectionAverage::getAverage(double in)
|
||||
previous_y_ = ((1.0 - g_a_) * in) + (g_a_ * previous_y_);
|
||||
else
|
||||
previous_y_ = ((1.0 - g_r_) * in) + (g_r_ * previous_y_);
|
||||
|
||||
return previous_y_;
|
||||
}
|
||||
|
||||
@ -120,7 +121,7 @@ GainControl::Limiter::Limiter(double r, double thresh) : ratio_(r), threshold_(t
|
||||
double GainControl::Limiter::limit(double in) const
|
||||
{
|
||||
double out = (in > threshold_ ? (ratio_ * (in - threshold_)) + threshold_ :
|
||||
in < -threshold_ ? (ratio_ * (in + threshold_)) - threshold_ : in);
|
||||
in < -threshold_ ? (ratio_ * (in + threshold_)) - threshold_ : in);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ MainBuffer::~MainBuffer()
|
||||
// delete any ring buffers that didn't get removed
|
||||
for (RingBufferMap::iterator iter = ringBufferMap_.begin(); iter != ringBufferMap_.end(); ++iter)
|
||||
delete iter->second;
|
||||
|
||||
pthread_mutex_destroy(&mutex_);
|
||||
}
|
||||
|
||||
@ -88,6 +89,7 @@ void MainBuffer::removeCallIDSet(const std::string &set_id)
|
||||
void MainBuffer::addCallIDtoSet(const std::string &set_id, const std::string &call_id)
|
||||
{
|
||||
CallIDSet* callid_set = getCallIDSet(set_id);
|
||||
|
||||
if (callid_set)
|
||||
callid_set->insert(call_id);
|
||||
else
|
||||
@ -229,7 +231,7 @@ void MainBuffer::unBindAll(const std::string & call_id)
|
||||
CallIDSet temp_set(*callid_set);
|
||||
|
||||
for (CallIDSet::iterator iter_set = temp_set.begin();
|
||||
iter_set != temp_set.end(); ++iter_set) {
|
||||
iter_set != temp_set.end(); ++iter_set) {
|
||||
std::string call_id_in_set(*iter_set);
|
||||
unBindCallID(call_id, call_id_in_set);
|
||||
}
|
||||
@ -323,6 +325,7 @@ size_t MainBuffer::availableForGet(const std::string &call_id)
|
||||
} else {
|
||||
|
||||
size_t availableSamples = INT_MAX;
|
||||
|
||||
for (CallIDSet::iterator i = callid_set->begin(); i != callid_set->end(); ++i) {
|
||||
const size_t nbSamples = availableForGetByID(*i, call_id);
|
||||
|
||||
@ -335,7 +338,7 @@ size_t MainBuffer::availableForGet(const std::string &call_id)
|
||||
}
|
||||
|
||||
size_t MainBuffer::availableForGetByID(const std::string &call_id,
|
||||
const std::string &reader_id) const
|
||||
const std::string &reader_id) const
|
||||
{
|
||||
if (call_id != DEFAULT_ID and reader_id == call_id)
|
||||
ERROR("RingBuffer has a readpointer on itself");
|
||||
@ -405,6 +408,7 @@ void MainBuffer::flushAllBuffers()
|
||||
void MainBuffer::dumpInfo()
|
||||
{
|
||||
sfl::ScopedLock guard(mutex_);
|
||||
|
||||
// print each call and bound call ids
|
||||
for (CallIDMap::const_iterator iter_call = callIDMap_.begin(); iter_call != callIDMap_.end(); ++iter_call) {
|
||||
std::string dbg_str(" Call: \t");
|
||||
@ -429,6 +433,7 @@ void MainBuffer::dumpInfo()
|
||||
dbg_str.append(" as read pointer: \t");
|
||||
|
||||
RingBuffer* rbuffer = iter_buffer->second;
|
||||
|
||||
if (rbuffer) {
|
||||
ReadPointer* rpointer = rbuffer->getReadPointerList();
|
||||
|
||||
@ -439,6 +444,7 @@ void MainBuffer::dumpInfo()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG("%s", dbg_str.c_str());
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ void stream_moved_callback(pa_stream *s, void *userdata UNUSED)
|
||||
} // end anonymous namespace
|
||||
|
||||
#ifdef RECTODISK
|
||||
std::ofstream outfileResampled ("testMicOuputResampled.raw", std::ifstream::binary);
|
||||
std::ofstream outfileResampled("testMicOuputResampled.raw", std::ifstream::binary);
|
||||
std::ofstream outfile("testMicOuput.raw", std::ifstream::binary);
|
||||
#endif
|
||||
|
||||
@ -94,8 +94,10 @@ PulseLayer::PulseLayer(AudioPreference &pref)
|
||||
pa_proplist_sets(pl, PA_PROP_MEDIA_ROLE, "phone");
|
||||
|
||||
context_ = pa_context_new_with_proplist(pa_threaded_mainloop_get_api(mainloop_), "SFLphone", pl);
|
||||
|
||||
if (pl)
|
||||
pa_proplist_free(pl);
|
||||
|
||||
#else
|
||||
setenv("PULSE_PROP_media.role", "phone", 1);
|
||||
context_ = pa_context_new(pa_threaded_mainloop_get_api(mainloop_), "SFLphone");
|
||||
@ -150,7 +152,7 @@ void PulseLayer::context_state_callback(pa_context* c, void *user_data)
|
||||
PulseLayer *pulse = static_cast<PulseLayer*>(user_data);
|
||||
assert(c and pulse and pulse->mainloop_);
|
||||
const pa_subscription_mask_t mask = (pa_subscription_mask_t)
|
||||
(PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE);
|
||||
(PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE);
|
||||
|
||||
switch (pa_context_get_state(c)) {
|
||||
case PA_CONTEXT_CONNECTING:
|
||||
@ -186,6 +188,7 @@ void PulseLayer::updateSinkList()
|
||||
sinkList_.clear();
|
||||
enumeratingSinks_ = true;
|
||||
pa_operation *op = pa_context_get_sink_info_list(context_, sink_input_info_callback, this);
|
||||
|
||||
if (op != NULL)
|
||||
pa_operation_unref(op);
|
||||
}
|
||||
@ -195,6 +198,7 @@ void PulseLayer::updateSourceList()
|
||||
sourceList_.clear();
|
||||
enumeratingSources_ = true;
|
||||
pa_operation *op = pa_context_get_source_info_list(context_, source_input_info_callback, this);
|
||||
|
||||
if (op != NULL)
|
||||
pa_operation_unref(op);
|
||||
}
|
||||
@ -236,9 +240,11 @@ std::vector<std::string> PulseLayer::getPlaybackDeviceList() const
|
||||
int PulseLayer::getAudioDeviceIndex(const std::string& name) const
|
||||
{
|
||||
int index = std::distance(sourceList_.begin(), std::find_if(sourceList_.begin(), sourceList_.end(), PaDeviceInfos::nameComparator(name)));
|
||||
|
||||
if (index == std::distance(sourceList_.begin(), sourceList_.end())) {
|
||||
index = std::distance(sinkList_.begin(), std::find_if(sinkList_.begin(), sinkList_.end(), PaDeviceInfos::nameComparator(name)));
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
@ -260,12 +266,14 @@ std::string PulseLayer::getAudioDeviceName(int index, PCMType type) const
|
||||
return "";
|
||||
}
|
||||
return sinkList_[index].name;
|
||||
|
||||
case SFL_PCM_CAPTURE:
|
||||
if (index < 0 or static_cast<size_t>(index) >= sourceList_.size()) {
|
||||
ERROR("Index %d out of range", index);
|
||||
return "";
|
||||
}
|
||||
return sourceList_[index].name;
|
||||
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
@ -324,13 +332,13 @@ void PulseLayer::createStreams(pa_context* c)
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Delete stream and zero out its pointer
|
||||
void
|
||||
cleanupStream(AudioStream *&stream)
|
||||
{
|
||||
delete stream;
|
||||
stream = 0;
|
||||
}
|
||||
// Delete stream and zero out its pointer
|
||||
void
|
||||
cleanupStream(AudioStream *&stream)
|
||||
{
|
||||
delete stream;
|
||||
stream = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -403,6 +411,7 @@ void PulseLayer::writeToSpeaker()
|
||||
}
|
||||
|
||||
SFLAudioSample *data = 0;
|
||||
|
||||
if (urgentBytes) {
|
||||
AudioBuffer linearbuff(urgentSamples, n_channels);
|
||||
pa_stream_begin_write(s, (void**)&data, &urgentBytes);
|
||||
@ -449,6 +458,7 @@ void PulseLayer::writeToSpeaker()
|
||||
|
||||
unsigned int mainBufferSampleRate = Manager::instance().getMainBuffer().getInternalSamplingRate();
|
||||
bool resample = sampleRate_ != mainBufferSampleRate;
|
||||
|
||||
if (resample) {
|
||||
resampleFactor = (double) sampleRate_ / mainBufferSampleRate;
|
||||
readableSamples = (double) readableSamples / resampleFactor;
|
||||
@ -564,9 +574,9 @@ void PulseLayer::ringtoneToSpeaker()
|
||||
//applyGain(static_cast<SFLAudioSample *>(data), bytes / sizeof(SFLAudioSample), getPlaybackGain());
|
||||
fileToPlay->getNext(tmp, getPlaybackGain());
|
||||
tmp.interleave((SFLAudioSample*)data);
|
||||
}
|
||||
else
|
||||
} else {
|
||||
memset(data, 0, bytes);
|
||||
}
|
||||
|
||||
pa_stream_write(s, data, bytes, NULL, 0, PA_SEEK_RELATIVE);
|
||||
}
|
||||
@ -577,8 +587,9 @@ PulseLayer::context_changed_callback(pa_context* c,
|
||||
uint32_t idx UNUSED, void *userdata)
|
||||
{
|
||||
PulseLayer *context = static_cast<PulseLayer*>(userdata);
|
||||
|
||||
switch (type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
|
||||
pa_operation *op;
|
||||
pa_operation *op;
|
||||
|
||||
case PA_SUBSCRIPTION_EVENT_SINK:
|
||||
switch (type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) {
|
||||
@ -587,11 +598,14 @@ PulseLayer::context_changed_callback(pa_context* c,
|
||||
DEBUG("Updating sink list");
|
||||
context->sinkList_.clear();
|
||||
op = pa_context_get_sink_info_list(c, sink_input_info_callback, userdata);
|
||||
|
||||
if (op != NULL)
|
||||
pa_operation_unref(op);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PA_SUBSCRIPTION_EVENT_SOURCE:
|
||||
@ -601,12 +615,16 @@ PulseLayer::context_changed_callback(pa_context* c,
|
||||
DEBUG("Updating source list");
|
||||
context->sourceList_.clear();
|
||||
op = pa_context_get_source_info_list(c, source_input_info_callback, userdata);
|
||||
|
||||
if (op != NULL)
|
||||
pa_operation_unref(op);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG("Unhandled event type 0x%x", type);
|
||||
break;
|
||||
@ -625,29 +643,29 @@ void PulseLayer::source_input_info_callback(pa_context *c UNUSED, const pa_sourc
|
||||
}
|
||||
|
||||
DEBUG("Source %u\n"
|
||||
" Name: %s\n"
|
||||
" Driver: %s\n"
|
||||
" Description: %s\n"
|
||||
" Sample Specification: %s\n"
|
||||
" Channel Map: %s\n"
|
||||
" Owner Module: %u\n"
|
||||
" Volume: %s\n"
|
||||
" Monitor if Sink: %u\n"
|
||||
" Latency: %0.0f usec\n"
|
||||
" Flags: %s%s%s\n",
|
||||
i->index,
|
||||
i->name,
|
||||
i->driver,
|
||||
i->description,
|
||||
pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
|
||||
pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
|
||||
i->owner_module,
|
||||
i->mute ? "muted" : pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
|
||||
i->monitor_of_sink,
|
||||
(double) i->latency,
|
||||
i->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
|
||||
i->flags & PA_SOURCE_LATENCY ? "LATENCY " : "",
|
||||
i->flags & PA_SOURCE_HARDWARE ? "HARDWARE" : "");
|
||||
" Name: %s\n"
|
||||
" Driver: %s\n"
|
||||
" Description: %s\n"
|
||||
" Sample Specification: %s\n"
|
||||
" Channel Map: %s\n"
|
||||
" Owner Module: %u\n"
|
||||
" Volume: %s\n"
|
||||
" Monitor if Sink: %u\n"
|
||||
" Latency: %0.0f usec\n"
|
||||
" Flags: %s%s%s\n",
|
||||
i->index,
|
||||
i->name,
|
||||
i->driver,
|
||||
i->description,
|
||||
pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
|
||||
pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
|
||||
i->owner_module,
|
||||
i->mute ? "muted" : pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
|
||||
i->monitor_of_sink,
|
||||
(double) i->latency,
|
||||
i->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
|
||||
i->flags & PA_SOURCE_LATENCY ? "LATENCY " : "",
|
||||
i->flags & PA_SOURCE_HARDWARE ? "HARDWARE" : "");
|
||||
|
||||
if (not context->inSourceList(i->name)) {
|
||||
PaDeviceInfos ep_infos(i->index, i->name, i->sample_spec, i->channel_map);
|
||||
@ -699,19 +717,23 @@ void PulseLayer::sink_input_info_callback(pa_context *c UNUSED, const pa_sink_in
|
||||
void PulseLayer::updatePreference(AudioPreference &preference, int index, PCMType type)
|
||||
{
|
||||
const std::string devName(getAudioDeviceName(index, type));
|
||||
|
||||
switch (type) {
|
||||
case SFL_PCM_PLAYBACK:
|
||||
DEBUG("setting %s for playback", devName.c_str());
|
||||
preference.setPulseDevicePlayback(devName);
|
||||
break;
|
||||
|
||||
case SFL_PCM_CAPTURE:
|
||||
DEBUG("setting %s for capture", devName.c_str());
|
||||
preference.setPulseDeviceRecord(devName);
|
||||
break;
|
||||
|
||||
case SFL_PCM_RINGTONE:
|
||||
DEBUG("setting %s for ringer", devName.c_str());
|
||||
preference.setPulseDeviceRingtone(devName);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -41,8 +41,8 @@
|
||||
#include "ringbuffer.h"
|
||||
|
||||
namespace {
|
||||
// corresponds to 160 ms (about 5 rtp packets)
|
||||
const size_t MIN_BUFFER_SIZE = 1280;
|
||||
// corresponds to 160 ms (about 5 rtp packets)
|
||||
const size_t MIN_BUFFER_SIZE = 1280;
|
||||
}
|
||||
|
||||
// Create a ring buffer with 'size' bytes
|
||||
@ -192,6 +192,7 @@ void RingBuffer::put(AudioBuffer& buf)
|
||||
pos = (pos + block) % buffer_size;
|
||||
toCopy -= block;
|
||||
}
|
||||
|
||||
endPos_ = pos;
|
||||
}
|
||||
|
||||
|
@ -71,8 +71,7 @@ bool DTMF::generateDTMF(vector<SFLAudioSample> &buffer)
|
||||
dtmfgenerator_.getSamples(buffer, newTone_);
|
||||
currentTone_ = newTone_;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
} catch (const DTMFException &e) {
|
||||
|
@ -111,6 +111,7 @@ void DTMFGenerator::getSamples(vector<SFLAudioSample> &buffer, unsigned char cod
|
||||
|
||||
size_t i;
|
||||
const size_t n = buffer.size();
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
buffer[i] = state.sample[i % sampleRate_];
|
||||
|
||||
@ -128,6 +129,7 @@ void DTMFGenerator::getNextSamples(vector<SFLAudioSample> &buffer)
|
||||
|
||||
size_t i;
|
||||
const size_t n = buffer.size();
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
buffer[i] = state.sample[(state.offset + i) % sampleRate_];
|
||||
|
||||
|
Reference in New Issue
Block a user