diff --git a/Telegram/SourceFiles/media/player/media_player_instance.cpp b/Telegram/SourceFiles/media/player/media_player_instance.cpp index c5eb1a74be..0ca7a99ac0 100644 --- a/Telegram/SourceFiles/media/player/media_player_instance.cpp +++ b/Telegram/SourceFiles/media/player/media_player_instance.cpp @@ -394,6 +394,7 @@ void Instance::playStreamed( data->streamed = std::make_unique( audioId, std::move(shared)); + data->streamed->instance.lockPlayer(); data->streamed->instance.player().updates( ) | rpl::start_with_next_error([=](Streaming::Update &&update) { diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.cpp index ce490ad8b4..00f21d856e 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.cpp @@ -171,6 +171,14 @@ void AudioTrack::resume(crl::time time) { Media::Player::mixer()->resume(_audioId, true); } +void AudioTrack::stop() { + Expects(initialized()); + + if (_audioId.externalPlayId()) { + Media::Player::mixer()->stop(_audioId); + } +} + void AudioTrack::setSpeed(float64 speed) { _options.speed = speed; Media::Player::mixer()->setSpeedFromExternal(_audioId, speed); @@ -228,9 +236,7 @@ rpl::producer AudioTrack::playPosition() { } AudioTrack::~AudioTrack() { - if (_audioId.externalPlayId()) { - Media::Player::mixer()->stop(_audioId); - } + stop(); } } // namespace Streaming diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.h b/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.h index bb6f75b736..5d05c58b2c 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.h @@ -28,6 +28,9 @@ public: void pause(crl::time time); void resume(crl::time time); + // Allow to irreversibly stop only audio track. + void stop(); + // Called from the main thread. void setSpeed(float64 speed); [[nodiscard]] rpl::producer<> waitingForData() const; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_instance.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_instance.cpp index d51a4eb4ca..92848a9c1a 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_instance.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_instance.cpp @@ -41,6 +41,10 @@ Instance::~Instance() { } } +bool Instance::valid() const { + return (_shared != nullptr); +} + const Player &Instance::player() const { Expects(_shared != nullptr); @@ -77,6 +81,12 @@ void Instance::stop() { _shared->player().stop(); } +void Instance::stopAudio() { + Expects(_shared != nullptr); + + _shared->player().stopAudio(); +} + void Instance::saveFrameToCover() { Expects(_shared != nullptr); diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_instance.h b/Telegram/SourceFiles/media/streaming/media_streaming_instance.h index 2948c41b1d..a52f6ba3be 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_instance.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_instance.h @@ -36,6 +36,8 @@ public: Fn waitingCallback); ~Instance(); + [[nodiscard]] bool valid() const; + [[nodiscard]] const Player &player() const; [[nodiscard]] const Information &info() const; @@ -43,6 +45,7 @@ public: void pause(); void resume(); void stop(); + void stopAudio(); void saveFrameToCover(); [[nodiscard]] bool active() const; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp index 19bf593f0c..9f42666a38 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp @@ -578,6 +578,15 @@ void Player::stop() { stop(false); } +void Player::stopAudio() { + if (!_video) { + stop(); + } else if (_audio) { + _audioFinished = true; + _audio->stop(); + } +} + void Player::updatePausedState() { const auto paused = _pausedByUser || _pausedByWaitingForData; if (_paused == paused) { @@ -666,7 +675,7 @@ void Player::start() { _updates.fire({ WaitingForData{ true } }); }, _sessionLifetime); - if (guard && _audio) { + if (guard && _audio && !_audioFinished) { _audio->playPosition( ) | rpl::start_with_next_done([=](crl::time position) { audioPlayedTill(position); @@ -701,7 +710,13 @@ void Player::start() { }, _sessionLifetime); } if (guard && _audio) { - trackSendReceivedTill(*_audio, _information.audio.state); + if (_audioFinished) { + if (!_video || _videoFinished) { + _updates.fire({ Finished() }); + } + } else { + trackSendReceivedTill(*_audio, _information.audio.state); + } } if (guard && _video) { trackSendReceivedTill(*_video, _information.video.state); diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_player.h b/Telegram/SourceFiles/media/streaming/media_streaming_player.h index fb40322b2d..6ba43e44c9 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_player.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_player.h @@ -45,6 +45,9 @@ public: void resume(); void stop(); + // Allow to irreversibly stop only audio track. + void stopAudio(); + [[nodiscard]] bool active() const; [[nodiscard]] bool ready() const; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index b1011aaf4f..dd47feb248 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -435,8 +435,7 @@ bool OverlayWidget::documentBubbleShown() const { void OverlayWidget::clearStreaming() { _fullScreenVideo = false; if (_streamed) { - _streamed->instance.stop(); - _streamed->instance.unlockPlayer(); + _streamed->instance.stopAudio(); _streamed = nullptr; } } @@ -1860,8 +1859,7 @@ void OverlayWidget::displayDocument( } else { _doc->automaticLoad(fileOrigin(), item); - if (_doc->canBePlayed()) { - initStreaming(); + if (_doc->canBePlayed() && initStreaming()) { } else if (_doc->isVideoFile()) { initStreamingThumbnail(); } else if (_doc->isTheme()) { @@ -1988,15 +1986,18 @@ void OverlayWidget::displayFinished() { } } -void OverlayWidget::initStreaming() { +bool OverlayWidget::initStreaming() { Expects(_doc != nullptr); Expects(_doc->canBePlayed()); if (_streamed) { - return; + return true; } initStreamingThumbnail(); - createStreamingObjects(); + if (!createStreamingObjects()) { + _doc->setInappPlaybackFailed(); + return false; + } Core::App().updateNonIdle(); @@ -2008,6 +2009,7 @@ void OverlayWidget::initStreaming() { }, _streamed->instance.lifetime()); startStreamingPlayer(); + return true; } void OverlayWidget::startStreamingPlayer() { @@ -2071,13 +2073,17 @@ void OverlayWidget::streamingReady(Streaming::Information &&info) { this->update(contentRect()); } -void OverlayWidget::createStreamingObjects() { +bool OverlayWidget::createStreamingObjects() { _streamed = std::make_unique( _doc, fileOrigin(), this, static_cast(this), [=] { waitingAnimationCallback(); }); + if (!_streamed->instance.valid()) { + _streamed = nullptr; + return false; + } _streamed->instance.lockPlayer(); _streamed->withSound = _doc->isAudioFile() || _doc->isVideoFile() @@ -2090,6 +2096,7 @@ void OverlayWidget::createStreamingObjects() { refreshClipControllerGeometry(); _streamed->controls.show(); } + return true; } QImage OverlayWidget::transformVideoFrame(QImage frame) const { @@ -2281,7 +2288,9 @@ void OverlayWidget::playbackPauseResume() { _streamed->resumeOnCallEnd = false; if (_streamed->instance.player().failed()) { clearStreaming(); - initStreaming(); + if (!_doc->canBePlayed() || !initStreaming()) { + redisplayContent(); + } } else if (_streamed->instance.player().finished()) { _streamingStartPaused = false; restartAtSeekPosition(0); @@ -2516,7 +2525,7 @@ void OverlayWidget::paintEvent(QPaintEvent *e) { } float64 progress = (hidingDt >= 0) ? (hidingDt / st::mediaviewSaveMsgHiding) : (dt / st::mediaviewSaveMsgShowing); _saveMsgOpacity.update(qMin(progress, 1.), anim::linear); - if (_saveMsgOpacity.current() > 0) { + if (_saveMsgOpacity.current() > 0) { p.setOpacity(_saveMsgOpacity.current()); App::roundRect(p, _saveMsg, st::mediaviewSaveMsgBg, MediaviewSaveCorners); st::mediaviewSaveMsgCheck.paint(p, _saveMsg.topLeft() + st::mediaviewSaveMsgCheckPos, width()); @@ -2528,7 +2537,7 @@ void OverlayWidget::paintEvent(QPaintEvent *e) { p.setOpacity(1); } if (!_blurred) { - auto nextFrame = (dt < st::mediaviewSaveMsgShowing || hidingDt >= 0) ? int(AnimationTimerDelta) : (st::mediaviewSaveMsgShowing + st::mediaviewSaveMsgShown + 1 - dt); + auto nextFrame = (dt < st::mediaviewSaveMsgShowing || hidingDt >= 0) ? int(AnimationTimerDelta) : (st::mediaviewSaveMsgShowing + st::mediaviewSaveMsgShown + 1 - dt); _saveMsgUpdater.start(nextFrame); } } else { diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index a12138a0e3..2f77371514 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -258,11 +258,11 @@ private: void refreshClipControllerGeometry(); void refreshCaptionGeometry(); - void initStreaming(); + [[nodiscard]] bool initStreaming(); void startStreamingPlayer(); void initStreamingThumbnail(); void streamingReady(Streaming::Information &&info); - void createStreamingObjects(); + [[nodiscard]] bool createStreamingObjects(); void handleStreamingUpdate(Streaming::Update &&update); void handleStreamingError(Streaming::Error &&error);