mirror of
https://github.com/cjcliffe/CubicSDR.git
synced 2025-09-04 14:17:51 -04:00
AudioThread: re-apply consistent formating
This commit is contained in:
parent
fc1c1c3b4d
commit
033bbd07df
@ -22,23 +22,23 @@ std::recursive_mutex AudioThread::m_device_mutex;
|
|||||||
|
|
||||||
AudioThread::AudioThread() : IOThread(), nBufferFrames(1024), sampleRate(0), controllerThread(nullptr) {
|
AudioThread::AudioThread() : IOThread(), nBufferFrames(1024), sampleRate(0), controllerThread(nullptr) {
|
||||||
|
|
||||||
audioQueuePtr = 0;
|
audioQueuePtr = 0;
|
||||||
underflowCount = 0;
|
underflowCount = 0;
|
||||||
active.store(false);
|
active.store(false);
|
||||||
outputDevice.store(-1);
|
outputDevice.store(-1);
|
||||||
gain = 1.0;
|
gain = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioThread::~AudioThread() {
|
AudioThread::~AudioThread() {
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
if (controllerThread != nullptr) {
|
|
||||||
|
|
||||||
controllerThread->join();
|
if (controllerThread != nullptr) {
|
||||||
delete controllerThread;
|
|
||||||
|
controllerThread->join();
|
||||||
controllerThread = nullptr;
|
delete controllerThread;
|
||||||
}
|
|
||||||
|
controllerThread = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::recursive_mutex & AudioThread::getMutex()
|
std::recursive_mutex & AudioThread::getMutex()
|
||||||
@ -47,15 +47,15 @@ std::recursive_mutex & AudioThread::getMutex()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioThread::attachControllerThread(std::thread* controllerThread_in) {
|
void AudioThread::attachControllerThread(std::thread* controllerThread_in) {
|
||||||
|
|
||||||
//cleanup previous (should never happen)
|
|
||||||
if (controllerThread != nullptr) {
|
|
||||||
|
|
||||||
controllerThread->join();
|
//cleanup previous (should never happen)
|
||||||
delete controllerThread;
|
if (controllerThread != nullptr) {
|
||||||
}
|
|
||||||
|
|
||||||
controllerThread = controllerThread_in;
|
controllerThread->join();
|
||||||
|
delete controllerThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
controllerThread = controllerThread_in;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioThread::bindThread(AudioThread *other) {
|
void AudioThread::bindThread(AudioThread *other) {
|
||||||
@ -68,8 +68,8 @@ void AudioThread::bindThread(AudioThread *other) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioThread::removeThread(AudioThread *other) {
|
void AudioThread::removeThread(AudioThread *other) {
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
auto i = std::find(boundThreads.begin(), boundThreads.end(), other);
|
auto i = std::find(boundThreads.begin(), boundThreads.end(), other);
|
||||||
|
|
||||||
@ -80,15 +80,15 @@ void AudioThread::removeThread(AudioThread *other) {
|
|||||||
|
|
||||||
void AudioThread::deviceCleanup() {
|
void AudioThread::deviceCleanup() {
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
|
||||||
// only notify, let the thread die by itself.
|
// only notify, let the thread die by itself.
|
||||||
for (auto i = deviceController.begin(); i != deviceController.end(); i++) {
|
for (auto i = deviceController.begin(); i != deviceController.end(); i++) {
|
||||||
i->second->terminate();
|
i->second->terminate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned int nBufferFrames, double /* streamTime */, RtAudioStreamStatus status,
|
static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned int nBufferFrames, double /* streamTime */, RtAudioStreamStatus status,
|
||||||
void *userData) {
|
void *userData) {
|
||||||
|
|
||||||
float *out = (float*)outputBuffer;
|
float *out = (float*)outputBuffer;
|
||||||
|
|
||||||
@ -96,10 +96,10 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
|
|||||||
//actually active.
|
//actually active.
|
||||||
::memset(out, 0, nBufferFrames * 2 * sizeof(float));
|
::memset(out, 0, nBufferFrames * 2 * sizeof(float));
|
||||||
|
|
||||||
//src in the controller thread:
|
//src in the controller thread:
|
||||||
AudioThread *src = (AudioThread *) userData;
|
AudioThread *src = (AudioThread *)userData;
|
||||||
|
|
||||||
//by construction, src is a controller thread, from deviceController:
|
//by construction, src is a controller thread, from deviceController:
|
||||||
std::lock_guard<std::recursive_mutex> lock(src->getMutex());
|
std::lock_guard<std::recursive_mutex> lock(src->getMutex());
|
||||||
|
|
||||||
if (src->isTerminated()) {
|
if (src->isTerminated()) {
|
||||||
@ -107,15 +107,15 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
std::cout << "Audio buffer underflow.." << (src->underflowCount++) << std::endl << std::flush;
|
std::cout << "Audio buffer underflow.." << (src->underflowCount++) << std::endl << std::flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
double peak = 0.0;
|
double peak = 0.0;
|
||||||
|
|
||||||
//Process the bound threads audio:
|
//Process the bound threads audio:
|
||||||
for (size_t j = 0; j < src->boundThreads.size(); j++) {
|
for (size_t j = 0; j < src->boundThreads.size(); j++) {
|
||||||
|
|
||||||
AudioThread *srcmix = src->boundThreads[j];
|
AudioThread *srcmix = src->boundThreads[j];
|
||||||
|
|
||||||
//lock every single boundThread srcmix in succession the time we process
|
//lock every single boundThread srcmix in succession the time we process
|
||||||
//its audio samples.
|
//its audio samples.
|
||||||
@ -127,23 +127,23 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
|
|||||||
|
|
||||||
if (!srcmix->currentInput) {
|
if (!srcmix->currentInput) {
|
||||||
srcmix->audioQueuePtr = 0;
|
srcmix->audioQueuePtr = 0;
|
||||||
|
|
||||||
if (!srcmix->inputQueue->try_pop(srcmix->currentInput)) {
|
if (!srcmix->inputQueue->try_pop(srcmix->currentInput)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (srcmix->currentInput->sampleRate != src->getSampleRate()) {
|
if (srcmix->currentInput->sampleRate != src->getSampleRate()) {
|
||||||
|
|
||||||
while (srcmix->inputQueue->try_pop(srcmix->currentInput)) {
|
while (srcmix->inputQueue->try_pop(srcmix->currentInput)) {
|
||||||
|
|
||||||
if (srcmix->currentInput) {
|
if (srcmix->currentInput) {
|
||||||
if (srcmix->currentInput->sampleRate == src->getSampleRate()) {
|
if (srcmix->currentInput->sampleRate == src->getSampleRate()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
srcmix->currentInput = nullptr;
|
srcmix->currentInput = nullptr;
|
||||||
} //end while
|
} //end while
|
||||||
@ -160,13 +160,13 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
|
|||||||
if (!srcmix->inputQueue->empty()) {
|
if (!srcmix->inputQueue->empty()) {
|
||||||
srcmix->audioQueuePtr = 0;
|
srcmix->audioQueuePtr = 0;
|
||||||
if (srcmix->currentInput) {
|
if (srcmix->currentInput) {
|
||||||
|
|
||||||
srcmix->currentInput = nullptr;
|
srcmix->currentInput = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!srcmix->inputQueue->try_pop(srcmix->currentInput)) {
|
if (!srcmix->inputQueue->try_pop(srcmix->currentInput)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -180,7 +180,7 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
|
|||||||
if (srcmix->audioQueuePtr >= srcmix->currentInput->data.size()) {
|
if (srcmix->audioQueuePtr >= srcmix->currentInput->data.size()) {
|
||||||
srcmix->audioQueuePtr = 0;
|
srcmix->audioQueuePtr = 0;
|
||||||
if (srcmix->currentInput) {
|
if (srcmix->currentInput) {
|
||||||
|
|
||||||
srcmix->currentInput = nullptr;
|
srcmix->currentInput = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +188,7 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
double srcPeak = srcmix->currentInput->peak * srcmix->gain;
|
double srcPeak = srcmix->currentInput->peak * srcmix->gain;
|
||||||
if (mixPeak < srcPeak) {
|
if (mixPeak < srcPeak) {
|
||||||
mixPeak = srcPeak;
|
mixPeak = srcPeak;
|
||||||
@ -201,13 +201,14 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
|
|||||||
}
|
}
|
||||||
srcmix->audioQueuePtr++;
|
srcmix->audioQueuePtr++;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
for (int i = 0, iMax = srcmix->currentInput->channels * nBufferFrames; i < iMax; i++) {
|
for (int i = 0, iMax = srcmix->currentInput->channels * nBufferFrames; i < iMax; i++) {
|
||||||
|
|
||||||
if (srcmix->audioQueuePtr >= srcmix->currentInput->data.size()) {
|
if (srcmix->audioQueuePtr >= srcmix->currentInput->data.size()) {
|
||||||
srcmix->audioQueuePtr = 0;
|
srcmix->audioQueuePtr = 0;
|
||||||
if (srcmix->currentInput) {
|
if (srcmix->currentInput) {
|
||||||
|
|
||||||
srcmix->currentInput = nullptr;
|
srcmix->currentInput = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,58 +297,58 @@ void AudioThread::enumerateDevices(std::vector<RtAudio::DeviceInfo> &devs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioThread::setDeviceSampleRate(int deviceId, int sampleRate) {
|
void AudioThread::setDeviceSampleRate(int deviceId, int sampleRate) {
|
||||||
|
|
||||||
AudioThread* matchingControllerThread = nullptr;
|
|
||||||
|
|
||||||
//scope lock here to minimize the common unique static lock contention
|
AudioThread* matchingControllerThread = nullptr;
|
||||||
{
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
|
|
||||||
|
|
||||||
if (deviceController.find(deviceId) != deviceController.end()) {
|
//scope lock here to minimize the common unique static lock contention
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
|
||||||
|
|
||||||
matchingControllerThread = deviceController[deviceId];
|
if (deviceController.find(deviceId) != deviceController.end()) {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//out-of-lock test
|
matchingControllerThread = deviceController[deviceId];
|
||||||
if (matchingControllerThread != nullptr) {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AudioThreadCommand refreshDevice;
|
//out-of-lock test
|
||||||
refreshDevice.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_SAMPLE_RATE;
|
if (matchingControllerThread != nullptr) {
|
||||||
refreshDevice.int_value = sampleRate;
|
|
||||||
//VSO : blocking push !
|
AudioThreadCommand refreshDevice;
|
||||||
matchingControllerThread->getCommandQueue()->push(refreshDevice);
|
refreshDevice.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_SAMPLE_RATE;
|
||||||
}
|
refreshDevice.int_value = sampleRate;
|
||||||
|
//VSO : blocking push !
|
||||||
|
matchingControllerThread->getCommandQueue()->push(refreshDevice);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioThread::setSampleRate(int sampleRate) {
|
void AudioThread::setSampleRate(int sampleRate) {
|
||||||
|
|
||||||
bool thisIsAController = false;
|
bool thisIsAController = false;
|
||||||
|
|
||||||
//scope lock here to minimize the common unique static lock contention
|
//scope lock here to minimize the common unique static lock contention
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
|
||||||
|
|
||||||
if (deviceController[outputDevice.load()] == this) {
|
if (deviceController[outputDevice.load()] == this) {
|
||||||
thisIsAController = true;
|
thisIsAController = true;
|
||||||
deviceSampleRate[outputDevice.load()] = sampleRate;
|
deviceSampleRate[outputDevice.load()] = sampleRate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
if (thisIsAController) {
|
if (thisIsAController) {
|
||||||
|
|
||||||
dac.stopStream();
|
dac.stopStream();
|
||||||
dac.closeStream();
|
dac.closeStream();
|
||||||
|
|
||||||
//Set bounded sample rate:
|
//Set bounded sample rate:
|
||||||
for (size_t j = 0; j < boundThreads.size(); j++) {
|
for (size_t j = 0; j < boundThreads.size(); j++) {
|
||||||
AudioThread *srcmix = boundThreads[j];
|
AudioThread *srcmix = boundThreads[j];
|
||||||
// the controller thread is part of the boundedThreads, so prevent infinite recursion:
|
// the controller thread is part of the boundedThreads, so prevent infinite recursion:
|
||||||
if (srcmix != this) {
|
if (srcmix != this) {
|
||||||
srcmix->setSampleRate(sampleRate);
|
srcmix->setSampleRate(sampleRate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//make a local copy, snapshot of the list of demodulators
|
//make a local copy, snapshot of the list of demodulators
|
||||||
@ -359,7 +360,7 @@ void AudioThread::setSampleRate(int sampleRate) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dac.openStream(¶meters, NULL, RTAUDIO_FLOAT32, sampleRate, &nBufferFrames, &audioCallback, (void *) this, &opts);
|
dac.openStream(¶meters, NULL, RTAUDIO_FLOAT32, sampleRate, &nBufferFrames, &audioCallback, (void *)this, &opts);
|
||||||
dac.startStream();
|
dac.startStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,8 +375,8 @@ int AudioThread::getSampleRate() {
|
|||||||
|
|
||||||
void AudioThread::setupDevice(int deviceId) {
|
void AudioThread::setupDevice(int deviceId) {
|
||||||
|
|
||||||
//global lock to setup the device...
|
//global lock to setup the device...
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
|
||||||
|
|
||||||
parameters.deviceId = deviceId;
|
parameters.deviceId = deviceId;
|
||||||
parameters.nChannels = 2;
|
parameters.nChannels = 2;
|
||||||
@ -385,10 +386,10 @@ void AudioThread::setupDevice(int deviceId) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (deviceController.find(outputDevice.load()) != deviceController.end()) {
|
if (deviceController.find(outputDevice.load()) != deviceController.end()) {
|
||||||
//'this' is not the controller, so remove it from the bounded list:
|
//'this' is not the controller, so remove it from the bounded list:
|
||||||
//beware, we must take the controller mutex, because the audio callback may use the list of bounded
|
//beware, we must take the controller mutex, because the audio callback may use the list of bounded
|
||||||
//threads at that moment:
|
//threads at that moment:
|
||||||
std::lock_guard<std::recursive_mutex> lock(deviceController[outputDevice.load()]->getMutex());
|
std::lock_guard<std::recursive_mutex> lock(deviceController[outputDevice.load()]->getMutex());
|
||||||
|
|
||||||
deviceController[outputDevice.load()]->removeThread(this);
|
deviceController[outputDevice.load()]->removeThread(this);
|
||||||
}
|
}
|
||||||
@ -400,39 +401,43 @@ void AudioThread::setupDevice(int deviceId) {
|
|||||||
|
|
||||||
if (deviceSampleRate.find(parameters.deviceId) != deviceSampleRate.end()) {
|
if (deviceSampleRate.find(parameters.deviceId) != deviceSampleRate.end()) {
|
||||||
sampleRate = deviceSampleRate[parameters.deviceId];
|
sampleRate = deviceSampleRate[parameters.deviceId];
|
||||||
} else {
|
}
|
||||||
std::cout << "Error, device sample rate wasn't initialized?" << std::endl;
|
else {
|
||||||
return;
|
std::cout << "Error, device sample rate wasn't initialized?" << std::endl;
|
||||||
// sampleRate = AudioThread::getDefaultAudioSampleRate();
|
return;
|
||||||
// deviceSampleRate[parameters.deviceId] = sampleRate;
|
// sampleRate = AudioThread::getDefaultAudioSampleRate();
|
||||||
|
// deviceSampleRate[parameters.deviceId] = sampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Create a new controller:
|
//Create a new controller:
|
||||||
if (deviceController.find(parameters.deviceId) == deviceController.end()) {
|
if (deviceController.find(parameters.deviceId) == deviceController.end()) {
|
||||||
|
|
||||||
//Create a new controller thread for parameters.deviceId:
|
//Create a new controller thread for parameters.deviceId:
|
||||||
deviceController[parameters.deviceId] = new AudioThread();
|
deviceController[parameters.deviceId] = new AudioThread();
|
||||||
|
|
||||||
deviceController[parameters.deviceId]->setInitOutputDevice(parameters.deviceId, sampleRate);
|
deviceController[parameters.deviceId]->setInitOutputDevice(parameters.deviceId, sampleRate);
|
||||||
deviceController[parameters.deviceId]->bindThread(this);
|
deviceController[parameters.deviceId]->bindThread(this);
|
||||||
deviceController[parameters.deviceId]->attachControllerThread(new std::thread(&AudioThread::threadMain, deviceController[parameters.deviceId]));
|
deviceController[parameters.deviceId]->attachControllerThread(new std::thread(&AudioThread::threadMain, deviceController[parameters.deviceId]));
|
||||||
|
|
||||||
} else if (deviceController[parameters.deviceId] == this) {
|
}
|
||||||
|
else if (deviceController[parameters.deviceId] == this) {
|
||||||
|
|
||||||
//Attach callback
|
//Attach callback
|
||||||
dac.openStream(¶meters, NULL, RTAUDIO_FLOAT32, sampleRate, &nBufferFrames, &audioCallback, (void *)this, &opts);
|
dac.openStream(¶meters, NULL, RTAUDIO_FLOAT32, sampleRate, &nBufferFrames, &audioCallback, (void *)this, &opts);
|
||||||
dac.startStream();
|
dac.startStream();
|
||||||
} else {
|
}
|
||||||
//we are a bound thread, add ourselves to the controller deviceController[parameters.deviceId].
|
else {
|
||||||
//beware, we must take the controller mutex, because the audio callback may use the list of bounded
|
//we are a bound thread, add ourselves to the controller deviceController[parameters.deviceId].
|
||||||
//threads at that moment:
|
//beware, we must take the controller mutex, because the audio callback may use the list of bounded
|
||||||
std::lock_guard<std::recursive_mutex> lock(deviceController[parameters.deviceId]->getMutex());
|
//threads at that moment:
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(deviceController[parameters.deviceId]->getMutex());
|
||||||
|
|
||||||
deviceController[parameters.deviceId]->bindThread(this);
|
deviceController[parameters.deviceId]->bindThread(this);
|
||||||
}
|
}
|
||||||
active = true;
|
active = true;
|
||||||
|
|
||||||
} catch (RtAudioError& e) {
|
}
|
||||||
|
catch (RtAudioError& e) {
|
||||||
e.printMessage();
|
e.printMessage();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -452,16 +457,17 @@ int AudioThread::getOutputDevice() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioThread::setInitOutputDevice(int deviceId, int sampleRate) {
|
void AudioThread::setInitOutputDevice(int deviceId, int sampleRate) {
|
||||||
|
|
||||||
//global lock
|
//global lock
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
|
||||||
|
|
||||||
outputDevice = deviceId;
|
outputDevice = deviceId;
|
||||||
if (sampleRate == -1) {
|
if (sampleRate == -1) {
|
||||||
if (deviceSampleRate.find(parameters.deviceId) != deviceSampleRate.end()) {
|
if (deviceSampleRate.find(parameters.deviceId) != deviceSampleRate.end()) {
|
||||||
sampleRate = deviceSampleRate[deviceId];
|
sampleRate = deviceSampleRate[deviceId];
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
deviceSampleRate[deviceId] = sampleRate;
|
deviceSampleRate[deviceId] = sampleRate;
|
||||||
}
|
}
|
||||||
this->sampleRate = sampleRate;
|
this->sampleRate = sampleRate;
|
||||||
@ -470,12 +476,12 @@ void AudioThread::setInitOutputDevice(int deviceId, int sampleRate) {
|
|||||||
void AudioThread::run() {
|
void AudioThread::run() {
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
pthread_t tID = pthread_self(); // ID of this thread
|
pthread_t tID = pthread_self(); // ID of this thread
|
||||||
int priority = sched_get_priority_max( SCHED_RR) - 1;
|
int priority = sched_get_priority_max(SCHED_RR) - 1;
|
||||||
sched_param prio = {priority}; // scheduling priority of thread
|
sched_param prio = { priority }; // scheduling priority of thread
|
||||||
pthread_setschedparam(tID, SCHED_RR, &prio);
|
pthread_setschedparam(tID, SCHED_RR, &prio);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// std::cout << "Audio thread initializing.." << std::endl;
|
// std::cout << "Audio thread initializing.." << std::endl;
|
||||||
|
|
||||||
if (dac.getDeviceCount() < 1) {
|
if (dac.getDeviceCount() < 1) {
|
||||||
std::cout << "No audio devices found!" << std::endl;
|
std::cout << "No audio devices found!" << std::endl;
|
||||||
@ -484,10 +490,10 @@ void AudioThread::run() {
|
|||||||
|
|
||||||
setupDevice((outputDevice.load() == -1) ? (dac.getDefaultOutputDevice()) : outputDevice.load());
|
setupDevice((outputDevice.load() == -1) ? (dac.getDefaultOutputDevice()) : outputDevice.load());
|
||||||
|
|
||||||
// std::cout << "Audio thread started." << std::endl;
|
// std::cout << "Audio thread started." << std::endl;
|
||||||
|
|
||||||
inputQueue = std::static_pointer_cast<AudioThreadInputQueue>(getInputQueue("AudioDataInput"));
|
inputQueue = std::static_pointer_cast<AudioThreadInputQueue>(getInputQueue("AudioDataInput"));
|
||||||
|
|
||||||
//Infinite loop, witing for commands or for termination
|
//Infinite loop, witing for commands or for termination
|
||||||
while (!stopping) {
|
while (!stopping) {
|
||||||
AudioThreadCommand command;
|
AudioThreadCommand command;
|
||||||
@ -503,27 +509,28 @@ void AudioThread::run() {
|
|||||||
setSampleRate(command.int_value);
|
setSampleRate(command.int_value);
|
||||||
}
|
}
|
||||||
} //end while
|
} //end while
|
||||||
|
|
||||||
// Drain any remaining inputs, with a non-blocking pop
|
// Drain any remaining inputs, with a non-blocking pop
|
||||||
if (inputQueue != nullptr) {
|
if (inputQueue != nullptr) {
|
||||||
inputQueue->flush();
|
inputQueue->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Nullify currentInput...
|
//Nullify currentInput...
|
||||||
currentInput = nullptr;
|
currentInput = nullptr;
|
||||||
|
|
||||||
//Stop : this affects the device list , so must be protected globally.
|
//Stop : this affects the device list , so must be protected globally.
|
||||||
std::lock_guard<std::recursive_mutex> global_lock(m_device_mutex);
|
std::lock_guard<std::recursive_mutex> global_lock(m_device_mutex);
|
||||||
|
|
||||||
if (deviceController[parameters.deviceId] != this) {
|
if (deviceController[parameters.deviceId] != this) {
|
||||||
//'this' is not the controller, so remove it from the bounded list:
|
//'this' is not the controller, so remove it from the bounded list:
|
||||||
//beware, we must take the controller mutex, because the audio callback may use the list of bounded
|
//beware, we must take the controller mutex, because the audio callback may use the list of bounded
|
||||||
//threads at that moment:
|
//threads at that moment:
|
||||||
std::lock_guard<std::recursive_mutex> lock(deviceController[parameters.deviceId]->getMutex());
|
std::lock_guard<std::recursive_mutex> lock(deviceController[parameters.deviceId]->getMutex());
|
||||||
|
|
||||||
deviceController[parameters.deviceId]->removeThread(this);
|
deviceController[parameters.deviceId]->removeThread(this);
|
||||||
} else {
|
}
|
||||||
// 'this' is a controller thread:
|
else {
|
||||||
|
// 'this' is a controller thread:
|
||||||
try {
|
try {
|
||||||
if (dac.isStreamOpen()) {
|
if (dac.isStreamOpen()) {
|
||||||
if (dac.isStreamRunning()) {
|
if (dac.isStreamRunning()) {
|
||||||
@ -531,12 +538,13 @@ void AudioThread::run() {
|
|||||||
}
|
}
|
||||||
dac.closeStream();
|
dac.closeStream();
|
||||||
}
|
}
|
||||||
} catch (RtAudioError& e) {
|
}
|
||||||
|
catch (RtAudioError& e) {
|
||||||
e.printMessage();
|
e.printMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::cout << "Audio thread done." << std::endl;
|
// std::cout << "Audio thread done." << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioThread::terminate() {
|
void AudioThread::terminate() {
|
||||||
@ -551,32 +559,33 @@ bool AudioThread::isActive() {
|
|||||||
|
|
||||||
void AudioThread::setActive(bool state) {
|
void AudioThread::setActive(bool state) {
|
||||||
|
|
||||||
AudioThread* matchingControllerThread = nullptr;
|
AudioThread* matchingControllerThread = nullptr;
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
//scope lock here to minimize the common unique static lock contention
|
//scope lock here to minimize the common unique static lock contention
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
|
||||||
|
|
||||||
if (deviceController.find(parameters.deviceId) != deviceController.end()) {
|
if (deviceController.find(parameters.deviceId) != deviceController.end()) {
|
||||||
|
|
||||||
matchingControllerThread = deviceController[parameters.deviceId];
|
matchingControllerThread = deviceController[parameters.deviceId];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchingControllerThread == nullptr) {
|
if (matchingControllerThread == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state && !active && inputQueue) {
|
if (state && !active && inputQueue) {
|
||||||
matchingControllerThread->bindThread(this);
|
matchingControllerThread->bindThread(this);
|
||||||
} else if (!state && active) {
|
}
|
||||||
matchingControllerThread->removeThread(this);
|
else if (!state && active) {
|
||||||
|
matchingControllerThread->removeThread(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activity state changing, clear any inputs
|
// Activity state changing, clear any inputs
|
||||||
if(inputQueue) {
|
if (inputQueue) {
|
||||||
inputQueue->flush();
|
inputQueue->flush();
|
||||||
}
|
}
|
||||||
active = state;
|
active = state;
|
||||||
@ -587,7 +596,7 @@ AudioThreadCommandQueue *AudioThread::getCommandQueue() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioThread::setGain(float gain_in) {
|
void AudioThread::setGain(float gain_in) {
|
||||||
|
|
||||||
if (gain_in < 0.0) {
|
if (gain_in < 0.0) {
|
||||||
gain_in = 0.0;
|
gain_in = 0.0;
|
||||||
}
|
}
|
||||||
|
@ -21,20 +21,20 @@ public:
|
|||||||
int channels;
|
int channels;
|
||||||
float peak;
|
float peak;
|
||||||
int type;
|
int type;
|
||||||
bool is_squelch_active;
|
bool is_squelch_active;
|
||||||
|
|
||||||
std::vector<float> data;
|
std::vector<float> data;
|
||||||
|
|
||||||
AudioThreadInput() :
|
AudioThreadInput() :
|
||||||
frequency(0), inputRate(0), sampleRate(0), channels(0), peak(0), type(0), is_squelch_active(false) {
|
frequency(0), inputRate(0), sampleRate(0), channels(0), peak(0), type(0), is_squelch_active(false) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AudioThreadInput(AudioThreadInput *copyFrom) {
|
AudioThreadInput(AudioThreadInput *copyFrom) {
|
||||||
copy(copyFrom);
|
copy(copyFrom);
|
||||||
}
|
}
|
||||||
|
|
||||||
void copy(AudioThreadInput *copyFrom) {
|
void copy(AudioThreadInput *copyFrom) {
|
||||||
frequency = copyFrom->frequency;
|
frequency = copyFrom->frequency;
|
||||||
inputRate = copyFrom->inputRate;
|
inputRate = copyFrom->inputRate;
|
||||||
@ -46,9 +46,9 @@ public:
|
|||||||
data.assign(copyFrom->data.begin(), copyFrom->data.end());
|
data.assign(copyFrom->data.begin(), copyFrom->data.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual ~AudioThreadInput() {
|
virtual ~AudioThreadInput() {
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
AudioThreadCommand() :
|
AudioThreadCommand() :
|
||||||
cmd(AUDIO_THREAD_CMD_NULL), int_value(0) {
|
cmd(AUDIO_THREAD_CMD_NULL), int_value(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioThreadCommandEnum cmd;
|
AudioThreadCommandEnum cmd;
|
||||||
@ -81,15 +81,15 @@ typedef std::shared_ptr<AudioThreadCommandQueue> AudioThreadCommandQueuePtr;
|
|||||||
class AudioThread : public IOThread {
|
class AudioThread : public IOThread {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
AudioThread();
|
AudioThread();
|
||||||
virtual ~AudioThread();
|
virtual ~AudioThread();
|
||||||
|
|
||||||
static void enumerateDevices(std::vector<RtAudio::DeviceInfo> &devs);
|
static void enumerateDevices(std::vector<RtAudio::DeviceInfo> &devs);
|
||||||
|
|
||||||
void setInitOutputDevice(int deviceId, int sampleRate=-1);
|
void setInitOutputDevice(int deviceId, int sampleRate = -1);
|
||||||
int getOutputDevice();
|
int getOutputDevice();
|
||||||
|
|
||||||
int getSampleRate();
|
int getSampleRate();
|
||||||
|
|
||||||
virtual void run();
|
virtual void run();
|
||||||
@ -99,7 +99,7 @@ public:
|
|||||||
void setActive(bool state);
|
void setActive(bool state);
|
||||||
|
|
||||||
void setGain(float gain_in);
|
void setGain(float gain_in);
|
||||||
|
|
||||||
static std::map<int, int> deviceSampleRate;
|
static std::map<int, int> deviceSampleRate;
|
||||||
|
|
||||||
AudioThreadCommandQueue *getCommandQueue();
|
AudioThreadCommandQueue *getCommandQueue();
|
||||||
@ -110,8 +110,8 @@ public:
|
|||||||
static void deviceCleanup();
|
static void deviceCleanup();
|
||||||
static void setDeviceSampleRate(int deviceId, int sampleRate);
|
static void setDeviceSampleRate(int deviceId, int sampleRate);
|
||||||
|
|
||||||
//
|
//
|
||||||
void attachControllerThread(std::thread* controllerThread);
|
void attachControllerThread(std::thread* controllerThread);
|
||||||
|
|
||||||
//fields below, only to be used by other AudioThreads !
|
//fields below, only to be used by other AudioThreads !
|
||||||
size_t underflowCount;
|
size_t underflowCount;
|
||||||
@ -126,7 +126,7 @@ private:
|
|||||||
|
|
||||||
std::atomic_bool active;
|
std::atomic_bool active;
|
||||||
std::atomic_int outputDevice;
|
std::atomic_int outputDevice;
|
||||||
|
|
||||||
RtAudio dac;
|
RtAudio dac;
|
||||||
unsigned int nBufferFrames;
|
unsigned int nBufferFrames;
|
||||||
RtAudio::StreamOptions opts;
|
RtAudio::StreamOptions opts;
|
||||||
@ -134,8 +134,8 @@ private:
|
|||||||
AudioThreadCommandQueue cmdQueue;
|
AudioThreadCommandQueue cmdQueue;
|
||||||
int sampleRate;
|
int sampleRate;
|
||||||
|
|
||||||
//if != nullptr, it mean AudioThread is a controller thread.
|
//if != nullptr, it mean AudioThread is a controller thread.
|
||||||
std::thread* controllerThread = nullptr;
|
std::thread* controllerThread = nullptr;
|
||||||
|
|
||||||
//The own m_mutex protecting this AudioThread, in particular boundThreads
|
//The own m_mutex protecting this AudioThread, in particular boundThreads
|
||||||
std::recursive_mutex m_mutex;
|
std::recursive_mutex m_mutex;
|
||||||
@ -146,8 +146,8 @@ private:
|
|||||||
void bindThread(AudioThread *other);
|
void bindThread(AudioThread *other);
|
||||||
void removeThread(AudioThread *other);
|
void removeThread(AudioThread *other);
|
||||||
|
|
||||||
static std::map<int, AudioThread* > deviceController;
|
static std::map<int, AudioThread* > deviceController;
|
||||||
|
|
||||||
//The mutex protecting static deviceController, deviceThread and deviceSampleRate access.
|
//The mutex protecting static deviceController, deviceThread and deviceSampleRate access.
|
||||||
static std::recursive_mutex m_device_mutex;
|
static std::recursive_mutex m_device_mutex;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user