From 69ce84c68a9e25dbd7e1970babb93b236ef795a0 Mon Sep 17 00:00:00 2001 From: Maya Posch Date: Thu, 19 Mar 2020 16:57:07 +0100 Subject: [PATCH] Fix issues with seeking routine. --- src/server/NymphCastServer.cpp | 34 +++++++++++++++++++++++++++++----- src/server/ffplay/ffplay.cpp | 25 +++++++++++++++++++------ src/server/ffplay/ffplay.h | 3 +++ 3 files changed, 51 insertions(+), 11 deletions(-) diff --git a/src/server/NymphCastServer.cpp b/src/server/NymphCastServer.cpp index 79b71316..ac89ea73 100644 --- a/src/server/NymphCastServer.cpp +++ b/src/server/NymphCastServer.cpp @@ -275,6 +275,7 @@ void resetDataBuffer() { media_buffer.currentSlot = 0; // The current vector slot we're using. media_buffer.numSlots = 50; // Total number of slots in the data vector. media_buffer.nextSlot = 0; // Next slot to fill in the buffer vector. + media_buffer.buffSlotLow = 0; media_buffer.buffIndexLow = 0; // File index at the buffer front. media_buffer.buffIndexHigh = 0; media_buffer.freeSlots = 50; @@ -284,8 +285,8 @@ void resetDataBuffer() { // If we're in the midst of a seeking operation, we are done here. if (media_buffer.seeking) { // Set high/low indices for the buffer in preparation for new data. - media_buffer.buffIndexLow = media_buffer.seekingPosition.load(); - media_buffer.buffIndexHigh = media_buffer.seekingPosition.load(); + //media_buffer.buffIndexLow = media_buffer.seekingPosition.load(); + //media_buffer.buffIndexHigh = media_buffer.seekingPosition.load(); // Send message to client indicating that we're seeking in the file. std::vector values; @@ -293,11 +294,20 @@ void resetDataBuffer() { std::string result; NymphBoolean* resVal = 0; if (!NymphRemoteClient::callCallback(media_buffer.activeSession, "MediaSeekCallback", values, result)) { - std::cerr << "Calling media stop callback failed: " << result << std::endl; + std::cerr << "Calling media seek callback failed: " << result << std::endl; media_buffer.seeking = false; return; } - media_buffer.seeking = false; + + // Wait for the seeking condition variable to be called or time out. + media_buffer.seekingMutex.lock(); + if (!media_buffer.seekingCondition.tryWait(media_buffer.seekingMutex, 500)) { + // Condition variable wasn't signalled before time-out. Return. + // Signal seeking operation failure by not resetting the 'seeking' boolean condition. + return; + } + + media_buffer.seeking = false; return; } @@ -592,7 +602,7 @@ NymphMessage* connectClient(int session, NymphMessage* msg, void* data) { values.push_back(getPlaybackStatus()); std::string result; NymphBoolean* resVal = 0; - if (!NymphRemoteClient::callCallback(media_buffer.activeSession, "MediaStatusCallback", values, result)) { + if (!NymphRemoteClient::callCallback(session, "MediaStatusCallback", values, result)) { std::cerr << "Calling media status callback failed: " << result << std::endl; } @@ -685,6 +695,11 @@ NymphMessage* session_data(int session, NymphMessage* msg, void* data) { // TODO: if this boolean is false already, dismiss message? media_buffer.requestInFlight = false; + if (media_buffer.seeking) { + // Signal condition variable to indicate seeking operation succeeded. + media_buffer.seekingCondition.signal(); + } + // Get iterator to the session instance for the client. std::map::iterator it; it = clients.find(session); @@ -709,6 +724,14 @@ NymphMessage* session_data(int session, NymphMessage* msg, void* data) { media_buffer.slotBytesLeft = mediaData.length(); } + // Update buffer lower bound slot if necessary. + if (media_buffer.nextSlot == media_buffer.buffSlotLow) { + media_buffer.buffIndexLow += media_buffer.slotSize; + if (!(++media_buffer.buffSlotLow < media_buffer.numSlots)) { + media_buffer.buffSlotLow = 0; + } + } + media_buffer.nextSlot++; if (!(media_buffer.nextSlot < media_buffer.numSlots)) { media_buffer.nextSlot = 0; } @@ -1513,6 +1536,7 @@ int main(int argc, char** argv) { media_buffer.currentSlot = 0; // The current vector slot we're using. media_buffer.numSlots = 50; // Total number of slots in the data vector. media_buffer.nextSlot = 0; // Next slot to fill in the buffer vector. + media_buffer.buffSlotLow = 0; media_buffer.buffIndexLow = 0; // File index at the buffer start (low). media_buffer.buffIndexHigh = 0; // File index at the buffer end (high). media_buffer.freeSlots = 50; diff --git a/src/server/ffplay/ffplay.cpp b/src/server/ffplay/ffplay.cpp index 70ce3015..63594ed5 100644 --- a/src/server/ffplay/ffplay.cpp +++ b/src/server/ffplay/ffplay.cpp @@ -408,7 +408,6 @@ int Ffplay::media_read(void* opaque, uint8_t* buf, int buf_size) { db->currentIndex = 0; db->slotBytesLeft = db->slotSize.load(); db->freeSlots++; // The used buffer slot just became available for more data. - db->buffIndexLow += db->slotSize; } else { db->currentIndex += byteCount; @@ -453,26 +452,40 @@ int Ffplay::media_read(void* opaque, uint8_t* buf, int buf_size) { * * @param opaque A pointer to the user-defined IO data structure. * @param offset The position to seek to. - * @param origin The relative point (origin) from which the seek is performed. + * @param whence . * - * @return The new position in the file. + * @return The new byte position in the file or -1 in case of failure. */ -int64_t Ffplay::media_seek(void* opaque, int64_t offset, int origin) { +int64_t Ffplay::media_seek(void* opaque, int64_t offset, int whence) { + std::cout << "media_seek: offset " << offset << ", origin " << whence << std::endl; + if (whence == AVSEEK_SIZE) { + std::cout << "media_seek: received AVSEEK_SIZE, returning unknown file size." << std::endl; + return -1; // FIXME: we don't know the file handle size. + } + DataBuffer* db = static_cast(opaque); + std::cout << "IdxLow: " << db->buffIndexLow << ", IdxHigh: " << db->buffIndexHigh << std::endl; // Try to find the index in the buffered data. If unavailable, request new data from client. if (offset < db->buffIndexLow || offset > db->buffIndexHigh) { // Reset the buffer and send request to client. db->seeking = true; db->seekingPosition = offset; + std::cout << "Resetting data buffer..." << std::endl; resetDataBuffer(); + if (db->seeking) { + // Seeking operation failed. + std::cerr << "Seeking failed." << std::endl; + return -1; + } + + db->seeking = false; } else { // Set the new position of the index in the appropriate buffer. uint64_t adjusted_offset = offset - db->buffIndexLow; - uint32_t oldSlot = db->currentSlot; uint32_t wholeSlots = adjusted_offset / db->slotSize; - uint32_t newSlot = (adjusted_offset / db->slotSize) + db->currentSlot; + uint32_t newSlot = (adjusted_offset / db->slotSize) + db->buffSlotLow; if ((newSlot + 1) > db->numSlots) { newSlot -= (db->numSlots - 1); } diff --git a/src/server/ffplay/ffplay.h b/src/server/ffplay/ffplay.h index 063f6eb1..d25faf3d 100644 --- a/src/server/ffplay/ffplay.h +++ b/src/server/ffplay/ffplay.h @@ -43,6 +43,7 @@ struct DataBuffer { std::atomic buffBytesLeft; // Number of bytes available for reading in the buffer. std::atomic eof; // Whether End of File for the source file has been reached. + std::atomic buffSlotLow; // Current slot containing the low index. std::atomic buffIndexLow; // File index at the buffer front (low index). std::atomic buffIndexHigh; // File index at the buffer back (high index). Poco::Mutex mutex; @@ -55,6 +56,8 @@ struct DataBuffer { std::atomic requestInFlight; std::atomic seeking; // Are we performing a seeking operation? std::atomic seekingPosition; // Position to seek to. + Poco::Condition seekingCondition; + Poco::Mutex seekingMutex; Poco::Mutex streamTrackQueueMutex; std::queue streamTrackQueue;