Commit 11b168e7 authored by Rafaël Carré's avatar Rafaël Carré
Browse files

* #6229 : remove malloc/free from pulse audio loop

use pa_stream_begin_write() when writing to speakers
parent fa186c4d
...@@ -51,20 +51,7 @@ int DcBlocker::getData (SFLDataFormat *outputData UNUSED) ...@@ -51,20 +51,7 @@ int DcBlocker::getData (SFLDataFormat *outputData UNUSED)
void DcBlocker::process (SFLDataFormat *data, int nbBytes) void DcBlocker::process (SFLDataFormat *data, int nbBytes)
{ {
// y(n) = x(n) - x(n-1) + R y(n-1) , R = 0.9999 abort(); // use the 3 args prototype with input == output
int nbSamples = nbBytes / sizeof (SFLDataFormat);
for (int i = 0; i < nbSamples; i++) {
_x = data[i];
_y = (SFLDataFormat) ( (float) _x - (float) _xm1 + 0.995 * (float) _ym1);
_xm1 = _x;
_ym1 = _y;
data[i] = _y;
}
} }
int DcBlocker::process (SFLDataFormat *inputData, SFLDataFormat *outputData, int nbBytes) int DcBlocker::process (SFLDataFormat *inputData, SFLDataFormat *outputData, int nbBytes)
......
...@@ -57,16 +57,7 @@ class DcBlocker : public Algorithm ...@@ -57,16 +57,7 @@ class DcBlocker : public Algorithm
*/ */
virtual int getData (SFLDataFormat *outputData); virtual int getData (SFLDataFormat *outputData);
/** virtual void process (SFLDataFormat *inputData, int nbBytes);
* Perform dc blocking given the input data
*/
virtual void process (SFLDataFormat *data, int nbBytes);
/**
* Perform echo cancellation using internal buffers
* \param inputData containing mixed echo and voice data
* \param outputData containing
*/
virtual int process (SFLDataFormat *inputData, SFLDataFormat *outputData, int nbBytes); virtual int process (SFLDataFormat *inputData, SFLDataFormat *outputData, int nbBytes);
private: private:
......
...@@ -197,6 +197,8 @@ PulseLayer::PulseLayer () ...@@ -197,6 +197,8 @@ PulseLayer::PulseLayer ()
, playback_(0) , playback_(0)
, record_(0) , record_(0)
, ringtone_(0) , ringtone_(0)
, mic_buffer_(NULL)
, mic_buf_size_(0)
{ {
setenv ("PULSE_PROP_media.role", "phone", 1); setenv ("PULSE_PROP_media.role", "phone", 1);
...@@ -241,6 +243,8 @@ PulseLayer::~PulseLayer (void) ...@@ -241,6 +243,8 @@ PulseLayer::~PulseLayer (void)
if (mainloop_) if (mainloop_)
pa_threaded_mainloop_free (mainloop_); pa_threaded_mainloop_free (mainloop_);
delete[] mic_buffer_;
} }
void PulseLayer::context_state_callback (pa_context* c, void* user_data) void PulseLayer::context_state_callback (pa_context* c, void* user_data)
...@@ -314,19 +318,19 @@ void PulseLayer::createStreams (pa_context* c) ...@@ -314,19 +318,19 @@ void PulseLayer::createStreams (pa_context* c)
_debug ("PulseAudio: Devices: playback %s , record %s , ringtone %s", _debug ("PulseAudio: Devices: playback %s , record %s , ringtone %s",
playbackDevice.c_str(), recordDevice.c_str(), ringtoneDevice.c_str()); playbackDevice.c_str(), recordDevice.c_str(), ringtoneDevice.c_str());
playback_ = new AudioStream (c, mainloop_, PLAYBACK_STREAM_NAME, PLAYBACK_STREAM, audioSampleRate_, playback_ = new AudioStream (c, mainloop_, "SFLphone playback", PLAYBACK_STREAM, audioSampleRate_,
inSinkList(playbackDevice) ? &playbackDevice : NULL); inSinkList(playbackDevice) ? &playbackDevice : NULL);
pa_stream_set_write_callback (playback_->pulseStream(), playback_callback, this); pa_stream_set_write_callback (playback_->pulseStream(), playback_callback, this);
pa_stream_set_moved_callback (playback_->pulseStream(), stream_moved_callback, this); pa_stream_set_moved_callback (playback_->pulseStream(), stream_moved_callback, this);
record_ = new AudioStream (c, mainloop_, CAPTURE_STREAM_NAME, CAPTURE_STREAM, audioSampleRate_, record_ = new AudioStream (c, mainloop_, "SFLphone capture", CAPTURE_STREAM, audioSampleRate_,
inSourceList(recordDevice) ? &recordDevice : NULL); inSourceList(recordDevice) ? &recordDevice : NULL);
pa_stream_set_read_callback (record_->pulseStream() , capture_callback, this); pa_stream_set_read_callback (record_->pulseStream() , capture_callback, this);
pa_stream_set_moved_callback (record_->pulseStream(), stream_moved_callback, this); pa_stream_set_moved_callback (record_->pulseStream(), stream_moved_callback, this);
ringtone_ = new AudioStream (c, mainloop_, RINGTONE_STREAM_NAME, RINGTONE_STREAM, audioSampleRate_, ringtone_ = new AudioStream (c, mainloop_, "SFLphone ringtone", RINGTONE_STREAM, audioSampleRate_,
inSourceList(ringtoneDevice) ? &ringtoneDevice : NULL); inSourceList(ringtoneDevice) ? &ringtoneDevice : NULL);
pa_stream_set_write_callback (ringtone_->pulseStream(), ringtone_callback, this); pa_stream_set_write_callback (ringtone_->pulseStream(), ringtone_callback, this);
...@@ -410,24 +414,26 @@ void PulseLayer::writeToSpeaker (void) ...@@ -410,24 +414,26 @@ void PulseLayer::writeToSpeaker (void)
if (!playback_ or !playback_->isReady()) if (!playback_ or !playback_->isReady())
return; return;
pa_stream *s = playback_->pulseStream();
// available bytes to be written in pulseaudio internal buffer // available bytes to be written in pulseaudio internal buffer
int writeableSizeBytes = pa_stream_writable_size (playback_->pulseStream()); int writable = pa_stream_writable_size(s);
if (writeableSizeBytes < 0) if (writable < 0)
_error("Pulse: playback error : %s", pa_strerror (writeableSizeBytes)); _error("Pulse: playback error : %s", pa_strerror(writable));
if (writeableSizeBytes <= 0) if (writable <= 0)
return; return;
size_t bytes = writable;
void *data;
notifyincomingCall(); notifyincomingCall();
size_t urgentBytes = urgentRingBuffer_.AvailForGet();
int urgentBytes = urgentRingBuffer_.AvailForGet(); if (urgentBytes > bytes)
if (urgentBytes > writeableSizeBytes) urgentBytes = bytes;
urgentBytes = writeableSizeBytes;
if (urgentBytes) { if (urgentBytes) {
SFLDataFormat *out = (SFLDataFormat*) pa_xmalloc (urgentBytes); pa_stream_begin_write(s, &data, &urgentBytes);
urgentRingBuffer_.Get (out, urgentBytes); urgentRingBuffer_.Get (data, urgentBytes);
pa_stream_write (playback_->pulseStream(), out, urgentBytes, NULL, 0, PA_SEEK_RELATIVE); pa_stream_write (s, data, urgentBytes, NULL, 0, PA_SEEK_RELATIVE);
pa_xfree (out);
// Consume the regular one as well (same amount of bytes) // Consume the regular one as well (same amount of bytes)
getMainBuffer()->discard (urgentBytes); getMainBuffer()->discard (urgentBytes);
return; return;
...@@ -436,22 +442,20 @@ void PulseLayer::writeToSpeaker (void) ...@@ -436,22 +442,20 @@ void PulseLayer::writeToSpeaker (void)
AudioLoop *toneToPlay = Manager::instance().getTelephoneTone(); AudioLoop *toneToPlay = Manager::instance().getTelephoneTone();
if (toneToPlay) { if (toneToPlay) {
if (playback_->isReady()) { if (playback_->isReady()) {
SFLDataFormat *out = (SFLDataFormat*) pa_xmalloc (writeableSizeBytes); pa_stream_begin_write(s, &data, &bytes);
toneToPlay->getNext (out, writeableSizeBytes / sizeof (SFLDataFormat), 100); toneToPlay->getNext ((SFLDataFormat*)data, bytes / sizeof (SFLDataFormat), 100);
pa_stream_write (playback_->pulseStream(), out, writeableSizeBytes, NULL, 0, PA_SEEK_RELATIVE); pa_stream_write (s, data, bytes, NULL, 0, PA_SEEK_RELATIVE);
pa_xfree (out);
} }
return; return;
} }
flushUrgent(); // flush remaining samples in _urgentRingBuffer flushUrgent(); // flush remaining samples in _urgentRingBuffer
int availSamples = getMainBuffer()->availForGet() / sizeof(SFLDataFormat); size_t availSamples = getMainBuffer()->availForGet() / sizeof(SFLDataFormat);
if (availSamples == 0) { if (availSamples == 0) {
// play silence pa_stream_begin_write(s, &data, &bytes);
SFLDataFormat* zeros = (SFLDataFormat*) pa_xmalloc0(writeableSizeBytes); memset(data, 0, bytes);
pa_stream_write (playback_->pulseStream(), zeros, writeableSizeBytes, NULL, 0, PA_SEEK_RELATIVE); pa_stream_write (s, data, bytes, NULL, 0, PA_SEEK_RELATIVE);
pa_xfree (zeros);
return; return;
} }
...@@ -459,10 +463,10 @@ void PulseLayer::writeToSpeaker (void) ...@@ -459,10 +463,10 @@ void PulseLayer::writeToSpeaker (void)
bool resample = audioSampleRate_ != mainBufferSampleRate; bool resample = audioSampleRate_ != mainBufferSampleRate;
// how much samples we can write in the output // how much samples we can write in the output
int outSamples = writeableSizeBytes / sizeof(SFLDataFormat); size_t outSamples = bytes / sizeof(SFLDataFormat);
// how much samples we want to read from the buffer // how much samples we want to read from the buffer
int inSamples = outSamples; size_t inSamples = outSamples;
double resampleFactor = 1.; double resampleFactor = 1.;
if (resample) { if (resample) {
...@@ -472,21 +476,19 @@ void PulseLayer::writeToSpeaker (void) ...@@ -472,21 +476,19 @@ void PulseLayer::writeToSpeaker (void)
if (inSamples > availSamples) if (inSamples > availSamples)
inSamples = availSamples; inSamples = availSamples;
int outBytes = (double)inSamples * resampleFactor * sizeof(SFLDataFormat); size_t outBytes = (double)inSamples * resampleFactor * sizeof(SFLDataFormat);
int inBytes = inSamples * sizeof (SFLDataFormat); size_t inBytes = inSamples * sizeof (SFLDataFormat);
SFLDataFormat *out = (SFLDataFormat*) pa_xmalloc (inBytes); pa_stream_begin_write(s, &data, &inBytes);
getMainBuffer()->getData (out, inBytes); getMainBuffer()->getData (data, inBytes);
if (resample) { if (resample) {
SFLDataFormat* rsmpl_out = (SFLDataFormat*) pa_xmalloc (outBytes); SFLDataFormat* rsmpl_out = (SFLDataFormat*) pa_xmalloc (outBytes);
converter_->resample (out, rsmpl_out, mainBufferSampleRate, audioSampleRate_, inSamples); converter_->resample((SFLDataFormat*)data, rsmpl_out, mainBufferSampleRate, audioSampleRate_, inSamples);
pa_stream_write (playback_->pulseStream(), rsmpl_out, outBytes, NULL, 0, PA_SEEK_RELATIVE); pa_stream_write (s, rsmpl_out, outBytes, NULL, 0, PA_SEEK_RELATIVE);
pa_xfree (rsmpl_out); pa_xfree (rsmpl_out);
} else } else
pa_stream_write (playback_->pulseStream(), out, inBytes, NULL, 0, PA_SEEK_RELATIVE); pa_stream_write (s, data, inBytes, NULL, 0, PA_SEEK_RELATIVE);
pa_xfree (out);
} }
void PulseLayer::readFromMic (void) void PulseLayer::readFromMic (void)
...@@ -495,33 +497,34 @@ void PulseLayer::readFromMic (void) ...@@ -495,33 +497,34 @@ void PulseLayer::readFromMic (void)
return; return;
const char *data = NULL; const char *data = NULL;
size_t r; size_t bytes;
SFLDataFormat *out; size_t samples;
unsigned int mainBufferSampleRate = getMainBuffer()->getInternalSamplingRate(); unsigned int mainBufferSampleRate = getMainBuffer()->getInternalSamplingRate();
bool resample = audioSampleRate_ != mainBufferSampleRate; bool resample = audioSampleRate_ != mainBufferSampleRate;
if (pa_stream_peek (record_->pulseStream() , (const void**) &data , &r) < 0 or !data) { if (pa_stream_peek (record_->pulseStream() , (const void**) &data , &bytes) < 0 or !data) {
_error("Audio: Error capture stream peek failed: %s" , pa_strerror (pa_context_errno (context_))); _error("Audio: Error capture stream peek failed: %s" , pa_strerror (pa_context_errno (context_)));
goto end; goto end;
} }
if (resample) { if (resample) {
double resampleFactor = (double) audioSampleRate_ / mainBufferSampleRate; double resampleFactor = (double) audioSampleRate_ / mainBufferSampleRate;
r = (double) r * resampleFactor; bytes = (double) bytes * resampleFactor;
} }
out = (SFLDataFormat*) pa_xmalloc (r); samples = bytes / sizeof(SFLDataFormat);
if (bytes > mic_buf_size_) {
if (resample) { mic_buf_size_ = bytes;
converter_->resample ( (SFLDataFormat *) data, out, mainBufferSampleRate, audioSampleRate_, r / sizeof(SFLDataFormat)); delete[] mic_buffer_;
dcblocker_.process(out, r); mic_buffer_ = new SFLDataFormat[samples];
} else {
dcblocker_.process( (SFLDataFormat *) data, out, r);
} }
getMainBuffer()->putData (out, r); if (resample)
pa_xfree (out); converter_->resample((SFLDataFormat*)data, mic_buffer_, mainBufferSampleRate, audioSampleRate_, samples);
dcblocker_.process(resample ? mic_buffer_ : (SFLDataFormat*)data, mic_buffer_, bytes);
getMainBuffer()->putData(mic_buffer_, bytes);
end: end:
if (pa_stream_drop (record_->pulseStream()) < 0) if (pa_stream_drop (record_->pulseStream()) < 0)
...@@ -532,22 +535,25 @@ end: ...@@ -532,22 +535,25 @@ end:
void PulseLayer::ringtoneToSpeaker (void) void PulseLayer::ringtoneToSpeaker (void)
{ {
if (!ringtone_ or !ringtone_->isReady()) if (!ringtone_ or !ringtone_->isReady())
return; return;
pa_stream *s = ringtone_->pulseStream();
int writableSize = pa_stream_writable_size (ringtone_->pulseStream()); int writable = pa_stream_writable_size (s);
if (writableSize < 0) if (writable < 0)
_error("Pulse: ringtone error : %s", pa_strerror (writableSize)); _error("Pulse: ringtone error : %s", pa_strerror (writable));
if (writableSize <= 0) if (writable <= 0)
return; return;
SFLDataFormat *out = (SFLDataFormat *) pa_xmalloc (writableSize); size_t bytes = writable;
void *data;
pa_stream_begin_write(s, &data, &bytes);
AudioLoop *fileToPlay = Manager::instance().getTelephoneFile(); AudioLoop *fileToPlay = Manager::instance().getTelephoneFile();
if (fileToPlay) if (fileToPlay)
fileToPlay->getNext (out, writableSize/sizeof (SFLDataFormat), 100); fileToPlay->getNext((SFLDataFormat*)data, bytes / sizeof(SFLDataFormat), 100);
else else
memset (out, 0, writableSize); memset(data, 0, bytes);
pa_stream_write (ringtone_->pulseStream(), out, writableSize, NULL, 0, PA_SEEK_RELATIVE); pa_stream_write(s, data, bytes, NULL, 0, PA_SEEK_RELATIVE);
pa_xfree (out);
} }
...@@ -39,17 +39,7 @@ ...@@ -39,17 +39,7 @@
#include <list> #include <list>
#include <string> #include <string>
#define PLAYBACK_STREAM_NAME "SFLphone playback"
#define CAPTURE_STREAM_NAME "SFLphone capture"
#define RINGTONE_STREAM_NAME "SFLphone ringtone"
class RingBuffer;
class ManagerImpl;
class AudioStream; class AudioStream;
class DcBlocker;
class SamplerateConverter;
typedef std::list<std::string> DeviceList;
class PulseLayer : public AudioLayer class PulseLayer : public AudioLayer
{ {
...@@ -57,11 +47,11 @@ class PulseLayer : public AudioLayer ...@@ -57,11 +47,11 @@ class PulseLayer : public AudioLayer
PulseLayer (); PulseLayer ();
~PulseLayer (void); ~PulseLayer (void);
DeviceList* getSinkList (void) { std::list<std::string>* getSinkList (void) {
return &sinkList_; return &sinkList_;
} }
DeviceList* getSourceList (void) { std::list<std::string>* getSourceList (void) {
return &sourceList_; return &sourceList_;
} }
...@@ -124,8 +114,14 @@ class PulseLayer : public AudioLayer ...@@ -124,8 +114,14 @@ class PulseLayer : public AudioLayer
*/ */
AudioStream* ringtone_; AudioStream* ringtone_;
DeviceList sinkList_; std::list<std::string> sinkList_;
DeviceList sourceList_; std::list<std::string> sourceList_;
/*
* Buffers used to avoid doing malloc/free in the audio thread
*/
SFLDataFormat *mic_buffer_;
size_t mic_buf_size_;
public: public:
friend class AudioLayerTest; friend class AudioLayerTest;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment