Skip to content
Snippets Groups Projects
Commit 9548423f authored by Philippe Groarke's avatar Philippe Groarke Committed by Tristan Matthews
Browse files

OSX: Audio output works using default output

Refs #57721

Change-Id: Ib038b25ad82047092d6dfb466495e6c3275934b2
parent 9e26a1b4
Branches
Tags
No related merge requests found
...@@ -84,3 +84,6 @@ nbproject ...@@ -84,3 +84,6 @@ nbproject
# Windows # Windows
*.exe *.exe
# Mac
.DS_Store
...@@ -5,4 +5,3 @@ configure ...@@ -5,4 +5,3 @@ configure
bin/dbus/*.adaptor.h bin/dbus/*.adaptor.h
bin/dbus/org.sflphone.SFLphone.service bin/dbus/org.sflphone.SFLphone.service
bin/sflphoned bin/sflphoned
.DS_Store
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <cstring> #include <cstring>
#include <signal.h> #include <signal.h>
#include <getopt.h> #include <getopt.h>
#include <string>
#include "sflphone.h" #include "sflphone.h"
#include "fileutils.h" #include "fileutils.h"
...@@ -129,10 +130,24 @@ static bool parse_args(int argc, char *argv[], bool &persistent) ...@@ -129,10 +130,24 @@ static bool parse_args(int argc, char *argv[], bool &persistent)
return quit; return quit;
} }
void myOnIncomingCall(const std::string& acc_id, const std::string& call_id, const std::string& from)
{
std::cout << std::endl << "INCOMING CALL!" << std::endl <<
"Account: " << acc_id <<
", Id: " << call_id <<
", From: " << from << std::endl << std::endl;
sflph_call_accept(call_id);
sflph_call_set_recording(call_id);
//sflph_call_join_participant(call_id, "patate");
}
static int osxTests() static int osxTests()
{ {
sflph_ev_handlers evHandlers = { sflph_ev_handlers evHandlers = {
.call_ev_handlers = {}, .call_ev_handlers = {
.on_incoming_call = myOnIncomingCall
},
.config_ev_handlers = {}, .config_ev_handlers = {},
#ifdef SFL_PRESENCE #ifdef SFL_PRESENCE
.pres_ev_handlers = {} .pres_ev_handlers = {}
...@@ -145,15 +160,25 @@ static int osxTests() ...@@ -145,15 +160,25 @@ static int osxTests()
sflph_init(&evHandlers, static_cast<sflph_init_flag>(sflphFlags)); sflph_init(&evHandlers, static_cast<sflph_init_flag>(sflphFlags));
sflph_call_play_dtmf("0"); sflph_call_play_dtmf("0");
for (auto x : sflph_config_get_audio_output_device_list()) sleep(1);
std::cout << x << std::endl; sflph_call_play_dtmf("1");
sleep(1);
//sflph_call_place("IP2IP", "patate", "127.0.0.1");
//sflph_call_set_recording("patate");
while (true) {
sflph_poll_events();
sleep(1);
}
sflph_fini();
} }
static int run() static int run()
{ {
osxTests(); osxTests();
return 1; return 0;
} }
static void interrupt() static void interrupt()
......
...@@ -154,6 +154,15 @@ void AudioBuffer::applyGain(double gain) ...@@ -154,6 +154,15 @@ void AudioBuffer::applyGain(double gain)
sample *= g; sample *= g;
} }
size_t AudioBuffer::channelToFloat(float* out, const int& channel) const
{
for (int i=0, f=frames(); i < f; i++)
*out++ = (float) samples_[channel][i] * .000030517578125f;
return frames() * samples_.size();
}
size_t AudioBuffer::interleave(SFLAudioSample* out) const size_t AudioBuffer::interleave(SFLAudioSample* out) const
{ {
for (unsigned i=0, f=frames(), c=channels(); i < f; ++i) for (unsigned i=0, f=frames(), c=channels(); i < f; ++i)
......
...@@ -239,6 +239,14 @@ class AudioBuffer { ...@@ -239,6 +239,14 @@ class AudioBuffer {
return raw_data; return raw_data;
} }
/**
* Convert fixed-point channel to float and write in the out buffer (Float 32-bits).
* The out buffer must be at least of size capacity()*sizeof(SFLAudioSample) bytes.
*
* @returns Number of samples writen.
*/
size_t channelToFloat(float* out, const int& channel) const;
/** /**
* Write interleaved multichannel data to the out buffer (fixed-point 16-bits). * Write interleaved multichannel data to the out buffer (fixed-point 16-bits).
* The out buffer must be at least of size capacity()*sizeof(SFLAudioSample) bytes. * The out buffer must be at least of size capacity()*sizeof(SFLAudioSample) bytes.
......
...@@ -42,11 +42,8 @@ class AudioDevice { ...@@ -42,11 +42,8 @@ class AudioDevice {
public: public:
AudioDevice() : id_(kAudioDeviceUnknown) { } AudioDevice() : id_(kAudioDeviceUnknown) { }
AudioDevice(AudioDeviceID devid, bool isInput); AudioDevice(AudioDeviceID devid, bool isInput);
void init(AudioDeviceID devid, bool isInput); void init(AudioDeviceID devid, bool isInput);
bool valid() const; bool valid() const;
void setBufferSize(UInt32 size); void setBufferSize(UInt32 size);
public: public:
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "corelayer.h" #include "corelayer.h"
#include "manager.h" #include "manager.h"
#include "noncopyable.h" #include "noncopyable.h"
#include "audio/resampler.h"
#include "audio/ringbufferpool.h" #include "audio/ringbufferpool.h"
#include "audio/ringbuffer.h" #include "audio/ringbuffer.h"
#include "audiodevice.h" #include "audiodevice.h"
...@@ -40,46 +41,6 @@ ...@@ -40,46 +41,6 @@
namespace sfl { namespace sfl {
// Actual audio thread.
class CoreAudioThread {
public:
CoreAudioThread(CoreLayer* coreAudio);
~CoreAudioThread();
void start();
private:
NON_COPYABLE(CoreAudioThread);
void run();
std::thread thread_;
CoreLayer* coreAudio_;
std::atomic_bool running_;
};
CoreAudioThread::CoreAudioThread(CoreLayer* coreAudio)
: thread_(), coreAudio_(coreAudio), running_(false)
{}
CoreAudioThread::~CoreAudioThread()
{
running_ = false;
if (thread_.joinable())
thread_.join();
}
void CoreAudioThread::start()
{
running_ = true;
thread_ = std::thread(&CoreAudioThread::run, this);
}
void CoreAudioThread::run()
{
// Actual playback is here.
while (running_) {
}
}
// AudioLayer implementation. // AudioLayer implementation.
CoreLayer::CoreLayer(const AudioPreference &pref) CoreLayer::CoreLayer(const AudioPreference &pref)
: AudioLayer(pref) : AudioLayer(pref)
...@@ -87,27 +48,32 @@ CoreLayer::CoreLayer(const AudioPreference &pref) ...@@ -87,27 +48,32 @@ CoreLayer::CoreLayer(const AudioPreference &pref)
, indexOut_(pref.getAlsaCardout()) , indexOut_(pref.getAlsaCardout())
, indexRing_(pref.getAlsaCardring()) , indexRing_(pref.getAlsaCardring())
, playbackBuff_(0, audioFormat_) , playbackBuff_(0, audioFormat_)
, captureBuff_(0, audioFormat_) , captureBuff_(0)
, playbackIBuff_(1024)
, captureIBuff_(1024)
, is_playback_prepared_(false)
, is_capture_prepared_(false)
, is_playback_running_(false) , is_playback_running_(false)
, is_capture_running_(false) , is_capture_running_(false)
, is_playback_open_(false)
, is_capture_open_(false)
, audioThread_(nullptr)
, mainRingBuffer_(Manager::instance().getRingBufferPool().getRingBuffer(RingBufferPool::DEFAULT_ID)) , mainRingBuffer_(Manager::instance().getRingBufferPool().getRingBuffer(RingBufferPool::DEFAULT_ID))
{} {}
CoreLayer::~CoreLayer() CoreLayer::~CoreLayer()
{ {
isStarted_ = false; isStarted_ = false;
if (captureBuff_) {
for (UInt32 i = 0; i < captureBuff_->mNumberBuffers; ++i)
free(captureBuff_->mBuffers[i].mData);
free(captureBuff_);
captureBuff_ = 0;
}
} }
std::vector<std::string> CoreLayer::getCaptureDeviceList() const std::vector<std::string> CoreLayer::getCaptureDeviceList() const
{ {
return {}; std::vector<std::string> ret;
for (auto x : getDeviceList(true))
ret.push_back(x.name_);
return ret;
} }
std::vector<std::string> CoreLayer::getPlaybackDeviceList() const std::vector<std::string> CoreLayer::getPlaybackDeviceList() const
...@@ -122,34 +88,350 @@ std::vector<std::string> CoreLayer::getPlaybackDeviceList() const ...@@ -122,34 +88,350 @@ std::vector<std::string> CoreLayer::getPlaybackDeviceList() const
return ret; return ret;
} }
void CoreLayer::startStream() int CoreLayer::getAudioDeviceIndex(const std::string& name, DeviceType type) const
{ {
dcblocker_.reset(); return 0;
}
if (is_playback_running_ and is_capture_running_) std::string CoreLayer::getAudioDeviceName(int index, DeviceType type) const
{
return "";
}
void CoreLayer::initAudioLayerPlayback()
{
// OS X uses Audio Units for output. Steps:
// 1) Create a description.
// 2) Find the audio unit that fits that.
// 3) Set the audio unit callback.
// 4) Initialize everything.
// 5) Profit...
SFL_DBG("INIT AUDIO PLAYBACK");
AudioComponentDescription outputDesc = {0};
outputDesc.componentType = kAudioUnitType_Output;
outputDesc.componentSubType = kAudioUnitSubType_DefaultOutput;
outputDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
AudioComponent outComp = AudioComponentFindNext(NULL, &outputDesc);
if (outComp == NULL) {
SFL_ERR("Can't find default output audio component.");
return; return;
} }
checkErr(AudioComponentInstanceNew(outComp, &outputUnit_));
int CoreLayer::getAudioDeviceIndex(const std::string& name, DeviceType type) const AURenderCallbackStruct callback;
callback.inputProc = outputCallback;
callback.inputProcRefCon = this;
checkErr(AudioUnitSetProperty(outputUnit_,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&callback,
sizeof(callback)));
checkErr(AudioUnitInitialize(outputUnit_));
checkErr(AudioOutputUnitStart(outputUnit_));
is_playback_running_ = true;
is_capture_running_ = true;
initAudioFormat();
}
void CoreLayer::initAudioLayerCapture()
{ {
return 0; // HALUnit description.
AudioComponentDescription desc;
desc = {0};
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_HALOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
AudioComponent comp = AudioComponentFindNext(NULL, &desc);
if (comp == NULL)
SFL_ERR("Can't find an input HAL unit that matches description.");
checkErr(AudioComponentInstanceNew(comp, &inputUnit_));
// HALUnit settings.
AudioUnitScope outputBus = 0;
AudioUnitScope inputBus = 1;
UInt32 enableIO = 1;
UInt32 disableIO = 0;
UInt32 size = 0;
checkErr(AudioUnitSetProperty(inputUnit_,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
inputBus,
&enableIO,
sizeof(enableIO)));
checkErr(AudioUnitSetProperty(inputUnit_,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
outputBus,
&disableIO,
sizeof(disableIO)));
AudioDeviceID defaultDevice = kAudioObjectUnknown;
size = sizeof(defaultDevice);
AudioObjectPropertyAddress defaultDeviceProperty;
defaultDeviceProperty.mSelector = kAudioHardwarePropertyDefaultInputDevice;
defaultDeviceProperty.mScope = kAudioObjectPropertyScopeGlobal;
defaultDeviceProperty.mElement = kAudioObjectPropertyElementMaster;
checkErr(AudioObjectGetPropertyData(kAudioObjectSystemObject,
&defaultDeviceProperty,
outputBus,
NULL,
&size,
&defaultDevice));
checkErr(AudioUnitSetProperty(inputUnit_,
kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Global,
outputBus,
&defaultDevice,
sizeof(defaultDevice)));
// Set format on output *SCOPE* in input *BUS*.
AudioStreamBasicDescription info;
size = sizeof(AudioStreamBasicDescription);
checkErr(AudioUnitGetProperty(inputUnit_,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
inputBus,
&info,
&size));
const AudioFormat mainBufferFormat = Manager::instance().getRingBufferPool().getInternalAudioFormat();
audioFormat_ = {(unsigned int)info.mSampleRate, (unsigned int)info.mChannelsPerFrame};
//hardwareFormatAvailable(audioFormat_);
SFL_DBG("Input format : %d, %d\n\n", audioFormat_.sample_rate, audioFormat_.nb_channels);
// Input buffer setup. Note that ioData is empty and we have to store data
// in another buffer.
UInt32 bufferSizeFrames = 0;
size = sizeof(UInt32);
checkErr(AudioUnitGetProperty(inputUnit_,
kAudioDevicePropertyBufferFrameSize,
kAudioUnitScope_Global,
outputBus,
&bufferSizeFrames,
&size));
UInt32 bufferSizeBytes = bufferSizeFrames * sizeof(Float32);
size = offsetof(AudioBufferList, mBuffers[0]) +
(sizeof(AudioBuffer) * info.mChannelsPerFrame);
captureBuff_ = (AudioBufferList *)malloc(size);
captureBuff_->mNumberBuffers = info.mChannelsPerFrame;
for (UInt32 i = 0; i < captureBuff_->mNumberBuffers; ++i) {
captureBuff_->mBuffers[i].mNumberChannels = 1;
captureBuff_->mBuffers[i].mDataByteSize = bufferSizeBytes;
captureBuff_->mBuffers[i].mData = malloc(bufferSizeBytes);
} }
std::string CoreLayer::getAudioDeviceName(int index, DeviceType type) const // Input callback setup.
AURenderCallbackStruct inputCall;
inputCall.inputProc = inputCallback;
inputCall.inputProcRefCon = this;
checkErr(AudioUnitSetProperty(inputUnit_,
kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Global,
outputBus,
&inputCall,
sizeof(inputCall)));
// Start it up.
checkErr(AudioUnitInitialize(inputUnit_));
checkErr(AudioOutputUnitStart(inputUnit_));
}
void CoreLayer::startStream()
{ {
return ""; SFL_DBG("START STREAM");
dcblocker_.reset();
if (is_playback_running_ and is_capture_running_)
return;
initAudioLayerPlayback();
initAudioLayerCapture();
}
void CoreLayer::destroyAudioLayer()
{
AudioOutputUnitStop(outputUnit_);
AudioUnitUninitialize(outputUnit_);
AudioComponentInstanceDispose(outputUnit_);
AudioOutputUnitStop(inputUnit_);
AudioUnitUninitialize(inputUnit_);
AudioComponentInstanceDispose(inputUnit_);
} }
void CoreLayer::stopStream() void CoreLayer::stopStream()
{ {
isStarted_ = false; SFL_DBG("STOP STREAM");
isStarted_ = is_playback_running_ = is_capture_running_ = false;
destroyAudioLayer();
/* Flush the ring buffers */ /* Flush the ring buffers */
flushUrgent(); flushUrgent();
flushMain(); flushMain();
} }
//// PRIVATE /////
void CoreLayer::initAudioFormat()
{
AudioStreamBasicDescription info;
UInt32 size = sizeof(info);
checkErr(AudioUnitGetProperty(outputUnit_,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&info,
&size));
audioFormat_ = {(unsigned int)info.mSampleRate, (unsigned int)info.mChannelsPerFrame};
hardwareFormatAvailable(audioFormat_);
}
OSStatus CoreLayer::outputCallback(void* inRefCon,
AudioUnitRenderActionFlags* ioActionFlags,
const AudioTimeStamp* inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList* ioData)
{
static_cast<CoreLayer*>(inRefCon)->write(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
return kAudioServicesNoError;
}
void CoreLayer::write(AudioUnitRenderActionFlags* ioActionFlags,
const AudioTimeStamp* inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList* ioData)
{
unsigned framesToGet = urgentRingBuffer_.availableForGet(RingBufferPool::DEFAULT_ID);
if (framesToGet <= 0) {
for (int i = 0; i < inNumberFrames; ++i) {
Float32* outDataL = (Float32*)ioData->mBuffers[0].mData;
outDataL[i] = 0.0;
Float32* outDataR = (Float32*)ioData->mBuffers[1].mData;
outDataR[i] = 0.0;
}
return;
}
size_t totSample = std::min(inNumberFrames, framesToGet);
playbackBuff_.setFormat(audioFormat_);
playbackBuff_.resize(totSample);
urgentRingBuffer_.get(playbackBuff_, RingBufferPool::DEFAULT_ID);
playbackBuff_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_);
for (int i = 0; i < audioFormat_.nb_channels; ++i)
playbackBuff_.channelToFloat((Float32*)ioData->mBuffers[i].mData, i); // Write
Manager::instance().getRingBufferPool().discard(totSample, RingBufferPool::DEFAULT_ID);
}
OSStatus CoreLayer::inputCallback(void* inRefCon,
AudioUnitRenderActionFlags* ioActionFlags,
const AudioTimeStamp* inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList* ioData)
{
static_cast<CoreLayer*>(inRefCon)->read(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
return kAudioServicesNoError;
}
void CoreLayer::read(AudioUnitRenderActionFlags* ioActionFlags,
const AudioTimeStamp* inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList* ioData)
{
//SFL_DBG("INPUT CALLBACK");
if (inNumberFrames <= 0) {
SFL_WARN("No frames for input.");
return;
}
// Write the mic samples in our buffer
checkErr(AudioUnitRender(inputUnit_,
ioActionFlags,
inTimeStamp,
inBusNumber,
inNumberFrames,
captureBuff_));
AudioStreamBasicDescription info;
UInt32 size = sizeof(AudioStreamBasicDescription);
checkErr(AudioUnitGetProperty(inputUnit_,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
inBusNumber,
&info,
&size));
// Add them to sflphone ringbuffer.
const AudioFormat mainBufferFormat = Manager::instance().getRingBufferPool().getInternalAudioFormat();
bool resample = info.mSampleRate != mainBufferFormat.sample_rate;
// FIXME: Performance! There *must* be a better way. This is testing only.
AudioBuffer inBuff(inNumberFrames, audioFormat_);
for (int i = 0; i < info.mChannelsPerFrame; ++i) {
Float32* data = (Float32*)captureBuff_->mBuffers[i].mData;
for (int j = 0; j < inNumberFrames; ++j) {
(*inBuff.getChannel(i))[j] = (SFLAudioSample)((data)[j] / .000030517578125f);
}
}
if (resample) {
//SFL_WARN("Resampling Input.");
//FIXME: May be a multiplication, check alsa vs pulse implementation.
int outSamples = inNumberFrames / (static_cast<double>(audioFormat_.sample_rate) / mainBufferFormat.sample_rate);
AudioBuffer out(outSamples, mainBufferFormat);
resampler_->resample(inBuff, out);
dcblocker_.process(out);
mainRingBuffer_->put(out);
} else {
dcblocker_.process(inBuff);
mainRingBuffer_->put(inBuff);
}
}
void CoreLayer::updatePreference(AudioPreference &preference, int index, DeviceType type) void CoreLayer::updatePreference(AudioPreference &preference, int index, DeviceType type)
{ {
switch (type) { switch (type) {
......
...@@ -33,6 +33,19 @@ ...@@ -33,6 +33,19 @@
#include "audio/audiolayer.h" #include "audio/audiolayer.h"
#include "noncopyable.h" #include "noncopyable.h"
#include <CoreFoundation/CoreFoundation.h>
#include <AudioToolbox/AudioToolbox.h>
#include <CoreAudio/AudioHardware.h>
#define checkErr( err) \
if(err) {\
OSStatus error = static_cast<OSStatus>(err);\
fprintf(stdout, "CoreAudio Error: %ld -> %s: %d\n", (long)error,\
__FILE__, \
__LINE__\
);\
fflush(stdout);\
}
/** /**
* @file CoreLayer.h * @file CoreLayer.h
...@@ -41,7 +54,6 @@ ...@@ -41,7 +54,6 @@
namespace sfl { namespace sfl {
class CoreAudioThread;
class RingBuffer; class RingBuffer;
class AudioDevice; class AudioDevice;
...@@ -84,6 +96,9 @@ class CoreLayer : public AudioLayer { ...@@ -84,6 +96,9 @@ class CoreLayer : public AudioLayer {
return indexRing_; return indexRing_;
} }
void initAudioLayerPlayback();
void initAudioLayerCapture();
/** /**
* Start the capture stream and prepare the playback stream. * Start the capture stream and prepare the playback stream.
* The playback starts accordingly to its threshold * The playback starts accordingly to its threshold
...@@ -92,6 +107,8 @@ class CoreLayer : public AudioLayer { ...@@ -92,6 +107,8 @@ class CoreLayer : public AudioLayer {
virtual void startStream(); virtual void startStream();
void destroyAudioLayer();
/** /**
* Stop the playback and capture streams. * Stop the playback and capture streams.
* Drops the pending frames and put the capture and playback handles to PREPARED state * Drops the pending frames and put the capture and playback handles to PREPARED state
...@@ -99,9 +116,39 @@ class CoreLayer : public AudioLayer { ...@@ -99,9 +116,39 @@ class CoreLayer : public AudioLayer {
*/ */
virtual void stopStream(); virtual void stopStream();
private: private:
NON_COPYABLE(CoreLayer); NON_COPYABLE(CoreLayer);
friend class CoreAudioThread;
void initAudioFormat();
static OSStatus outputCallback(void* inRefCon,
AudioUnitRenderActionFlags* ioActionFlags,
const AudioTimeStamp* inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList* ioData);
void write(AudioUnitRenderActionFlags* ioActionFlags,
const AudioTimeStamp* inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList* ioData);
static OSStatus inputCallback(void* inRefCon,
AudioUnitRenderActionFlags* ioActionFlags,
const AudioTimeStamp* inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList* ioData);
void read(AudioUnitRenderActionFlags* ioActionFlags,
const AudioTimeStamp* inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList* ioData);
virtual void updatePreference(AudioPreference &pref, int index, DeviceType type); virtual void updatePreference(AudioPreference &pref, int index, DeviceType type);
/** /**
...@@ -121,21 +168,18 @@ class CoreLayer : public AudioLayer { ...@@ -121,21 +168,18 @@ class CoreLayer : public AudioLayer {
/** Non-interleaved audio buffers */ /** Non-interleaved audio buffers */
AudioBuffer playbackBuff_; AudioBuffer playbackBuff_;
AudioBuffer captureBuff_; ::AudioBufferList* captureBuff_; // CoreAudio buffer.
/** Interleaved buffer */ /** Interleaved buffer */
std::vector<SFLAudioSample> playbackIBuff_; std::vector<SFLAudioSample> playbackIBuff_;
std::vector<SFLAudioSample> captureIBuff_; std::vector<SFLAudioSample> captureIBuff_;
bool is_playback_prepared_; AudioUnit outputUnit_;
bool is_capture_prepared_; AudioUnit inputUnit_;
std::shared_ptr<RingBuffer> mainRingBuffer_;
bool is_playback_running_; bool is_playback_running_;
bool is_capture_running_; bool is_capture_running_;
bool is_playback_open_;
bool is_capture_open_;
CoreAudioThread* audioThread_;
std::shared_ptr<RingBuffer> mainRingBuffer_;
std::vector<AudioDevice> getDeviceList(bool getCapture) const; std::vector<AudioDevice> getDeviceList(bool getCapture) const;
}; };
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment