Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto DJ skip fix lp1941989 #4319

Merged
merged 8 commits into from
Sep 23, 2021
1 change: 1 addition & 0 deletions src/engine/cachingreader/cachingreader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ void CachingReader::newTrack(TrackPointer pTrack) {
m_worker.newTrack(std::move(pTrack));
}

// Called from the engine thread
void CachingReader::process() {
ReaderStatusUpdate update;
while (m_readerStatusUpdateFIFO.read(&update, 1) == 1) {
Expand Down
58 changes: 39 additions & 19 deletions src/engine/cachingreader/cachingreaderworker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ CachingReaderWorker::CachingReaderWorker(
: m_group(group),
m_tag(QString("CachingReaderWorker %1").arg(m_group)),
m_pChunkReadRequestFIFO(pChunkReadRequestFIFO),
m_pReaderStatusFIFO(pReaderStatusFIFO),
m_newTrackAvailable(false),
m_stop(0) {
m_pReaderStatusFIFO(pReaderStatusFIFO) {
}

ReaderStatusUpdate CachingReaderWorker::processReadRequest(
Expand Down Expand Up @@ -80,7 +78,7 @@ void CachingReaderWorker::newTrack(TrackPointer pTrack) {
{
QMutexLocker locker(&m_newTrackMutex);
m_pNewTrack = pTrack;
m_newTrackAvailable = true;
m_newTrackAvailable.storeRelease(1);
}
workReady();
}
Expand All @@ -90,18 +88,24 @@ void CachingReaderWorker::run() {
QThread::currentThread()->setObjectName(QString("CachingReaderWorker %1").arg(++id));

Event::start(m_tag);
while (!atomicLoadAcquire(m_stop)) {
while (!m_stop.loadAcquire()) {
// Request is initialized by reading from FIFO
CachingReaderChunkReadRequest request;
if (m_newTrackAvailable) {
if (m_newTrackAvailable.loadAcquire()) {
TrackPointer pLoadTrack;
{ // locking scope
QMutexLocker locker(&m_newTrackMutex);
pLoadTrack = m_pNewTrack;
m_pNewTrack.reset();
m_newTrackAvailable = false;
m_newTrackAvailable.storeRelease(0);
} // implicitly unlocks the mutex
loadTrack(pLoadTrack);
if (pLoadTrack) {
// in this case the engine is still running with the old track
loadTrack(pLoadTrack);
} else {
// here, the engine is already stopped
unloadTrack();
}
} else if (m_pChunkReadRequestFIFO->read(&request, 1) == 1) {
// Read the requested chunk and send the result
const ReaderStatusUpdate update(processReadRequest(request));
Expand All @@ -114,27 +118,38 @@ void CachingReaderWorker::run() {
}
}

void CachingReaderWorker::loadTrack(const TrackPointer& pTrack) {
// Discard all pending read requests
void CachingReaderWorker::discardAllPendingRequests() {
CachingReaderChunkReadRequest request;
uklotzde marked this conversation as resolved.
Show resolved Hide resolved
while (m_pChunkReadRequestFIFO->read(&request, 1) == 1) {
const auto update = ReaderStatusUpdate::readDiscarded(request.chunk);
m_pReaderStatusFIFO->writeBlocking(&update, 1);
}
}

// Unload the track
m_pAudioSource.reset(); // Close open file handles
void CachingReaderWorker::closeAudioSource() {
discardAllPendingRequests();
// Closes open file handles of the old track.
m_pAudioSource.reset();

if (!pTrack) {
// If no new track is available then we are done
const auto update = ReaderStatusUpdate::trackUnloaded();
m_pReaderStatusFIFO->writeBlocking(&update, 1);
return;
}
// This function has to be called with the engine stopped only
// to avoid collecting new requests for the old track
DEBUG_ASSERT(!m_pChunkReadRequestFIFO->readAvailable());
}

void CachingReaderWorker::unloadTrack() {
closeAudioSource();

// Emit that a new track is loading, stops the current track
const auto update = ReaderStatusUpdate::trackUnloaded();
m_pReaderStatusFIFO->writeBlocking(&update, 1);
}

void CachingReaderWorker::loadTrack(const TrackPointer& pTrack) {
// This emit is directly connected and returns synchronized
// after the engine has been stopped.
emit trackLoading();

closeAudioSource();

const QString trackLocation = pTrack->getLocation();
if (trackLocation.isEmpty() || !pTrack->checkFileExists()) {
kLogger.warning()
Expand Down Expand Up @@ -199,6 +214,11 @@ void CachingReaderWorker::loadTrack(const TrackPointer& pTrack) {
const SINT sampleCount =
CachingReaderChunk::frames2samples(
m_pAudioSource->frameLength());

// The engine must not request any chunks before receiving the
// trackLoaded() signal
DEBUG_ASSERT(!m_pChunkReadRequestFIFO->readAvailable());

emit trackLoaded(
pTrack,
m_pAudioSource->getSignalInfo().getSampleRate(),
Expand Down
14 changes: 12 additions & 2 deletions src/engine/cachingreader/cachingreaderworker.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,20 @@ class CachingReaderWorker : public EngineWorker {
// Queue of Tracks to load, and the corresponding lock. Must acquire the
// lock to touch.
QMutex m_newTrackMutex;
bool m_newTrackAvailable;
QAtomicInt m_newTrackAvailable;
TrackPointer m_pNewTrack;

// Internal method to load a track. Emits trackLoaded when finished.
void discardAllPendingRequests();

/// call to be prepare for new tracks
/// Make sure engine has been stopped before
void closeAudioSource();

/// Internal method to unload a track.
/// does not emit signals
void unloadTrack();

/// Internal method to load a track. Emits trackLoaded when finished.
void loadTrack(const TrackPointer& pTrack);

ReaderStatusUpdate processReadRequest(
Expand Down
3 changes: 1 addition & 2 deletions src/engine/enginebuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ EngineBuffer::EngineBuffer(const QString& group,
m_iSeekPhaseQueued(0),
m_iEnableSyncQueued(SYNC_REQUEST_NONE),
m_iSyncModeQueued(SYNC_INVALID),
m_iTrackLoading(0),
m_bPlayAfterLoading(false),
m_iSampleRate(0),
m_pCrossfadeBuffer(SampleUtil::alloc(MAX_BUFFER_LEN)),
Expand Down Expand Up @@ -1050,7 +1049,7 @@ void EngineBuffer::process(CSAMPLE* pOutput, const int iBufferSize) {
m_pScaleST->setSampleRate(sampleRate);
m_pScaleRB->setSampleRate(sampleRate);

bool bTrackLoading = atomicLoadRelaxed(m_iTrackLoading) != 0;
bool bTrackLoading = m_iTrackLoading.loadAcquire() != 0;
if (!bTrackLoading && m_pause.tryLock()) {
processTrackLocked(pOutput, iBufferSize, m_iSampleRate);
// release the pauselock
Expand Down
1 change: 1 addition & 0 deletions src/library/autodj/autodjprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes,
// loaded into the otherDeck
thisDeck->fadeBeginPos = 1.0;
thisDeck->fadeEndPos = 1.0;
otherDeck->isFromDeck = false;
// Load the next track to otherDeck.
loadNextTrackFromQueue(*otherDeck);
emitAutoDJStateChanged(m_eState);
Expand Down