From 3b369fc98ea5d0d272f82239d2ccd8bc60b6ec8a Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 21 Feb 2019 17:40:09 +0400 Subject: [PATCH] Buffer audio when waiting data in streaming. --- Telegram/SourceFiles/config.h | 1 - Telegram/SourceFiles/data/data_document.cpp | 3 +- .../SourceFiles/media/audio/media_audio.cpp | 15 ++- .../SourceFiles/media/audio/media_audio.h | 1 + .../media/audio/media_audio_capture.cpp | 7 +- .../media/audio/media_audio_loader.h | 9 +- .../media/audio/media_audio_loaders.cpp | 98 ++++++++++++++----- .../media/audio/media_audio_loaders.h | 6 +- .../media/audio/media_child_ffmpeg_loader.cpp | 17 +++- .../media/audio/media_child_ffmpeg_loader.h | 6 +- .../streaming/media_streaming_audio_track.cpp | 10 ++ .../streaming/media_streaming_audio_track.h | 2 + .../media/streaming/media_streaming_common.h | 1 + .../media/streaming/media_streaming_file.cpp | 1 + .../streaming/media_streaming_file_delegate.h | 1 + .../media_streaming_loader_mtproto.cpp | 2 +- .../streaming/media_streaming_player.cpp | 43 +++++++- .../media/streaming/media_streaming_player.h | 8 +- .../streaming/media_streaming_video_track.cpp | 5 +- .../streaming/media_streaming_video_track.h | 1 + 20 files changed, 188 insertions(+), 49 deletions(-) diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index 498040e02..4ec78f7e8 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -48,7 +48,6 @@ enum { AudioVoiceMsgMaxLength = 100 * 60, // 100 minutes AudioVoiceMsgUpdateView = 100, // 100ms AudioVoiceMsgChannels = 2, // stereo - AudioVoiceMsgBufferSize = 256 * 1024, // 256 Kb buffers (1.3 - 3.0 secs) StickerMaxSize = 2048, // 2048x2048 is a max image size for sticker diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index ed44df027..941ee4ce6 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -326,7 +326,8 @@ void StartStreaming( auto options = Media::Streaming::PlaybackOptions(); options.speed = 1.; - options.position = (document->duration() / 2) * crl::time(1000); + //options.syncVideoByAudio = false; + //options.position = (document->duration() / 2) * crl::time(1000); player->init(options); player->updates( ) | rpl::start_with_next_error_done([=](Update &&update) { diff --git a/Telegram/SourceFiles/media/audio/media_audio.cpp b/Telegram/SourceFiles/media/audio/media_audio.cpp index e232ee34a..bee9fef7f 100644 --- a/Telegram/SourceFiles/media/audio/media_audio.cpp +++ b/Telegram/SourceFiles/media/audio/media_audio.cpp @@ -28,13 +28,14 @@ Q_DECLARE_METATYPE(VoiceWaveform); namespace { -QMutex AudioMutex; -ALCdevice *AudioDevice = nullptr; -ALCcontext *AudioContext = nullptr; - constexpr auto kSuppressRatioAll = 0.2; constexpr auto kSuppressRatioSong = 0.05; constexpr auto kPlaybackSpeedMultiplier = 1.7; +constexpr auto kWaveformCounterBufferSize = 256 * 1024; + +QMutex AudioMutex; +ALCdevice *AudioDevice = nullptr; +ALCcontext *AudioContext = nullptr; auto VolumeMultiplierAll = 1.; auto VolumeMultiplierSong = 1.; @@ -823,6 +824,10 @@ void Mixer::feedFromVideo(const VideoSoundPart &part) { _loader->feedFromVideo(part); } +void Mixer::forceToBufferVideo(const AudioMsgId &audioId) { + _loader->forceToBufferVideo(audioId); +} + Mixer::TimeCorrection Mixer::getVideoTimeCorrection( const AudioMsgId &audio) const { Expects(audio.type() == AudioMsgId::Type::Video); @@ -1683,7 +1688,7 @@ public: } QByteArray buffer; - buffer.reserve(AudioVoiceMsgBufferSize); + buffer.reserve(kWaveformCounterBufferSize); int64 countbytes = sampleSize() * samplesCount(); int64 processed = 0; int64 sumbytes = 0; diff --git a/Telegram/SourceFiles/media/audio/media_audio.h b/Telegram/SourceFiles/media/audio/media_audio.h index 8c64090a2..c3602a16e 100644 --- a/Telegram/SourceFiles/media/audio/media_audio.h +++ b/Telegram/SourceFiles/media/audio/media_audio.h @@ -122,6 +122,7 @@ public: // Video player audio stream interface. void feedFromVideo(const VideoSoundPart &part); + void forceToBufferVideo(const AudioMsgId &audioId); struct TimeCorrection { crl::time audioPositionValue = kTimeUnknown; crl::time audioPositionTime = kTimeUnknown; diff --git a/Telegram/SourceFiles/media/audio/media_audio_capture.cpp b/Telegram/SourceFiles/media/audio/media_audio_capture.cpp index 016da578d..844f589a8 100644 --- a/Telegram/SourceFiles/media/audio/media_audio_capture.cpp +++ b/Telegram/SourceFiles/media/audio/media_audio_capture.cpp @@ -22,6 +22,7 @@ namespace { constexpr auto kCaptureFrequency = Player::kDefaultFrequency; constexpr auto kCaptureSkipDuration = crl::time(400); constexpr auto kCaptureFadeInDuration = crl::time(300); +constexpr auto kCaptureBufferSlice = 256 * 1024; Instance *CaptureInstance = nullptr; @@ -323,7 +324,7 @@ void Instance::Inner::onStart() { _timer.start(50); _captured.clear(); - _captured.reserve(AudioVoiceMsgBufferSize); + _captured.reserve(kCaptureBufferSlice); DEBUG_LOG(("Audio Capture: started!")); } @@ -489,8 +490,8 @@ void Instance::Inner::onTimeout() { // Get samples from OpenAL auto s = _captured.size(); auto news = s + static_cast(samples * sizeof(short)); - if (news / AudioVoiceMsgBufferSize > s / AudioVoiceMsgBufferSize) { - _captured.reserve(((news / AudioVoiceMsgBufferSize) + 1) * AudioVoiceMsgBufferSize); + if (news / kCaptureBufferSlice > s / kCaptureBufferSlice) { + _captured.reserve(((news / kCaptureBufferSlice) + 1) * kCaptureBufferSlice); } _captured.resize(news); alcCaptureSamples(d->device, (ALCvoid *)(_captured.data() + s), samples); diff --git a/Telegram/SourceFiles/media/audio/media_audio_loader.h b/Telegram/SourceFiles/media/audio/media_audio_loader.h index 46f05b5d4..075382ccb 100644 --- a/Telegram/SourceFiles/media/audio/media_audio_loader.h +++ b/Telegram/SourceFiles/media/audio/media_audio_loader.h @@ -36,9 +36,16 @@ public: EndOfFile, }; virtual ReadResult readMore(QByteArray &samples, int64 &samplesCount) = 0; - virtual void enqueuePackets(QQueue &packets) { + virtual void enqueuePackets( + QQueue &&packets) { Unexpected("enqueuePackets() call on not ChildFFMpegLoader."); } + virtual void setForceToBuffer(bool force) { + Unexpected("setForceToBuffer() call on not ChildFFMpegLoader."); + } + virtual bool forceToBuffer() const { + return false; + } void saveDecodedSamples(QByteArray *samples, int64 *samplesCount); void takeSavedDecodedSamples(QByteArray *samples, int64 *samplesCount); diff --git a/Telegram/SourceFiles/media/audio/media_audio_loaders.cpp b/Telegram/SourceFiles/media/audio/media_audio_loaders.cpp index 922da09d5..15964a2fc 100644 --- a/Telegram/SourceFiles/media/audio/media_audio_loaders.cpp +++ b/Telegram/SourceFiles/media/audio/media_audio_loaders.cpp @@ -13,8 +13,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Media { namespace Player { +namespace { -Loaders::Loaders(QThread *thread) : _fromVideoNotify([this] { videoSoundAdded(); }) { +constexpr auto kPlaybackBufferSize = 256 * 1024; + +} // namespace + +Loaders::Loaders(QThread *thread) +: _fromVideoNotify([=] { videoSoundAdded(); }) { moveToThread(thread); _fromVideoNotify.moveToThread(thread); connect(thread, SIGNAL(started()), this, SLOT(onInit())); @@ -25,8 +31,22 @@ void Loaders::feedFromVideo(const VideoSoundPart &part) { auto invoke = false; { QMutexLocker lock(&_fromVideoMutex); + invoke = _fromVideoQueues.empty() + && _fromVideoForceToBuffer.empty(); _fromVideoQueues[part.audio].enqueue(FFMpeg::dataWrapFromPacket(*part.packet)); - invoke = true; + } + if (invoke) { + _fromVideoNotify.call(); + } +} + +void Loaders::forceToBufferVideo(const AudioMsgId &audioId) { + auto invoke = false; + { + QMutexLocker lock(&_fromVideoMutex); + invoke = _fromVideoQueues.empty() + && _fromVideoForceToBuffer.empty(); + _fromVideoForceToBuffer.emplace(audioId); } if (invoke) { _fromVideoNotify.call(); @@ -34,36 +54,53 @@ void Loaders::feedFromVideo(const VideoSoundPart &part) { } void Loaders::videoSoundAdded() { - auto waitingAndAdded = false; auto queues = decltype(_fromVideoQueues)(); + auto forces = decltype(_fromVideoForceToBuffer)(); { QMutexLocker lock(&_fromVideoMutex); queues = base::take(_fromVideoQueues); + forces = base::take(_fromVideoForceToBuffer); } - auto tryLoader = [this](auto &audio, auto &loader, auto &it) { - if (audio == it.key() && loader) { - loader->enqueuePackets(it.value()); - if (loader->holdsSavedDecodedSamples()) { - onLoad(audio); + for (const auto &audioId : forces) { + const auto tryLoader = [&](const auto &id, auto &loader) { + if (audioId == id && loader) { + loader->setForceToBuffer(true); + if (loader->holdsSavedDecodedSamples() + && !queues.contains(audioId)) { + loadData(audioId); + } + return true; } - return true; - } - return false; - }; - for (auto i = queues.begin(), e = queues.end(); i != e; ++i) { - if (!tryLoader(_audio, _audioLoader, i) - && !tryLoader(_song, _songLoader, i) - && !tryLoader(_video, _videoLoader, i)) { - for (auto &packetData : i.value()) { + return false; + }; + tryLoader(_audio, _audioLoader) + || tryLoader(_song, _songLoader) + || tryLoader(_video, _videoLoader); + } + for (auto &pair : queues) { + const auto audioId = pair.first; + auto &packets = pair.second; + const auto tryLoader = [&](const auto &id, auto &loader) { + if (id == audioId && loader) { + loader->enqueuePackets(std::move(packets)); + if (loader->holdsSavedDecodedSamples()) { + loadData(audioId); + } + return true; + } + return false; + }; + const auto used = tryLoader(_audio, _audioLoader) + || tryLoader(_song, _songLoader) + || tryLoader(_video, _videoLoader); + if (!used) { + for (auto &packetData : packets) { AVPacket packet; FFMpeg::packetFromDataWrap(packet, packetData); FFMpeg::freePacket(&packet); } } } - if (waitingAndAdded) { - onLoad(_video); - } } Loaders::~Loaders() { @@ -73,8 +110,10 @@ Loaders::~Loaders() { void Loaders::clearFromVideoQueue() { auto queues = base::take(_fromVideoQueues); - for (auto &queue : queues) { - for (auto &packetData : queue) { + for (auto &pair : queues) { + const auto audioId = pair.first; + auto &packets = pair.second; + for (auto &packetData : packets) { AVPacket packet; FFMpeg::packetFromDataWrap(packet, packetData); FFMpeg::freePacket(&packet); @@ -120,7 +159,7 @@ void Loaders::emitError(AudioMsgId::Type type) { } void Loaders::onLoad(const AudioMsgId &audio) { - loadData(audio, crl::time(0)); + loadData(audio); } void Loaders::loadData(AudioMsgId audio, crl::time positionMs) { @@ -144,7 +183,7 @@ void Loaders::loadData(AudioMsgId audio, crl::time positionMs) { if (l->holdsSavedDecodedSamples()) { l->takeSavedDecodedSamples(&samples, &samplesCount); } - while (samples.size() < AudioVoiceMsgBufferSize) { + while (samples.size() < kPlaybackBufferSize) { auto res = l->readMore(samples, samplesCount); using Result = AudioPlayerLoader::ReadResult; if (res == Result::Error) { @@ -166,7 +205,8 @@ void Loaders::loadData(AudioMsgId audio, crl::time positionMs) { } else if (res == Result::Ok) { errAtStart = false; } else if (res == Result::Wait) { - waiting = (samples.size() < AudioVoiceMsgBufferSize); + waiting = (samples.size() < kPlaybackBufferSize) + && !l->forceToBuffer(); if (waiting) { l->saveDecodedSamples(&samples, &samplesCount); } @@ -219,8 +259,16 @@ void Loaders::loadData(AudioMsgId audio, crl::time positionMs) { if (bufferIndex < 0) { // No free buffers, wait. l->saveDecodedSamples(&samples, &samplesCount); return; + } else if (l->forceToBuffer()) { + l->setForceToBuffer(false); } + //LOG(("[%4] PUSHING %1 SAMPLES (%2 BYTES) %3ms" + // ).arg(samplesCount + // ).arg(samples.size() + // ).arg((samplesCount * 1000LL) / track->frequency + // ).arg(crl::now() % 10000, 4, 10, QChar('0'))); + track->bufferSamples[bufferIndex] = samples; track->samplesCount[bufferIndex] = samplesCount; track->bufferedLength += samplesCount; diff --git a/Telegram/SourceFiles/media/audio/media_audio_loaders.h b/Telegram/SourceFiles/media/audio/media_audio_loaders.h index e4aeff7f7..0fe96429e 100644 --- a/Telegram/SourceFiles/media/audio/media_audio_loaders.h +++ b/Telegram/SourceFiles/media/audio/media_audio_loaders.h @@ -22,6 +22,7 @@ class Loaders : public QObject { public: Loaders(QThread *thread); void feedFromVideo(const VideoSoundPart &part); + void forceToBufferVideo(const AudioMsgId &audioId); ~Loaders(); signals: @@ -45,7 +46,8 @@ private: std::unique_ptr _videoLoader; QMutex _fromVideoMutex; - QMap> _fromVideoQueues; + base::flat_map> _fromVideoQueues; + base::flat_set _fromVideoForceToBuffer; SingleQueuedInvokation _fromVideoNotify; void emitError(AudioMsgId::Type type); @@ -58,7 +60,7 @@ private: SetupErrorLoadedFull = 2, SetupNoErrorStarted = 3, }; - void loadData(AudioMsgId audio, crl::time positionMs); + void loadData(AudioMsgId audio, crl::time positionMs = 0); AudioPlayerLoader *setupLoader( const AudioMsgId &audio, SetupError &err, diff --git a/Telegram/SourceFiles/media/audio/media_child_ffmpeg_loader.cpp b/Telegram/SourceFiles/media/audio/media_child_ffmpeg_loader.cpp index 0284fd711..282085e64 100644 --- a/Telegram/SourceFiles/media/audio/media_child_ffmpeg_loader.cpp +++ b/Telegram/SourceFiles/media/audio/media_child_ffmpeg_loader.cpp @@ -111,11 +111,24 @@ AudioPlayerLoader::ReadResult ChildFFMpegLoader::readMore( return ReadResult::Ok; } -void ChildFFMpegLoader::enqueuePackets(QQueue &packets) { - _queue += std::move(packets); +void ChildFFMpegLoader::enqueuePackets( + QQueue &&packets) { + if (_queue.empty()) { + _queue = std::move(packets); + } else { + _queue += std::move(packets); + } packets.clear(); } +void ChildFFMpegLoader::setForceToBuffer(bool force) { + _forceToBuffer = force; +} + +bool ChildFFMpegLoader::forceToBuffer() const { + return _forceToBuffer; +} + ChildFFMpegLoader::~ChildFFMpegLoader() { for (auto &packetData : base::take(_queue)) { AVPacket packet; diff --git a/Telegram/SourceFiles/media/audio/media_child_ffmpeg_loader.h b/Telegram/SourceFiles/media/audio/media_child_ffmpeg_loader.h index c3003ca7d..16a9965dd 100644 --- a/Telegram/SourceFiles/media/audio/media_child_ffmpeg_loader.h +++ b/Telegram/SourceFiles/media/audio/media_child_ffmpeg_loader.h @@ -70,7 +70,10 @@ public: } ReadResult readMore(QByteArray &result, int64 &samplesAdded) override; - void enqueuePackets(QQueue &packets) override; + void enqueuePackets( + QQueue &&packets) override; + void setForceToBuffer(bool force) override; + bool forceToBuffer() const override; bool eofReached() const { return _eofReached; @@ -88,6 +91,7 @@ private: std::unique_ptr _parentData; QQueue _queue; + bool _forceToBuffer = false; bool _eofReached = false; }; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.cpp index 6d2d9cc12..95981ba88 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.cpp @@ -50,6 +50,12 @@ void AudioTrack::process(Packet &&packet) { } } +void AudioTrack::waitForData() { + if (initialized()) { + mixerForceToBuffer(); + } +} + bool AudioTrack::initialized() const { return !_ready; } @@ -115,6 +121,10 @@ void AudioTrack::mixerEnqueue(Packet &&packet) { packet.release(); } +void AudioTrack::mixerForceToBuffer() { + Media::Player::mixer()->forceToBufferVideo(_audioId); +} + void AudioTrack::start(crl::time startTime) { Expects(initialized()); diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.h b/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.h index 8bcbb0eee..784a2f8a5 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.h @@ -39,6 +39,7 @@ public: // Called from the same unspecified thread. void process(Packet &&packet); + void waitForData(); // Called from the main thread. ~AudioTrack(); @@ -50,6 +51,7 @@ private: [[nodiscard]] bool fillStateFromFrame(); void mixerInit(); void mixerEnqueue(Packet &&packet); + void mixerForceToBuffer(); void callReady(); const PlaybackOptions _options; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_common.h b/Telegram/SourceFiles/media/streaming/media_streaming_common.h index e04ff61d5..789080569 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_common.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_common.h @@ -27,6 +27,7 @@ struct PlaybackOptions { Mode mode = Mode::Both; crl::time position = 0; float64 speed = 1.; // Valid values between 0.5 and 2. + bool syncVideoByAudio = true; }; struct TrackState { diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_file.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_file.cpp index 94ddcfd94..bc71b873a 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_file.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_file.cpp @@ -41,6 +41,7 @@ int File::Context::read(bytes::span buffer) { } buffer = buffer.subspan(0, amount); while (!_reader->fill(buffer, _offset, &_semaphore)) { + _delegate->fileWaitingForData(); _semaphore.acquire(); if (_interrupted) { return -1; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_file_delegate.h b/Telegram/SourceFiles/media/streaming/media_streaming_file_delegate.h index a3072a576..8cab74568 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_file_delegate.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_file_delegate.h @@ -17,6 +17,7 @@ class FileDelegate { public: virtual void fileReady(Stream &&video, Stream &&audio) = 0; virtual void fileError() = 0; + virtual void fileWaitingForData() = 0; // Return true if reading and processing more packets is desired. // Return false if sleeping until 'wake()' is called is desired. diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.cpp index cb941510a..8e3445b06 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.cpp @@ -13,7 +13,7 @@ namespace Media { namespace Streaming { namespace { -constexpr auto kMaxConcurrentRequests = 1; // #TODO streaming +constexpr auto kMaxConcurrentRequests = 2; // #TODO streaming } // namespace diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp index d8607e88d..6365f3b96 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp @@ -158,7 +158,6 @@ void Player::trackPlayedTill( void Player::audioReceivedTill(crl::time position) { Expects(_audio != nullptr); - //LOG(("AUDIO TILL: %1").arg(position)); trackReceivedTill(*_audio, _information.audio.state, position); } @@ -171,7 +170,6 @@ void Player::audioPlayedTill(crl::time position) { void Player::videoReceivedTill(crl::time position) { Expects(_video != nullptr); - //LOG(("VIDEO TILL: %1").arg(position)); trackReceivedTill(*_video, _information.video.state, position); } @@ -182,6 +180,8 @@ void Player::videoPlayedTill(crl::time position) { } void Player::fileReady(Stream &&video, Stream &&audio) { + _waitingForData = false; + const auto weak = base::make_weak(&_sessionGuard); const auto ready = [=](const Information & data) { crl::on_main(weak, [=, data = data]() mutable { @@ -226,12 +226,32 @@ void Player::fileReady(Stream &&video, Stream &&audio) { } void Player::fileError() { + _waitingForData = false; + crl::on_main(&_sessionGuard, [=] { fail(); }); } +void Player::fileWaitingForData() { + if (_waitingForData) { + return; + } + _waitingForData = true; + crl::on_main(&_sessionGuard, [=] { + _updates.fire({ WaitingForData() }); + }); + if (_audio) { + _audio->waitForData(); + } + if (_video) { + _video->waitForData(); + } +} + bool Player::fileProcessPacket(Packet &&packet) { + _waitingForData = false; + const auto &native = packet.fields(); const auto index = native.stream_index; if (packet.empty()) { @@ -250,12 +270,20 @@ bool Player::fileProcessPacket(Packet &&packet) { } } else if (_audio && _audio->streamIndex() == native.stream_index) { const auto time = PacketPosition(packet, _audio->streamTimeBase()); + //LOG(("[%2] AUDIO PACKET FOR %1ms" + // ).arg(time + // ).arg(crl::now() % 10000, 4, 10, QChar('0'))); + crl::on_main(&_sessionGuard, [=] { audioReceivedTill(time); }); _audio->process(std::move(packet)); } else if (_video && _video->streamIndex() == native.stream_index) { const auto time = PacketPosition(packet, _video->streamTimeBase()); + //LOG(("[%2] VIDEO PACKET FOR %1ms" + // ).arg(time + // ).arg(crl::now() % 10000, 4, 10, QChar('0'))); + crl::on_main(&_sessionGuard, [=] { videoReceivedTill(time); }); @@ -368,7 +396,16 @@ rpl::lifetime &Player::lifetime() { return _lifetime; } -Player::~Player() = default; +Player::~Player() { + // The order of field destruction is important. + // + // We are forced to maintain the correct order in the stop() method, + // because it can be called even before the player destruction. + // + // So instead of maintaining it in the class definition as well we + // simply call stop() here, after that the destruction is trivial. + stop(); +} } // namespace Streaming } // namespace Media diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_player.h b/Telegram/SourceFiles/media/streaming/media_streaming_player.h index a3ab28b72..e9b748939 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_player.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_player.h @@ -52,6 +52,9 @@ public: ~Player(); private: + static constexpr auto kReceivedTillEnd + = std::numeric_limits::max(); + enum class Stage { Uninitialized, Initializing, @@ -66,6 +69,7 @@ private: // FileDelegate methods are called only from the File thread. void fileReady(Stream &&video, Stream &&audio) override; void fileError() override; + void fileWaitingForData() override; bool fileProcessPacket(Packet &&packet) override; bool fileReadMore() override; @@ -95,9 +99,6 @@ private: const std::unique_ptr _file; - static constexpr auto kReceivedTillEnd - = std::numeric_limits::max(); - // Immutable while File is active after it is ready. AudioMsgId _audioId; std::unique_ptr _audio; @@ -109,6 +110,7 @@ private: // Belongs to the File thread while File is active. bool _readTillEnd = false; + bool _waitingForData = false; // Belongs to the main thread. Information _information; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp index 7736edd5a..85baf550b 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp @@ -277,7 +277,7 @@ VideoTrackObject::TrackTime VideoTrackObject::trackTime() const { return result; } - const auto correction = _audioId.playId() + const auto correction = (_options.syncVideoByAudio && _audioId.playId()) ? Media::Player::mixer()->getVideoTimeCorrection(_audioId) : Media::Player::Mixer::TimeCorrection(); const auto knownValue = correction @@ -478,6 +478,9 @@ void VideoTrack::process(Packet &&packet) { }); } +void VideoTrack::waitForData() { +} + void VideoTrack::start(crl::time startTime) { _wrapped.with([=](Implementation &unwrapped) { unwrapped.start(startTime); diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.h b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.h index 01555de73..1beba8b18 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.h @@ -33,6 +33,7 @@ public: // Called from the same unspecified thread. void process(Packet &&packet); + void waitForData(); // Called from the main thread. void start(crl::time startTime);