Commit 29b40b54 authored by Adrien Béraud's avatar Adrien Béraud

Bugfix with opensllayer

parent 1c21b1cd
......@@ -51,6 +51,18 @@ AudioBuffer::AudioBuffer(const AudioBuffer& other, bool copy_content /* = false
std::vector<std::vector<SFLAudioSample> >(other.samples_.size(), std::vector<SFLAudioSample>(other.frames())))
{}
AudioBuffer& AudioBuffer::operator=(const AudioBuffer& other) {
samples_ = other.samples_;
sampleRate_ = other.sampleRate_;
return *this;
}
AudioBuffer& AudioBuffer::operator=(AudioBuffer&& other) {
samples_ = std::move( other.samples_ );
sampleRate_ = other.sampleRate_;
return *this;
}
int AudioBuffer::getSampleRate() const
{
return sampleRate_;
......@@ -114,11 +126,11 @@ void AudioBuffer::applyGain(double gain)
size_t AudioBuffer::interleave(SFLAudioSample* out) const
{
for (unsigned i = 0; i < frames(); i++)
for (unsigned j = 0; j < samples_.size(); j++)
for (unsigned i=0, f=frames(), c=channels(); i < f; ++i)
for (unsigned j = 0; j < c; ++j)
*out++ = samples_[j][i];
return frames() * samples_.size();
return frames() * channels();
}
size_t AudioBuffer::interleaveFloat(float* out) const
......@@ -139,8 +151,8 @@ void AudioBuffer::deinterleave(const SFLAudioSample* in, size_t sample_num, unsi
setChannelNum(channel_num);
resize(sample_num);
for (unsigned i = 0; i < frames(); i++)
for (unsigned j = 0; j < samples_.size(); j++)
for (unsigned i=0, f=frames(), c=channels(); i < f; i++)
for (unsigned j = 0; j < c; j++)
samples_[j][i] = *in++;
}
......
......@@ -54,10 +54,25 @@ class AudioBuffer {
* If copy_content is set to true, the other buffer content is also copied.
*/
AudioBuffer(const AudioBuffer& other, bool copy_content = false);
/**
* Move contructor
*/
AudioBuffer(AudioBuffer&& other) : sampleRate_(other.sampleRate_), samples_( std::move(other.samples_) ) {};
/**
* Copy operator
*/
AudioBuffer& operator=(const AudioBuffer& other);
/**
* Move operator
*/
AudioBuffer& operator=(AudioBuffer&& other);
void reset() {
for (std::vector<std::vector<SFLAudioSample> >::iterator i = samples_.begin(); i != samples_.end(); ++i)
std::fill(i->begin(), i->end(), 0);
for(auto& c : samples_)
std::fill(c.begin(), c.end(), 0);
}
inline size_t size() {
......@@ -124,7 +139,7 @@ class AudioBuffer {
/**
* Return the data (audio samples) for a given channel number.
* Channel data can be modified but size of individual channel vectors should not be changed manually.
* Channel data can be modified but size of individual channel vectors should not be changed by the user.
*/
std::vector<SFLAudioSample> *getChannel(unsigned chan);
......@@ -137,7 +152,7 @@ class AudioBuffer {
/**
* Write interleaved multichannel data to the out buffer (fixed-point 16-bits).
* The out buffer must be at least large by capacity()*sizeof(SFLAudioSample) bytes.
* The out buffer must be at least of size capacity()*sizeof(SFLAudioSample) bytes.
*
* @returns Number of samples writen.
*/
......@@ -145,7 +160,7 @@ class AudioBuffer {
/**
* Write interleaved multichannel data to the out buffer, while samples are converted to float.
* The buffer must be at least of size getChannelNum()*frames()*sizeof(float).
* The out buffer must be at least of size capacity()*sizeof(float) bytes.
*
* @returns Number of samples writen.
*/
......@@ -164,9 +179,9 @@ class AudioBuffer {
void applyGain(double gain);
/**
* Mix elements of the other buffer within this buffer (in-place simple addition).
* If other.channels() is higher than this.channels(), only the first this.channels() channels are imported.
* If other.channels() is lower than this.channels(), behavior depends on upmix.
* Mix samples from the other buffer within this buffer (in-place simple addition).
* If the other buffer has more channels than this one, only the first this.channels() channels are imported.
* If the other buffer has less channels than this one, behavior depends on upmix.
* Sample rate is not considered by this function.
*
* TODO: some kind of check for overflow/saturation.
......@@ -180,11 +195,10 @@ class AudioBuffer {
size_t mix(const AudioBuffer& other, bool upmix = true);
/**
* Copy sample_num samples from in (from sample pos_in) to this buffer (at sample pos_out).
* Copy sample_num samples from in (from sample sample pos_in) to this buffer (at sample sample pos_out).
* If sample_num is -1 (the default), the entire in buffer is copied.
*
* The number of channels is changed to match the in channel number.
* Buffer sample number is also increased if required to hold the new requested samples.
* Buffer sample number is increased if required to hold the new requested samples.
*/
size_t copy(AudioBuffer& in, int sample_num = -1, size_t pos_in = 0, size_t pos_out = 0, bool upmix = true);
......
......@@ -30,6 +30,7 @@
#include <cstdio>
#include <cassert>
#include <unistd.h>
#include "logger.h"
#include "array_size.h"
......@@ -44,7 +45,7 @@ const int OpenSLLayer::NB_BUFFER_CAPTURE_QUEUE = ANDROID_BUFFER_QUEUE_LENGTH;
static long sawPtr = 0;
static void generateSawTooth(short *buffer, int length)
{
assert(NULL != buffer);
assert(nullptr != buffer);
assert(length > 0);
unsigned int i;
......@@ -82,14 +83,14 @@ OpenSLThread::~OpenSLThread()
opensl_->shutdownAudioEngine();
if (thread_)
pthread_join(thread_, NULL);
pthread_join(thread_, nullptr);
}
void
OpenSLThread::start()
{
running_ = true;
pthread_create(&thread_, NULL, &runCallback, this);
pthread_create(&thread_, nullptr, &runCallback, this);
}
void *
......@@ -97,7 +98,7 @@ OpenSLThread::runCallback(void *data)
{
OpenSLThread *context = static_cast<OpenSLThread*>(data);
context->run();
return NULL;
return nullptr;
}
bool
......@@ -158,7 +159,8 @@ OpenSLLayer::~OpenSLLayer()
stopStream();
}
//#define RECORD_AUDIO_TODISK
#define RECORD_AUDIO_TODISK
#ifdef RECORD_AUDIO_TODISK
#include <fstream>
std::ofstream opensl_outfile;
......@@ -173,7 +175,7 @@ OpenSLLayer::startStream()
DEBUG("Start OpenSL audio layer");
if (audioThread_ == NULL) {
if (audioThread_ == nullptr) {
#ifdef RECORD_AUDIO_TODISK
opensl_outfile.open("/data/data/com.savoirfairelinux.sflphone/opensl_playback.raw", std::ofstream::out | std::ofstream::binary);
opensl_infile.open("/data/data/com.savoirfairelinux.sflphone/opensl_record.raw", std::ofstream::out | std::ofstream::binary);
......@@ -200,7 +202,7 @@ OpenSLLayer::stopStream()
isStarted_ = false;
delete audioThread_;
audioThread_ = NULL;
audioThread_ = nullptr;
#ifdef RECORD_AUDIO_TODISK
opensl_outfile.close();
opensl_infile.close();
......@@ -213,7 +215,7 @@ OpenSLLayer::initAudioEngine()
SLresult result;
DEBUG("Create Audio Engine\n");
result = slCreateEngine(&engineObject_, 0, NULL, 0, NULL, NULL);
result = slCreateEngine(&engineObject_, 0, nullptr, 0, nullptr, nullptr);
assert(SL_RESULT_SUCCESS == result);
DEBUG("Realize Audio Engine\n");
......@@ -225,7 +227,7 @@ OpenSLLayer::initAudioEngine()
assert(SL_RESULT_SUCCESS == result);
DEBUG("Create Output Mixer\n");
result = (*engineInterface_)->CreateOutputMix(engineInterface_, &outputMixer_, 0, NULL, NULL);
result = (*engineInterface_)->CreateOutputMix(engineInterface_, &outputMixer_, 0, nullptr, nullptr);
assert(SL_RESULT_SUCCESS == result);
DEBUG("Realize Output Mixer\n");
......@@ -242,43 +244,43 @@ OpenSLLayer::shutdownAudioEngine()
// destroy buffer queue audio player object, and invalidate all associated interfaces
DEBUG("Shutdown audio player\n");
if (playerObject_ != NULL) {
if (playerObject_ != nullptr) {
(*playerObject_)->Destroy(playerObject_);
playerObject_ = NULL;
playerInterface_ = NULL;
playbackBufferQueue_ = NULL;
playerObject_ = nullptr;
playerInterface_ = nullptr;
playbackBufferQueue_ = nullptr;
}
// destroy output mix object, and invalidate all associated interfaces
DEBUG("Shutdown audio mixer\n");
if (outputMixer_ != NULL) {
if (outputMixer_ != nullptr) {
(*outputMixer_)->Destroy(outputMixer_);
outputMixer_ = NULL;
outputMixer_ = nullptr;
}
if(recorderObject_ != NULL){
if(recorderObject_ != nullptr){
(*recorderObject_)->Destroy(recorderObject_);
recorderObject_ = NULL;
recorderInterface_ = NULL;
recorderBufferQueue_ = NULL;
recorderObject_ = nullptr;
recorderInterface_ = nullptr;
recorderBufferQueue_ = nullptr;
}
// destroy engine object, and invalidate all associated interfaces
DEBUG("Shutdown audio engine\n");
if (engineObject_ != NULL) {
if (engineObject_ != nullptr) {
(*engineObject_)->Destroy(engineObject_);
engineObject_ = NULL;
engineInterface_ = NULL;
engineObject_ = nullptr;
engineInterface_ = nullptr;
}
}
void
OpenSLLayer::initAudioPlayback()
{
assert(NULL != engineObject_);
assert(NULL != engineInterface_);
assert(NULL != outputMixer_);
assert(nullptr != engineObject_);
assert(nullptr != engineInterface_);
assert(nullptr != outputMixer_);
SLresult result;
......@@ -305,7 +307,7 @@ OpenSLLayer::initAudioPlayback()
// Cofiguration fo the audio sink as an output mixer
DEBUG("Set output mixer location\n");
SLDataLocator_OutputMix mixerLocation = {SL_DATALOCATOR_OUTPUTMIX, outputMixer_};
SLDataSink audioSink = {&mixerLocation, NULL};
SLDataSink audioSink = {&mixerLocation, nullptr};
const SLInterfaceID ids[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
SL_IID_VOLUME, SL_IID_ANDROIDCONFIGURATION
......@@ -368,11 +370,11 @@ OpenSLLayer::initAudioCapture()
SLDataLocator_IODevice deviceLocator = {SL_DATALOCATOR_IODEVICE,
SL_IODEVICE_AUDIOINPUT,
SL_DEFAULTDEVICEID_AUDIOINPUT,
NULL
nullptr
};
SLDataSource audioSource = {&deviceLocator,
NULL
nullptr
};
// configure audio sink
......@@ -400,7 +402,7 @@ OpenSLLayer::initAudioCapture()
const SLInterfaceID id[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
const SLboolean req[] = {SL_BOOLEAN_TRUE};
if (engineInterface_ != NULL) {
if (engineInterface_ != nullptr) {
result = (*engineInterface_)->CreateAudioRecorder(engineInterface_,
&recorderObject_, &audioSource, &audioSink, 1, id, req);
}
......@@ -442,7 +444,7 @@ OpenSLLayer::initAudioCapture()
void
OpenSLLayer::startAudioPlayback()
{
assert(NULL != playbackBufferQueue_);
assert(nullptr != playbackBufferQueue_);
DEBUG("Start audio playback\n");
......@@ -454,7 +456,7 @@ OpenSLLayer::startAudioPlayback()
buffer.reset();
result = (*playbackBufferQueue_)->Enqueue(playbackBufferQueue_, buffer.getData()[0].data(), buffer.getData()[0].size());
result = (*playbackBufferQueue_)->Enqueue(playbackBufferQueue_, buffer.getChannel(0)->data(), buffer.frames());
if (SL_RESULT_SUCCESS != result) {
DEBUG("Error could not enqueue initial buffers\n");
......@@ -470,7 +472,7 @@ OpenSLLayer::startAudioPlayback()
void
OpenSLLayer::startAudioCapture()
{
assert(NULL != playbackBufferQueue_);
assert(nullptr != playbackBufferQueue_);
DEBUG("Start audio capture\n");
......@@ -478,7 +480,7 @@ OpenSLLayer::startAudioCapture()
// in case already recording, stop recording and clear buffer queue
if (recorderInterface_ != NULL) {
if (recorderInterface_ != nullptr) {
result = (*recorderInterface_)->SetRecordState(recorderInterface_, SL_RECORDSTATE_STOPPED);
assert(SL_RESULT_SUCCESS == result);
}
......@@ -496,7 +498,7 @@ OpenSLLayer::startAudioCapture()
buffer.reset();
DEBUG("Enqueue record buffer\n");
result = (*recorderBufferQueue_)->Enqueue(recorderBufferQueue_, buffer.getData()[0].data(), buffer.getData()[0].size());
result = (*recorderBufferQueue_)->Enqueue(recorderBufferQueue_, buffer.getChannel(0)->data(), buffer.frames());
// the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
// which for this code example would indicate a programming error
......@@ -517,7 +519,7 @@ OpenSLLayer::stopAudioPlayback()
{
DEBUG("Stop audio playback\n");
if (playerInterface_ != NULL) {
if (playerInterface_ != nullptr) {
SLresult result;
result = (*playerInterface_)->SetPlayState(playerInterface_, SL_PLAYSTATE_STOPPED);
assert(SL_RESULT_SUCCESS == result);
......@@ -531,7 +533,7 @@ OpenSLLayer::stopAudioCapture()
{
DEBUG("Stop audio capture\n");
if (recorderInterface_ != NULL) {
if (recorderInterface_ != nullptr) {
SLresult result;
result = (*recorderInterface_)->SetRecordState(recorderInterface_, SL_RECORDSTATE_STOPPED);
assert(SL_RESULT_SUCCESS == result);
......@@ -560,21 +562,21 @@ OpenSLLayer::getPlaybackDeviceList() const
void
OpenSLLayer::playback(SLAndroidSimpleBufferQueueItf queue)
{
assert(NULL != queue);
assert(nullptr != queue);
usleep(20000);
// usleep(20000);
AudioBuffer &buffer = getNextPlaybackBuffer();
buffer.reset();
//buffer.reset();
const bool bufferFilled = audioPlaybackFillBuffer(buffer);
if (bufferFilled) {
#ifdef RECORD_AUDIO_TODISK
opensl_outfile.write((char const *)(buffer.getData()[0].data()), buffer.getData()[0].size());
opensl_outfile.write((char const *)(buffer.getChannel(0)->data()), buffer.frames()*sizeof(SFLAudioSample));
#endif
SLresult result = (*queue)->Enqueue(queue, buffer.getData()[0].data(), buffer.getData()[0].size());
SLresult result = (*queue)->Enqueue(queue, buffer.getChannel(0)->data(), buffer.frames()*sizeof(SFLAudioSample));
if (SL_RESULT_SUCCESS != result) {
DEBUG("Error could not enqueue buffers in playback callback\n");
......@@ -587,14 +589,14 @@ OpenSLLayer::playback(SLAndroidSimpleBufferQueueItf queue)
void
OpenSLLayer::audioPlaybackCallback(SLAndroidSimpleBufferQueueItf queue, void *context)
{
assert(NULL != context);
assert(nullptr != context);
static_cast<OpenSLLayer*>(context)->playback(queue);
}
void
OpenSLLayer::capture(SLAndroidSimpleBufferQueueItf queue)
{
assert(NULL != queue);
assert(nullptr != queue);
AudioBuffer &buffer = getNextRecordBuffer();
incrementRecordIndex();
......@@ -603,21 +605,23 @@ OpenSLLayer::capture(SLAndroidSimpleBufferQueueItf queue)
// enqueue an empty buffer to be filled by the recorder
// (for streaming recording, we enqueue at least 2 empty buffers to start things off)
result = (*recorderBufferQueue_)->Enqueue(recorderBufferQueue_, buffer.getData()[0].data(), buffer.getData()[0].size());
//result = (*recorderBufferQueue_)->Enqueue(recorderBufferQueue_, buffer.getData()[0].data(), buffer.getData()[0].size());
result = (*recorderBufferQueue_)->Enqueue(recorderBufferQueue_, buffer.getChannel(0)->data(), buffer.frames()*sizeof(SFLAudioSample));
// the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
// which for this code example would indicate a programming error
assert(SL_RESULT_SUCCESS == result);
audioCaptureFillBuffer(buffer);
#ifdef RECORD_AUDIO_TODISK
opensl_infile.write((char const *)(buffer.getData()[0].data()), buffer.getData()[0].size());
opensl_infile.write((char const *)(buffer.getChannel(0)->data()), buffer.frames()*sizeof(SFLAudioSample));
#endif
}
void
OpenSLLayer::audioCaptureCallback(SLAndroidSimpleBufferQueueItf queue, void *context)
{
assert(NULL != context);
assert(nullptr != context);
static_cast<OpenSLLayer*>(context)->capture(queue);
}
......@@ -648,9 +652,8 @@ bool OpenSLLayer::audioPlaybackFillBuffer(AudioBuffer &buffer)
{
// Looks if there's any voice audio from rtp to be played
MainBuffer &mbuffer = Manager::instance().getMainBuffer();
size_t bytesToGet = mbuffer.availableForGet(MainBuffer::DEFAULT_ID);
size_t urgentBytesToGet = urgentRingBuffer_.availableForGet(MainBuffer::DEFAULT_ID);
size_t samplesToGet = mbuffer.availableForGet(MainBuffer::DEFAULT_ID);
size_t urgentSamplesToGet = urgentRingBuffer_.availableForGet(MainBuffer::DEFAULT_ID);
PlaybackMode mode = getPlaybackMode();
......@@ -661,16 +664,16 @@ bool OpenSLLayer::audioPlaybackFillBuffer(AudioBuffer &buffer)
case TONE:
case RINGTONE:
case URGENT: {
if (urgentBytesToGet > 0)
bufferFilled = audioPlaybackFillWithUrgent(buffer, urgentBytesToGet);
if (urgentSamplesToGet > 0)
bufferFilled = audioPlaybackFillWithUrgent(buffer, urgentSamplesToGet);
else
bufferFilled = audioPlaybackFillWithToneOrRingtone(buffer);
}
break;
case VOICE: {
if (bytesToGet > 0)
bufferFilled = audioPlaybackFillWithVoice(buffer, bytesToGet);
if (samplesToGet > 0)
bufferFilled = audioPlaybackFillWithVoice(buffer, samplesToGet);
else {
buffer.reset();
bufferFilled = true;
......@@ -686,7 +689,7 @@ bool OpenSLLayer::audioPlaybackFillBuffer(AudioBuffer &buffer)
}
if (!bufferFilled)
printf("Error buffer not filled in audio playback\n");
DEBUG("Error buffer not filled in audio playback\n");
return bufferFilled;
}
......@@ -724,52 +727,59 @@ void OpenSLLayer::audioCaptureFillBuffer(AudioBuffer &buffer)
bool OpenSLLayer::audioPlaybackFillWithToneOrRingtone(AudioBuffer &buffer)
{
buffer.resize(BUFFER_SIZE);
AudioLoop *tone = Manager::instance().getTelephoneTone();
AudioLoop *file_tone = Manager::instance().getTelephoneFile();
// In case of a dtmf, the pointers will be set to NULL once the dtmf length is
// reached. For this reason we need to fill audio buffer with zeros if pointer is NULL
// In case of a dtmf, the pointers will be set to nullptr once the dtmf length is
// reached. For this reason we need to fill audio buffer with zeros if pointer is nullptr
if (tone) {
DEBUG("audioPlaybackFillWithToneOrRingtone tone\n");
tone->getNext(buffer, playbackGain_);
} else if (file_tone) {
DEBUG("audioPlaybackFillWithToneOrRingtone file_tone\n");
file_tone->getNext(buffer, playbackGain_);
} else {
DEBUG("audioPlaybackFillWithToneOrRingtone reset\n");
buffer.reset();
}
return true;
}
bool OpenSLLayer::audioPlaybackFillWithUrgent(AudioBuffer &buffer, size_t bytesToGet)
bool OpenSLLayer::audioPlaybackFillWithUrgent(AudioBuffer &buffer, size_t samplesToGet)
{
// Urgent data (dtmf, incoming call signal) come first.
bytesToGet = std::min(bytesToGet, buffer.capacity());
samplesToGet = std::min(samplesToGet, buffer.frames());
buffer.resize(samplesToGet);
urgentRingBuffer_.get(buffer, MainBuffer::DEFAULT_ID);
buffer.applyGain(playbackGain_);
// Consume the regular one as well (same amount of bytes)
Manager::instance().getMainBuffer().discard(bytesToGet, MainBuffer::DEFAULT_ID);
// Consume the regular one as well (same amount of samples)
Manager::instance().getMainBuffer().discard(samplesToGet, MainBuffer::DEFAULT_ID);
return true;
}
bool OpenSLLayer::audioPlaybackFillWithVoice(AudioBuffer &buffer, size_t bytesAvail)
bool OpenSLLayer::audioPlaybackFillWithVoice(AudioBuffer &buffer, size_t samplesAvail)
{
const size_t bytesToCpy = buffer.capacity();
//const size_t samplesToCpy = buffer.samples();
if (bytesAvail == 0)
if (samplesAvail == 0)
return false;
MainBuffer &mainBuffer = Manager::instance().getMainBuffer();
buffer.resize(samplesAvail);
mainBuffer.getData(buffer, MainBuffer::DEFAULT_ID);
buffer.applyGain(getPlaybackGain());
if (sampleRate_ != mainBuffer.getInternalSamplingRate()) {
DEBUG("OpenSLLayer::audioPlaybackFillWithVoice sampleRate_ != mainBuffer.getInternalSamplingRate() \n");
AudioBuffer out(buffer, false);
out.setSampleRate(sampleRate_);
converter_.resample(buffer, out);
buffer = out;
buffer = std::move(out);
}
return true;
......
......@@ -34,6 +34,7 @@
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#include <vector>
#include <atomic>
#include "../audiolayer.h"
#include "logger.h"
......@@ -53,7 +54,7 @@ class AudioPreference;
class OpenSLThread;
#define ANDROID_BUFFER_QUEUE_LENGTH 2
#define BUFFER_SIZE 5000
#define BUFFER_SIZE 80
/**
......@@ -254,12 +255,10 @@ class OpenSLLayer : public AudioLayer {
* OpenSL playback buffer
*/
SLAndroidSimpleBufferQueueItf playbackBufferQueue_;
SLAndroidSimpleBufferQueueItf recorderBufferQueue_;
int playbackBufferIndex_;
int recordBufferIndex_;
std::atomic<int> playbackBufferIndex_;
std::atomic<int> recordBufferIndex_;
AudioBufferStack playbackBufferStack_;
AudioBufferStack recordBufferStack_;
......
Markdown is supported
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