[DEV] rework and correct timestamp of Alsa (pase 1)
This commit is contained in:
@@ -30,14 +30,17 @@ namespace airtaudio {
|
||||
bool xrun[2];
|
||||
std::condition_variable runnable_cv;
|
||||
bool runnable;
|
||||
|
||||
std::unique_ptr<std::thread> thread;
|
||||
bool threadRunning;
|
||||
AlsaPrivate() :
|
||||
synchronized(false),
|
||||
runnable(false) {
|
||||
runnable(false),
|
||||
threadRunning(false) {
|
||||
handles[0] = nullptr;
|
||||
handles[1] = nullptr;
|
||||
xrun[0] = false;
|
||||
xrun[1] = false;
|
||||
// TODO : Wait thread ...
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -692,10 +695,11 @@ foundDevice:
|
||||
} else {
|
||||
m_mode = _mode;
|
||||
// Setup callback thread.
|
||||
m_callbackInfo.isRunning = true;
|
||||
m_callbackInfo.thread = new std::thread(&airtaudio::api::Alsa::alsaCallbackEvent, this);
|
||||
if (m_callbackInfo.thread == nullptr) {
|
||||
m_callbackInfo.isRunning = false;
|
||||
m_private->threadRunning = true;
|
||||
std::unique_ptr<std::thread> tmpThread(new std::thread(&airtaudio::api::Alsa::alsaCallbackEvent, this));
|
||||
m_private->thread = std::move(tmpThread);
|
||||
if (m_private->thread == nullptr) {
|
||||
m_private->threadRunning = false;
|
||||
ATA_ERROR("creating callback thread!");
|
||||
goto error;
|
||||
}
|
||||
@@ -729,15 +733,15 @@ enum airtaudio::error airtaudio::api::Alsa::closeStream() {
|
||||
ATA_ERROR("no open stream to close!");
|
||||
return airtaudio::error_warning;
|
||||
}
|
||||
m_callbackInfo.isRunning = false;
|
||||
m_private->threadRunning = false;
|
||||
m_mutex.lock();
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
m_private->runnable = true;
|
||||
m_private->runnable_cv.notify_one();
|
||||
}
|
||||
m_mutex.unlock();
|
||||
if (m_callbackInfo.thread != nullptr) {
|
||||
m_callbackInfo.thread->join();
|
||||
if (m_private->thread != nullptr) {
|
||||
m_private->thread->join();
|
||||
}
|
||||
if (m_state == airtaudio::state_running) {
|
||||
m_state = airtaudio::state_stopped;
|
||||
@@ -909,27 +913,51 @@ unlock:
|
||||
|
||||
|
||||
void airtaudio::api::Alsa::alsaCallbackEvent(void *_userData) {
|
||||
etk::log::setThreadName("Alsa IO");
|
||||
airtaudio::api::Alsa* myClass = reinterpret_cast<airtaudio::api::Alsa*>(_userData);
|
||||
myClass->callbackEvent();
|
||||
}
|
||||
|
||||
void airtaudio::api::Alsa::callbackEvent() {
|
||||
while (m_callbackInfo.isRunning == true) {
|
||||
etk::log::setThreadName("Alsa IO-" + m_name);
|
||||
while (m_private->threadRunning == true) {
|
||||
callbackEventOneCycle();
|
||||
}
|
||||
}
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> airtaudio::api::Alsa::getStreamTime() {
|
||||
snd_pcm_uframes_t avail;
|
||||
snd_htimestamp_t tstamp;
|
||||
if (m_private->handles[0] != nullptr) {
|
||||
int plop = snd_pcm_htimestamp(m_private->handles[0], &avail, &tstamp);
|
||||
} else if (m_private->handles[1] != nullptr) {
|
||||
int plop = snd_pcm_htimestamp(m_private->handles[1], &avail, &tstamp);
|
||||
namespace std {
|
||||
static std::ostream& operator <<(std::ostream& _os, const std::chrono::system_clock::time_point& _obj) {
|
||||
std::chrono::nanoseconds ns = std::chrono::duration_cast<std::chrono::nanoseconds>(_obj.time_since_epoch());
|
||||
int64_t totalSecond = ns.count()/1000000000;
|
||||
int64_t millisecond = (ns.count()%1000000000)/1000000;
|
||||
int64_t microsecond = (ns.count()%1000000)/1000;
|
||||
int64_t nanosecond = ns.count()%1000;
|
||||
//_os << totalSecond << "s " << millisecond << "ms " << microsecond << "<22>s " << nanosecond << "ns";
|
||||
|
||||
int32_t second = totalSecond % 60;
|
||||
int32_t minute = (totalSecond/60)%60;
|
||||
int32_t hour = (totalSecond/3600)%24;
|
||||
int32_t day = (totalSecond/(24*3600))%365;
|
||||
int32_t year = totalSecond/(24*3600*365);
|
||||
_os << year << "y " << day << "d " << hour << "h" << minute << ":"<< second << "s " << millisecond << "ms " << microsecond << "µs " << nanosecond << "ns";
|
||||
return _os;
|
||||
}
|
||||
//ATA_WARNING("plop : " << tstamp.tv_sec << " sec " << tstamp.tv_nsec);
|
||||
return std::chrono::system_clock::from_time_t(tstamp.tv_sec) + std::chrono::nanoseconds(tstamp.tv_nsec);
|
||||
}
|
||||
std::chrono::time_point<std::chrono::system_clock> airtaudio::api::Alsa::getStreamTime() {
|
||||
if (m_startTime == std::chrono::system_clock::time_point()) {
|
||||
snd_pcm_uframes_t avail;
|
||||
snd_htimestamp_t tstamp;
|
||||
if (m_private->handles[0] != nullptr) {
|
||||
int plop = snd_pcm_htimestamp(m_private->handles[0], &avail, &tstamp);
|
||||
} else if (m_private->handles[1] != nullptr) {
|
||||
int plop = snd_pcm_htimestamp(m_private->handles[1], &avail, &tstamp);
|
||||
}
|
||||
//ATA_WARNING("plop : " << tstamp.tv_sec << " sec " << tstamp.tv_nsec);
|
||||
//return std::chrono::system_clock::from_time_t(tstamp.tv_sec) + std::chrono::nanoseconds(tstamp.tv_nsec);
|
||||
//m_startTime = std::chrono::system_clock::from_time_t(tstamp.tv_sec) + std::chrono::nanoseconds(tstamp.tv_nsec);
|
||||
//m_duration = std::chrono::microseconds(0);
|
||||
}
|
||||
ATA_DEBUG(" createTimeStamp : " << m_startTime + m_duration);
|
||||
return m_startTime + m_duration;
|
||||
}
|
||||
|
||||
|
||||
@@ -952,22 +980,23 @@ void airtaudio::api::Alsa::callbackEventOneCycle() {
|
||||
}
|
||||
int32_t doStopStream = 0;
|
||||
std::chrono::system_clock::time_point streamTime = getStreamTime();
|
||||
enum airtaudio::status status = airtaudio::status_ok;
|
||||
std::vector<enum airtaudio::status> status;
|
||||
if ( m_mode != airtaudio::mode_input
|
||||
&& m_private->xrun[0] == true) {
|
||||
status = airtaudio::status_underflow;
|
||||
status.push_back(airtaudio::status_underflow);
|
||||
m_private->xrun[0] = false;
|
||||
}
|
||||
if ( m_mode != airtaudio::mode_output
|
||||
&& m_private->xrun[1] == true) {
|
||||
status = airtaudio::status_overflow;
|
||||
status.push_back(airtaudio::status_overflow);
|
||||
m_private->xrun[1] = false;
|
||||
}
|
||||
doStopStream = m_callbackInfo.callback(&m_userBuffer[0][0],
|
||||
&m_userBuffer[1][0],
|
||||
m_bufferSize,
|
||||
streamTime,
|
||||
status);
|
||||
doStopStream = m_callback(&m_userBuffer[1][0],
|
||||
streamTime,
|
||||
&m_userBuffer[0][0],
|
||||
streamTime,
|
||||
m_bufferSize,
|
||||
status);
|
||||
if (doStopStream == 2) {
|
||||
abortStream();
|
||||
return;
|
||||
|
@@ -46,7 +46,7 @@ namespace airtaudio {
|
||||
enum audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
airtaudio::StreamOptions *_options);
|
||||
virtual std::chrono::time_point<std::chrono::system_clock> getStreamTime();
|
||||
virtual std::chrono::system_clock::time_point getStreamTime();
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@@ -111,20 +111,22 @@ void airtaudio::api::Android::callBackEvent(void* _data,
|
||||
int32_t _frameRate) {
|
||||
int32_t doStopStream = 0;
|
||||
std::chrono::system_clock::time_point streamTime = getStreamTime();
|
||||
enum airtaudio::status status = airtaudio::status_ok;
|
||||
std::vector<enum airtaudio::status> status;
|
||||
if (m_doConvertBuffer[airtaudio::mode_output] == true) {
|
||||
doStopStream = m_callbackInfo.callback(m_userBuffer[airtaudio::mode_output],
|
||||
nullptr,
|
||||
_frameRate,
|
||||
streamTime,
|
||||
status);
|
||||
doStopStream = m_callback(nullptr,
|
||||
std::chrono::system_clock::time_point(),
|
||||
m_userBuffer[airtaudio::mode_output],
|
||||
streamTime,
|
||||
_frameRate,
|
||||
status);
|
||||
convertBuffer((char*)_data, (char*)m_userBuffer[airtaudio::mode_output], m_convertInfo[airtaudio::mode_output]);
|
||||
} else {
|
||||
doStopStream = m_callbackInfo.callback(_data,
|
||||
nullptr,
|
||||
_frameRate,
|
||||
streamTime,
|
||||
status);
|
||||
doStopStream = m_callback(_data,
|
||||
streamTime,
|
||||
nullptr,
|
||||
std::chrono::system_clock::time_point(),
|
||||
_frameRate,
|
||||
status);
|
||||
}
|
||||
if (doStopStream == 2) {
|
||||
abortStream();
|
||||
|
@@ -502,9 +502,7 @@ bool airtaudio::api::Asio::probeDeviceOpen(uint32_t _device,
|
||||
m_sampleRate = _sampleRate;
|
||||
m_device[modeToIdTable(_mode)] = _device;
|
||||
m_state = airtaudio::state_stopped;
|
||||
asioCallbackInfo = &m_callbackInfo;
|
||||
m_callbackInfo.object = (void*)this;
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
if ( _mode == airtaudio::mode_output
|
||||
&& _mode == airtaudio::mode_input) {
|
||||
// We had already set up an output stream.
|
||||
m_mode = airtaudio::mode_duplex;
|
||||
@@ -695,19 +693,20 @@ bool airtaudio::api::Asio::callbackEvent(long bufferIndex) {
|
||||
// draining stream.
|
||||
if (m_private->drainCounter == 0) {
|
||||
std::chrono::system_clock::time_point streamTime = getStreamTime();
|
||||
rtaudio::streamStatus status = 0;
|
||||
std::vector<enum airtaudio::status status;
|
||||
if (m_mode != airtaudio::mode_input && asioXRun == true) {
|
||||
status |= RTAUDIO_airtaudio::status_underflow;
|
||||
status.push_back(airtaudio::status_underflow);
|
||||
asioXRun = false;
|
||||
}
|
||||
if (m_mode != airtaudio::mode_output && asioXRun == true) {
|
||||
status |= RTAUDIO_airtaudio::mode_input_OVERFLOW;
|
||||
status.push_back(airtaudio::status_underflow;
|
||||
asioXRun = false;
|
||||
}
|
||||
int32_t cbReturnValue = info->callback(m_userBuffer[0],
|
||||
m_userBuffer[1],
|
||||
m_bufferSize,
|
||||
int32_t cbReturnValue = info->callback(m_userBuffer[1],
|
||||
streamTime,
|
||||
m_userBuffer[0],
|
||||
streamTime,
|
||||
m_bufferSize,
|
||||
status);
|
||||
if (cbReturnValue == 2) {
|
||||
m_state = airtaudio::state_stopping;
|
||||
|
@@ -1011,7 +1011,9 @@ void airtaudio::api::Core::coreStopStream(void *_userData) {
|
||||
|
||||
bool airtaudio::api::Core::callbackEvent(AudioDeviceID _deviceId,
|
||||
const AudioBufferList *_inBufferList,
|
||||
const AudioBufferList *_outBufferList) {
|
||||
const std::chrono::system_clock::time_point& _inTime,
|
||||
const AudioBufferList *_outBufferList,
|
||||
const std::chrono::system_clock::time_point& _outTime) {
|
||||
if ( m_state == airtaudio::state_stopped
|
||||
|| m_state == airtaudio::state_stopping) {
|
||||
return true;
|
||||
@@ -1020,7 +1022,6 @@ bool airtaudio::api::Core::callbackEvent(AudioDeviceID _deviceId,
|
||||
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
||||
return false;
|
||||
}
|
||||
CallbackInfo *info = (CallbackInfo *) &m_callbackInfo;
|
||||
// Check if we were draining the stream and signal is finished.
|
||||
if (m_private->drainCounter > 3) {
|
||||
m_state = airtaudio::state_stopping;
|
||||
@@ -1038,23 +1039,23 @@ bool airtaudio::api::Core::callbackEvent(AudioDeviceID _deviceId,
|
||||
// draining stream or duplex mode AND the input/output devices are
|
||||
// different AND this function is called for the input device.
|
||||
if (m_private->drainCounter == 0 && (m_mode != airtaudio::mode_duplex || _deviceId == outputDevice)) {
|
||||
std::chrono::system_clock::time_point streamTime = getStreamTime();
|
||||
enum airtaudio::status status = airtaudio::status_ok;
|
||||
std::vector<enum airtaudio::status> status;
|
||||
if ( m_mode != airtaudio::mode_input
|
||||
&& m_private->xrun[0] == true) {
|
||||
status = airtaudio::status_underflow;
|
||||
status.push_back(airtaudio::status_underflow);
|
||||
m_private->xrun[0] = false;
|
||||
}
|
||||
if ( m_mode != airtaudio::mode_output
|
||||
&& m_private->xrun[1] == true) {
|
||||
status = airtaudio::status_overflow;
|
||||
status.push_back(airtaudio::status_overflow);
|
||||
m_private->xrun[1] = false;
|
||||
}
|
||||
int32_t cbReturnValue = info->callback(&m_userBuffer[0][0],
|
||||
&m_userBuffer[1][0],
|
||||
m_bufferSize,
|
||||
streamTime,
|
||||
status);
|
||||
int32_t cbReturnValue = m_callback(&m_userBuffer[1][0],
|
||||
_inTime,
|
||||
&m_userBuffer[0][0],
|
||||
_outTime,
|
||||
m_bufferSize,
|
||||
status);
|
||||
if (cbReturnValue == 2) {
|
||||
m_state = airtaudio::state_stopping;
|
||||
ATA_VERBOSE("Set state as stopping");
|
||||
|
@@ -31,13 +31,11 @@ namespace airtaudio {
|
||||
enum airtaudio::error stopStream();
|
||||
enum airtaudio::error abortStream();
|
||||
long getStreamLatency();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
bool callbackEvent(AudioDeviceID _deviceId,
|
||||
const AudioBufferList *_inBufferList,
|
||||
const AudioBufferList *_outBufferList);
|
||||
const std::chrono::system_clock::time_point& _inTime,
|
||||
const AudioBufferList *_outBufferList,
|
||||
const std::chrono::system_clock::time_point& _outTime);
|
||||
static OSStatus callbackEvent(AudioDeviceID _inDevice,
|
||||
const AudioTimeStamp* _inNow,
|
||||
const AudioBufferList* _inInputData,
|
||||
@@ -57,11 +55,10 @@ namespace airtaudio {
|
||||
uint32_t *_bufferSize,
|
||||
airtaudio::StreamOptions *_options);
|
||||
static const char* getErrorCode(OSStatus _code);
|
||||
|
||||
static OSStatus xrunListener(AudioObjectID _inDevice,
|
||||
uint32_t _nAddresses,
|
||||
const AudioObjectPropertyAddress _properties[],
|
||||
void* _userData);
|
||||
static OSStatus xrunListener(AudioObjectID _inDevice,
|
||||
uint32_t _nAddresses,
|
||||
const AudioObjectPropertyAddress _properties[],
|
||||
void* _userData);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@@ -111,7 +111,7 @@ enum airtaudio::error airtaudio::api::CoreIos::abortStream(void) {
|
||||
}
|
||||
|
||||
void airtaudio::api::CoreIos::callBackEvent(void* _data,
|
||||
int32_t _frameRate) {
|
||||
int32_t _nbChunk) {
|
||||
|
||||
#if 0
|
||||
static double value=0;
|
||||
@@ -128,20 +128,22 @@ void airtaudio::api::CoreIos::callBackEvent(void* _data,
|
||||
#endif
|
||||
int32_t doStopStream = 0;
|
||||
std::chrono::system_clock::time_point streamTime = getStreamTime();
|
||||
enum airtaudio::status status = airtaudio::status_ok;
|
||||
std::vector<enum airtaudio::status> status;
|
||||
if (m_doConvertBuffer[modeToIdTable(airtaudio::mode_output)] == true) {
|
||||
doStopStream = m_callbackInfo.callback(&m_userBuffer[modeToIdTable(airtaudio::mode_output)][0],
|
||||
nullptr,
|
||||
_frameRate,
|
||||
streamTime,
|
||||
status);
|
||||
doStopStream = m_callback(nullptr,
|
||||
streamTime,
|
||||
&m_userBuffer[modeToIdTable(airtaudio::mode_output)][0],
|
||||
streamTime,
|
||||
_nbChunk,
|
||||
status);
|
||||
convertBuffer((char*)_data, &m_userBuffer[modeToIdTable(airtaudio::mode_output)][0], m_convertInfo[modeToIdTable(airtaudio::mode_output)]);
|
||||
} else {
|
||||
doStopStream = m_callbackInfo.callback(_data,
|
||||
nullptr,
|
||||
_frameRate,
|
||||
streamTime,
|
||||
status);
|
||||
doStopStream = m_callback(_data,
|
||||
streamTime,
|
||||
nullptr,
|
||||
streamTime,
|
||||
_nbChunk,
|
||||
status);
|
||||
}
|
||||
if (doStopStream == 2) {
|
||||
abortStream();
|
||||
@@ -152,11 +154,11 @@ void airtaudio::api::CoreIos::callBackEvent(void* _data,
|
||||
|
||||
|
||||
static OSStatus playbackCallback(void *_userData,
|
||||
AudioUnitRenderActionFlags* _ioActionFlags,
|
||||
const AudioTimeStamp* _inTimeStamp,
|
||||
uint32_t _inBusNumber,
|
||||
uint32_t _inNumberFrames,
|
||||
AudioBufferList* _ioData) {
|
||||
AudioUnitRenderActionFlags* _ioActionFlags,
|
||||
const AudioTimeStamp* _inTimeStamp,
|
||||
uint32_t _inBusNumber,
|
||||
uint32_t _inNumberFrames,
|
||||
AudioBufferList* _ioData) {
|
||||
if (_userData == nullptr) {
|
||||
ATA_ERROR("callback event ... nullptr pointer");
|
||||
return -1;
|
||||
|
@@ -74,17 +74,20 @@ namespace airtaudio {
|
||||
namespace api {
|
||||
class DsPrivate {
|
||||
public:
|
||||
std::unique_ptr<std::thread> thread;
|
||||
bool threadRunning;
|
||||
uint32_t drainCounter; // Tracks callback counts when draining
|
||||
bool internalDrain; // Indicates if stop is initiated from callback or not.
|
||||
void *id[2];
|
||||
void *buffer[2];
|
||||
bool xrun[2];
|
||||
UINT bufferPointer[2];
|
||||
UINT bufferPointer[2];
|
||||
DWORD dsBufferSize[2];
|
||||
DWORD dsPointerLeadTime[2]; // the number of bytes ahead of the safe pointer to lead by.
|
||||
HANDLE condition;
|
||||
std::vector<DsDevice> dsDevices;
|
||||
DsPrivate() :
|
||||
threadRunning(false),
|
||||
drainCounter(0),
|
||||
internalDrain(false) {
|
||||
id[0] = 0;
|
||||
@@ -738,15 +741,16 @@ bool airtaudio::api::Ds::probeDeviceOpen(uint32_t _device,
|
||||
setConvertInfo(_mode, _firstChannel);
|
||||
}
|
||||
// Setup the callback thread.
|
||||
if (m_callbackInfo.isRunning == false) {
|
||||
m_callbackInfo.isRunning = true;
|
||||
m_callbackInfo.thread = new std::thread(&airtaudio::api::Ds::dsCallbackEvent, this);
|
||||
if (m_callbackInfo.thread == nullptr) {
|
||||
if (m_private->threadRunning == false) {
|
||||
m_private->threadRunning = true;
|
||||
std::unique_ptr<std::thread> tmpThread(new std::thread(&airtaudio::api::Ds::dsCallbackEvent, this));
|
||||
m_private->thread = std::move(tmpThread);
|
||||
if (m_private->thread == nullptr) {
|
||||
ATA_ERROR("error creating callback thread!");
|
||||
goto error;
|
||||
}
|
||||
// Boost DS thread priority
|
||||
SetThreadPriority((HANDLE)m_callbackInfo.thread, THREAD_PRIORITY_HIGHEST);
|
||||
SetThreadPriority((HANDLE)m_private->thread, THREAD_PRIORITY_HIGHEST);
|
||||
}
|
||||
return true;
|
||||
error:
|
||||
@@ -784,9 +788,9 @@ enum airtaudio::error airtaudio::api::Ds::closeStream() {
|
||||
return airtaudio::error_warning;
|
||||
}
|
||||
// Stop the callback thread.
|
||||
m_callbackInfo.isRunning = false;
|
||||
WaitForSingleObject((HANDLE) m_callbackInfo.thread, INFINITE);
|
||||
CloseHandle((HANDLE) m_callbackInfo.thread);
|
||||
m_private->threadRunning = false;
|
||||
WaitForSingleObject((HANDLE) m_private->thread, INFINITE);
|
||||
CloseHandle((HANDLE) m_private->thread);
|
||||
if (m_private->buffer[0]) { // the object pointer can be nullptr and valid
|
||||
LPDIRECTSOUND object = (LPDIRECTSOUND) m_private->id[0];
|
||||
LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) m_private->buffer[0];
|
||||
@@ -968,7 +972,6 @@ void airtaudio::api::Ds::callbackEvent() {
|
||||
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
||||
return;
|
||||
}
|
||||
CallbackInfo *info = (CallbackInfo *) &m_callbackInfo;
|
||||
// Check if we were draining the stream and signal is finished.
|
||||
if (m_private->drainCounter > m_nBuffers + 2) {
|
||||
m_state = airtaudio::state_stopping;
|
||||
@@ -994,10 +997,11 @@ void airtaudio::api::Ds::callbackEvent() {
|
||||
status = airtaudio::status_overflow;
|
||||
m_private->xrun[1] = false;
|
||||
}
|
||||
int32_t cbReturnValue = info->callback(&m_userBuffer[0][0],
|
||||
&m_userBuffer[1][0],
|
||||
m_bufferSize,
|
||||
int32_t cbReturnValue = info->callback(&m_userBuffer[1][0],
|
||||
streamTime,
|
||||
&m_userBuffer[0][0],
|
||||
streamTime,
|
||||
m_bufferSize,
|
||||
status);
|
||||
if (cbReturnValue == 2) {
|
||||
m_state = airtaudio::state_stopping;
|
||||
@@ -1257,7 +1261,7 @@ void airtaudio::api::Ds::callbackEvent() {
|
||||
}
|
||||
} else { // _mode == airtaudio::mode_input
|
||||
while ( safeReadPointer < endRead
|
||||
&& m_callbackInfo.isRunning) {
|
||||
&& m_private->threadRunning) {
|
||||
// See comments for playback.
|
||||
double millis = (endRead - safeReadPointer) * 1000.0;
|
||||
millis /= (audio::getFormatBytes(m_deviceFormat[1]) * m_nDeviceChannels[1] * m_sampleRate);
|
||||
@@ -1327,9 +1331,9 @@ unlock:
|
||||
}
|
||||
|
||||
void airtaudio::api::Ds::dsCallbackEvent(void *_userData) {
|
||||
etk::log::setThreadName("DS IO");
|
||||
etk::log::setThreadName("DS IO-" + m_name);
|
||||
airtaudio::api::Ds* myClass = reinterpret_cast<airtaudio::api::Ds*>(_userData);
|
||||
while (myClass->m_callbackInfo.isRunning == true) {
|
||||
while (myClass->m_private->threadRunning == true) {
|
||||
myClass->callbackEvent();
|
||||
}
|
||||
}
|
||||
|
@@ -654,20 +654,21 @@ bool airtaudio::api::Jack::callbackEvent(uint64_t _nframes) {
|
||||
// Invoke user callback first, to get fresh output data.
|
||||
if (m_private->drainCounter == 0) {
|
||||
std::chrono::time_point<std::chrono::system_clock> streamTime = getStreamTime();
|
||||
enum airtaudio::status status = airtaudio::status_ok;
|
||||
std::vector<enum airtaudio::status> status;
|
||||
if (m_mode != airtaudio::mode_input && m_private->xrun[0] == true) {
|
||||
status = airtaudio::status_underflow;
|
||||
status.push_back(airtaudio::status_underflow);
|
||||
m_private->xrun[0] = false;
|
||||
}
|
||||
if (m_mode != airtaudio::mode_output && m_private->xrun[1] == true) {
|
||||
status = airtaudio::status_overflow;
|
||||
status.push_back(airtaudio::status_overflow);
|
||||
m_private->xrun[1] = false;
|
||||
}
|
||||
int32_t cbReturnValue = m_callbackInfo.callback(&m_userBuffer[0][0],
|
||||
&m_userBuffer[1][0],
|
||||
m_bufferSize,
|
||||
streamTime,
|
||||
status);
|
||||
int32_t cbReturnValue = m_callback(&m_userBuffer[1][0],
|
||||
streamTime,
|
||||
&m_userBuffer[0][0],
|
||||
streamTime,
|
||||
m_bufferSize,
|
||||
status);
|
||||
if (cbReturnValue == 2) {
|
||||
m_state = airtaudio::state_stopping;
|
||||
m_private->drainCounter = 2;
|
||||
|
@@ -36,8 +36,11 @@ namespace airtaudio {
|
||||
bool xrun[2];
|
||||
bool triggered;
|
||||
std::condition_variable runnable;
|
||||
std::unique_ptr<std::thread> thread;
|
||||
bool threadRunning;
|
||||
OssPrivate():
|
||||
triggered(false) {
|
||||
triggered(false),
|
||||
threadRunning(false) {
|
||||
id[0] = 0;
|
||||
id[1] = 0;
|
||||
xrun[0] = false;
|
||||
@@ -503,10 +506,10 @@ bool airtaudio::api::Oss::probeDeviceOpen(uint32_t _device,
|
||||
} else {
|
||||
m_mode = _mode;
|
||||
// Setup callback thread.
|
||||
m_callbackInfo.isRunning = true;
|
||||
m_callbackInfo.thread = new std::thread(ossCallbackHandler, this);
|
||||
if (m_callbackInfo.thread == nullptr) {
|
||||
m_callbackInfo.isRunning = false;
|
||||
m_private->threadRunning = true;
|
||||
m_private->thread = new std::thread(ossCallbackHandler, this);
|
||||
if (m_private->thread == nullptr) {
|
||||
m_private->threadRunning = false;
|
||||
ATA_ERROR("creating callback thread!");
|
||||
goto error;
|
||||
}
|
||||
@@ -539,13 +542,13 @@ enum airtaudio::error airtaudio::api::Oss::closeStream() {
|
||||
ATA_ERROR("no open stream to close!");
|
||||
return airtaudio::error_warning;
|
||||
}
|
||||
m_callbackInfo.isRunning = false;
|
||||
m_private->threadRunning = false;
|
||||
m_mutex.lock();
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
m_private->runnable.notify_one();
|
||||
}
|
||||
m_mutex.unlock();
|
||||
m_callbackInfo.thread->join();
|
||||
m_private->thread->join();
|
||||
if (m_state == airtaudio::state_running) {
|
||||
if (m_mode == airtaudio::mode_output || m_mode == airtaudio::mode_duplex) {
|
||||
ioctl(m_private->id[0], SNDCTL_DSP_HALT, 0);
|
||||
@@ -712,22 +715,23 @@ void airtaudio::api::Oss::callbackEvent() {
|
||||
// Invoke user callback to get fresh output data.
|
||||
int32_t doStopStream = 0;
|
||||
std::chrono::system_clock::time_point streamTime = getStreamTime();
|
||||
rtaudio::streamStatus status = 0;
|
||||
std::vector<enum airtaudio::status> status;
|
||||
if ( m_mode != airtaudio::mode_input
|
||||
&& m_private->xrun[0] == true) {
|
||||
status |= RTAUDIO_airtaudio::status_underflow;
|
||||
status.push_back(airtaudio::status_underflow);
|
||||
m_private->xrun[0] = false;
|
||||
}
|
||||
if ( m_mode != airtaudio::mode_output
|
||||
&& m_private->xrun[1] == true) {
|
||||
status |= RTAUDIO_airtaudio::mode_input_OVERFLOW;
|
||||
status.push_back(airtaudio::status_overflow);
|
||||
m_private->xrun[1] = false;
|
||||
}
|
||||
doStopStream = m_callbackInfo.callback(m_userBuffer[0],
|
||||
m_userBuffer[1],
|
||||
m_bufferSize,
|
||||
streamTime,
|
||||
status);
|
||||
doStopStream = m_callback(m_userBuffer[1],
|
||||
streamTime,
|
||||
m_userBuffer[0],
|
||||
streamTime,
|
||||
m_bufferSize,
|
||||
status);
|
||||
if (doStopStream == 2) {
|
||||
this->abortStream();
|
||||
return;
|
||||
@@ -818,9 +822,9 @@ unlock:
|
||||
}
|
||||
|
||||
static void ossCallbackHandler(void* _userData) {
|
||||
etk::log::setThreadName("OSS callback");
|
||||
etk::log::setThreadName("OSS callback-" + m_name);
|
||||
airtaudio::api::Alsa* myClass = reinterpret_cast<airtaudio::api::Oss*>(_userData);
|
||||
while (myClass->m_callbackInfo->isRunning == true) {
|
||||
while (myClass->m_private->threadRunning == true) {
|
||||
myClass->callbackEvent();
|
||||
}
|
||||
}
|
||||
|
@@ -12,9 +12,6 @@
|
||||
#include <limits.h>
|
||||
#include <airtaudio/Interface.h>
|
||||
#include <airtaudio/debug.h>
|
||||
// Code written by Peter Meerwald, pmeerw@pmeerw.net
|
||||
// and Tristan Matthews.
|
||||
|
||||
#include <pulse/error.h>
|
||||
#include <pulse/simple.h>
|
||||
#include <cstdio>
|
||||
@@ -56,12 +53,14 @@ namespace airtaudio {
|
||||
public:
|
||||
pa_simple *s_play;
|
||||
pa_simple *s_rec;
|
||||
std::thread* thread;
|
||||
std::unique_ptr<std::thread> thread;
|
||||
bool threadRunning;
|
||||
std::condition_variable runnable_cv;
|
||||
bool runnable;
|
||||
PulsePrivate() :
|
||||
s_play(0),
|
||||
s_rec(0),
|
||||
threadRunning(false),
|
||||
runnable(false) {
|
||||
|
||||
}
|
||||
@@ -102,19 +101,19 @@ airtaudio::DeviceInfo airtaudio::api::Pulse::getDeviceInfo(uint32_t _device) {
|
||||
}
|
||||
|
||||
static void pulseaudio_callback(void* _userData) {
|
||||
etk::log::setThreadName("Pulse IO");
|
||||
airtaudio::api::Pulse* myClass = reinterpret_cast<airtaudio::api::Pulse*>(_userData);
|
||||
myClass->callbackEvent();
|
||||
}
|
||||
|
||||
void airtaudio::api::Pulse::callbackEvent() {
|
||||
while (m_callbackInfo.isRunning == true) {
|
||||
etk::log::setThreadName("Pulse IO-" + m_name);
|
||||
while (m_private->threadRunning == true) {
|
||||
callbackEventOneCycle();
|
||||
}
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Pulse::closeStream() {
|
||||
m_callbackInfo.isRunning = false;
|
||||
m_private->threadRunning = false;
|
||||
m_mutex.lock();
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
m_private->runnable = true;
|
||||
@@ -152,12 +151,13 @@ void airtaudio::api::Pulse::callbackEventOneCycle() {
|
||||
return;
|
||||
}
|
||||
std::chrono::system_clock::time_point streamTime = getStreamTime();
|
||||
enum airtaudio::status status = airtaudio::status_ok;
|
||||
int32_t doStopStream = m_callbackInfo.callback(&m_userBuffer[airtaudio::modeToIdTable(airtaudio::mode_output)][0],
|
||||
&m_userBuffer[airtaudio::modeToIdTable(airtaudio::mode_input)][0],
|
||||
m_bufferSize,
|
||||
streamTime,
|
||||
status);
|
||||
std::vector<enum airtaudio::status> status;
|
||||
int32_t doStopStream = m_callback(&m_userBuffer[airtaudio::modeToIdTable(airtaudio::mode_input)][0],
|
||||
streamTime,
|
||||
&m_userBuffer[airtaudio::modeToIdTable(airtaudio::mode_output)][0],
|
||||
streamTime,
|
||||
m_bufferSize,
|
||||
status);
|
||||
if (doStopStream == 2) {
|
||||
abortStream();
|
||||
return;
|
||||
@@ -396,9 +396,10 @@ bool airtaudio::api::Pulse::probeDeviceOpen(uint32_t _device,
|
||||
}else {
|
||||
m_mode = airtaudio::mode_duplex;
|
||||
}
|
||||
if (!m_callbackInfo.isRunning) {
|
||||
m_callbackInfo.isRunning = true;
|
||||
m_private->thread = new std::thread(pulseaudio_callback, this);
|
||||
if (!m_private->threadRunning) {
|
||||
m_private->threadRunning = true;
|
||||
std::unique_ptr<std::thread> tmpThread(new std::thread(&pulseaudio_callback, this));
|
||||
m_private->thread = std::move(tmpThread);
|
||||
if (m_private->thread == nullptr) {
|
||||
ATA_ERROR("error creating thread.");
|
||||
goto error;
|
||||
|
Reference in New Issue
Block a user