Fixing a re-sync issue on macOS by reworking CoreAudioPlayer to behave closer to AlsaPlayer: after 5 seconds of no chunks, the AudioQueue is destroyed. On a new chunk, the AudioQueue is re-created.

This commit is contained in:
Tommy Goode 2017-02-25 18:52:21 -06:00
parent d5e2446475
commit 1ae573a75f
2 changed files with 42 additions and 8 deletions

View file

@ -31,7 +31,7 @@ void callback(void *custom_data, AudioQueueRef queue, AudioQueueBufferRef buffer
} }
CoreAudioPlayer::CoreAudioPlayer(const PcmDevice& pcmDevice, std::shared_ptr<Stream> stream) : CoreAudioPlayer::CoreAudioPlayer(const PcmDevice& pcmDevice, std::shared_ptr<Stream> stream) :
Player(pcmDevice, stream), Player(pcmDevice, stream),
ms_(100), ms_(100),
pubStream_(stream) pubStream_(stream)
@ -61,27 +61,52 @@ void CoreAudioPlayer::playerCallback(AudioQueueRef queue, AudioQueueBufferRef bu
char *buffer = (char*)bufferRef->mAudioData; char *buffer = (char*)bufferRef->mAudioData;
if (!pubStream_->getPlayerChunk(buffer, delay, frames_)) if (!pubStream_->getPlayerChunk(buffer, delay, frames_))
{ {
if (chronos::getTickCount() - lastChunkTick > 5000)
{
logO << "No chunk received for 5000ms. Closing Audio Queue.\n";
uninitAudioQueue(queue);
return;
}
// logO << "Failed to get chunk. Playing silence.\n"; // logO << "Failed to get chunk. Playing silence.\n";
memset(buffer, 0, buff_size_); memset(buffer, 0, buff_size_);
} }
else else
{ {
lastChunkTick = chronos::getTickCount();
adjustVolume(buffer, frames_); adjustVolume(buffer, frames_);
} }
// OSStatus status = // OSStatus status =
AudioQueueEnqueueBuffer(queue, bufferRef, 0, NULL); AudioQueueEnqueueBuffer(queue, bufferRef, 0, NULL);
if (!active_) if (!active_)
{ {
AudioQueueStop(queue, false); uninitAudioQueue(queue);
AudioQueueDispose(queue, false);
CFRunLoopStop(CFRunLoopGetCurrent());
} }
} }
void CoreAudioPlayer::worker() void CoreAudioPlayer::worker()
{
while (active_)
{
if (pubStream_->waitForChunk(100))
{
try
{
initAudioQueue();
}
catch (const std::exception& e)
{
logE << "Exception in worker: " << e.what() << "\n";
chronos::sleep(100);
}
}
chronos::sleep(100);
}
}
void CoreAudioPlayer::initAudioQueue()
{ {
const SampleFormat& sampleFormat = pubStream_->getFormat(); const SampleFormat& sampleFormat = pubStream_->getFormat();
@ -99,7 +124,7 @@ void CoreAudioPlayer::worker()
AudioQueueRef queue; AudioQueueRef queue;
AudioQueueNewOutput(&format, callback, this, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &queue); AudioQueueNewOutput(&format, callback, this, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &queue);
AudioQueueCreateTimeline(queue, &timeLine_); AudioQueueCreateTimeline(queue, &timeLine_);
// Apple recommends this as buffer size: // Apple recommends this as buffer size:
// https://developer.apple.com/library/content/documentation/MusicAudio/Conceptual/CoreAudioOverview/CoreAudioEssentials/CoreAudioEssentials.html // https://developer.apple.com/library/content/documentation/MusicAudio/Conceptual/CoreAudioOverview/CoreAudioEssentials/CoreAudioEssentials.html
// static const int maxBufferSize = 0x10000; // limit maximum size to 64K // static const int maxBufferSize = 0x10000; // limit maximum size to 64K
@ -111,7 +136,7 @@ void CoreAudioPlayer::worker()
ms_ = frames_ * 1000 / sampleFormat.rate; ms_ = frames_ * 1000 / sampleFormat.rate;
buff_size_ = frames_ * sampleFormat.frameSize; buff_size_ = frames_ * sampleFormat.frameSize;
logO << "frames: " << frames_ << ", ms: " << ms_ << ", buffer size: " << buff_size_ << "\n"; logO << "frames: " << frames_ << ", ms: " << ms_ << ", buffer size: " << buff_size_ << "\n";
AudioQueueBufferRef buffers[NUM_BUFFERS]; AudioQueueBufferRef buffers[NUM_BUFFERS];
for (int i = 0; i < NUM_BUFFERS; i++) for (int i = 0; i < NUM_BUFFERS; i++)
{ {
@ -126,4 +151,10 @@ void CoreAudioPlayer::worker()
CFRunLoopRun(); CFRunLoopRun();
} }
void CoreAudioPlayer::uninitAudioQueue(AudioQueueRef queue)
{
AudioQueueStop(queue, false);
AudioQueueDispose(queue, false);
pubStream_->clearChunks();
CFRunLoopStop(CFRunLoopGetCurrent());
}

View file

@ -44,12 +44,15 @@ public:
protected: protected:
virtual void worker(); virtual void worker();
void initAudioQueue();
void uninitAudioQueue(AudioQueueRef queue);
AudioQueueTimelineRef timeLine_; AudioQueueTimelineRef timeLine_;
size_t ms_; size_t ms_;
size_t frames_; size_t frames_;
size_t buff_size_; size_t buff_size_;
std::shared_ptr<Stream> pubStream_; std::shared_ptr<Stream> pubStream_;
long lastChunkTick;
}; };