mirror of
https://github.com/badaix/snapcast.git
synced 2025-06-15 17:21:42 +02:00
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:
parent
d5e2446475
commit
1ae573a75f
2 changed files with 42 additions and 8 deletions
|
@ -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());
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue