Allow stopping audio without stopping video.

This commit is contained in:
John Preston 2019-12-18 21:26:17 +03:00
parent a2b6e05cdf
commit 40d4353d05
9 changed files with 68 additions and 18 deletions

View File

@ -394,6 +394,7 @@ void Instance::playStreamed(
data->streamed = std::make_unique<Streamed>( data->streamed = std::make_unique<Streamed>(
audioId, audioId,
std::move(shared)); std::move(shared));
data->streamed->instance.lockPlayer();
data->streamed->instance.player().updates( data->streamed->instance.player().updates(
) | rpl::start_with_next_error([=](Streaming::Update &&update) { ) | rpl::start_with_next_error([=](Streaming::Update &&update) {

View File

@ -171,6 +171,14 @@ void AudioTrack::resume(crl::time time) {
Media::Player::mixer()->resume(_audioId, true); Media::Player::mixer()->resume(_audioId, true);
} }
void AudioTrack::stop() {
Expects(initialized());
if (_audioId.externalPlayId()) {
Media::Player::mixer()->stop(_audioId);
}
}
void AudioTrack::setSpeed(float64 speed) { void AudioTrack::setSpeed(float64 speed) {
_options.speed = speed; _options.speed = speed;
Media::Player::mixer()->setSpeedFromExternal(_audioId, speed); Media::Player::mixer()->setSpeedFromExternal(_audioId, speed);
@ -228,9 +236,7 @@ rpl::producer<crl::time> AudioTrack::playPosition() {
} }
AudioTrack::~AudioTrack() { AudioTrack::~AudioTrack() {
if (_audioId.externalPlayId()) { stop();
Media::Player::mixer()->stop(_audioId);
}
} }
} // namespace Streaming } // namespace Streaming

View File

@ -28,6 +28,9 @@ public:
void pause(crl::time time); void pause(crl::time time);
void resume(crl::time time); void resume(crl::time time);
// Allow to irreversibly stop only audio track.
void stop();
// Called from the main thread. // Called from the main thread.
void setSpeed(float64 speed); void setSpeed(float64 speed);
[[nodiscard]] rpl::producer<> waitingForData() const; [[nodiscard]] rpl::producer<> waitingForData() const;

View File

@ -41,6 +41,10 @@ Instance::~Instance() {
} }
} }
bool Instance::valid() const {
return (_shared != nullptr);
}
const Player &Instance::player() const { const Player &Instance::player() const {
Expects(_shared != nullptr); Expects(_shared != nullptr);
@ -77,6 +81,12 @@ void Instance::stop() {
_shared->player().stop(); _shared->player().stop();
} }
void Instance::stopAudio() {
Expects(_shared != nullptr);
_shared->player().stopAudio();
}
void Instance::saveFrameToCover() { void Instance::saveFrameToCover() {
Expects(_shared != nullptr); Expects(_shared != nullptr);

View File

@ -36,6 +36,8 @@ public:
Fn<void()> waitingCallback); Fn<void()> waitingCallback);
~Instance(); ~Instance();
[[nodiscard]] bool valid() const;
[[nodiscard]] const Player &player() const; [[nodiscard]] const Player &player() const;
[[nodiscard]] const Information &info() const; [[nodiscard]] const Information &info() const;
@ -43,6 +45,7 @@ public:
void pause(); void pause();
void resume(); void resume();
void stop(); void stop();
void stopAudio();
void saveFrameToCover(); void saveFrameToCover();
[[nodiscard]] bool active() const; [[nodiscard]] bool active() const;

View File

@ -578,6 +578,15 @@ void Player::stop() {
stop(false); stop(false);
} }
void Player::stopAudio() {
if (!_video) {
stop();
} else if (_audio) {
_audioFinished = true;
_audio->stop();
}
}
void Player::updatePausedState() { void Player::updatePausedState() {
const auto paused = _pausedByUser || _pausedByWaitingForData; const auto paused = _pausedByUser || _pausedByWaitingForData;
if (_paused == paused) { if (_paused == paused) {
@ -666,7 +675,7 @@ void Player::start() {
_updates.fire({ WaitingForData{ true } }); _updates.fire({ WaitingForData{ true } });
}, _sessionLifetime); }, _sessionLifetime);
if (guard && _audio) { if (guard && _audio && !_audioFinished) {
_audio->playPosition( _audio->playPosition(
) | rpl::start_with_next_done([=](crl::time position) { ) | rpl::start_with_next_done([=](crl::time position) {
audioPlayedTill(position); audioPlayedTill(position);
@ -701,7 +710,13 @@ void Player::start() {
}, _sessionLifetime); }, _sessionLifetime);
} }
if (guard && _audio) { 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) { if (guard && _video) {
trackSendReceivedTill(*_video, _information.video.state); trackSendReceivedTill(*_video, _information.video.state);

View File

@ -45,6 +45,9 @@ public:
void resume(); void resume();
void stop(); void stop();
// Allow to irreversibly stop only audio track.
void stopAudio();
[[nodiscard]] bool active() const; [[nodiscard]] bool active() const;
[[nodiscard]] bool ready() const; [[nodiscard]] bool ready() const;

View File

@ -435,8 +435,7 @@ bool OverlayWidget::documentBubbleShown() const {
void OverlayWidget::clearStreaming() { void OverlayWidget::clearStreaming() {
_fullScreenVideo = false; _fullScreenVideo = false;
if (_streamed) { if (_streamed) {
_streamed->instance.stop(); _streamed->instance.stopAudio();
_streamed->instance.unlockPlayer();
_streamed = nullptr; _streamed = nullptr;
} }
} }
@ -1860,8 +1859,7 @@ void OverlayWidget::displayDocument(
} else { } else {
_doc->automaticLoad(fileOrigin(), item); _doc->automaticLoad(fileOrigin(), item);
if (_doc->canBePlayed()) { if (_doc->canBePlayed() && initStreaming()) {
initStreaming();
} else if (_doc->isVideoFile()) { } else if (_doc->isVideoFile()) {
initStreamingThumbnail(); initStreamingThumbnail();
} else if (_doc->isTheme()) { } else if (_doc->isTheme()) {
@ -1988,15 +1986,18 @@ void OverlayWidget::displayFinished() {
} }
} }
void OverlayWidget::initStreaming() { bool OverlayWidget::initStreaming() {
Expects(_doc != nullptr); Expects(_doc != nullptr);
Expects(_doc->canBePlayed()); Expects(_doc->canBePlayed());
if (_streamed) { if (_streamed) {
return; return true;
} }
initStreamingThumbnail(); initStreamingThumbnail();
createStreamingObjects(); if (!createStreamingObjects()) {
_doc->setInappPlaybackFailed();
return false;
}
Core::App().updateNonIdle(); Core::App().updateNonIdle();
@ -2008,6 +2009,7 @@ void OverlayWidget::initStreaming() {
}, _streamed->instance.lifetime()); }, _streamed->instance.lifetime());
startStreamingPlayer(); startStreamingPlayer();
return true;
} }
void OverlayWidget::startStreamingPlayer() { void OverlayWidget::startStreamingPlayer() {
@ -2071,13 +2073,17 @@ void OverlayWidget::streamingReady(Streaming::Information &&info) {
this->update(contentRect()); this->update(contentRect());
} }
void OverlayWidget::createStreamingObjects() { bool OverlayWidget::createStreamingObjects() {
_streamed = std::make_unique<Streamed>( _streamed = std::make_unique<Streamed>(
_doc, _doc,
fileOrigin(), fileOrigin(),
this, this,
static_cast<PlaybackControls::Delegate*>(this), static_cast<PlaybackControls::Delegate*>(this),
[=] { waitingAnimationCallback(); }); [=] { waitingAnimationCallback(); });
if (!_streamed->instance.valid()) {
_streamed = nullptr;
return false;
}
_streamed->instance.lockPlayer(); _streamed->instance.lockPlayer();
_streamed->withSound = _doc->isAudioFile() _streamed->withSound = _doc->isAudioFile()
|| _doc->isVideoFile() || _doc->isVideoFile()
@ -2090,6 +2096,7 @@ void OverlayWidget::createStreamingObjects() {
refreshClipControllerGeometry(); refreshClipControllerGeometry();
_streamed->controls.show(); _streamed->controls.show();
} }
return true;
} }
QImage OverlayWidget::transformVideoFrame(QImage frame) const { QImage OverlayWidget::transformVideoFrame(QImage frame) const {
@ -2281,7 +2288,9 @@ void OverlayWidget::playbackPauseResume() {
_streamed->resumeOnCallEnd = false; _streamed->resumeOnCallEnd = false;
if (_streamed->instance.player().failed()) { if (_streamed->instance.player().failed()) {
clearStreaming(); clearStreaming();
initStreaming(); if (!_doc->canBePlayed() || !initStreaming()) {
redisplayContent();
}
} else if (_streamed->instance.player().finished()) { } else if (_streamed->instance.player().finished()) {
_streamingStartPaused = false; _streamingStartPaused = false;
restartAtSeekPosition(0); restartAtSeekPosition(0);
@ -2516,7 +2525,7 @@ void OverlayWidget::paintEvent(QPaintEvent *e) {
} }
float64 progress = (hidingDt >= 0) ? (hidingDt / st::mediaviewSaveMsgHiding) : (dt / st::mediaviewSaveMsgShowing); float64 progress = (hidingDt >= 0) ? (hidingDt / st::mediaviewSaveMsgHiding) : (dt / st::mediaviewSaveMsgShowing);
_saveMsgOpacity.update(qMin(progress, 1.), anim::linear); _saveMsgOpacity.update(qMin(progress, 1.), anim::linear);
if (_saveMsgOpacity.current() > 0) { if (_saveMsgOpacity.current() > 0) {
p.setOpacity(_saveMsgOpacity.current()); p.setOpacity(_saveMsgOpacity.current());
App::roundRect(p, _saveMsg, st::mediaviewSaveMsgBg, MediaviewSaveCorners); App::roundRect(p, _saveMsg, st::mediaviewSaveMsgBg, MediaviewSaveCorners);
st::mediaviewSaveMsgCheck.paint(p, _saveMsg.topLeft() + st::mediaviewSaveMsgCheckPos, width()); st::mediaviewSaveMsgCheck.paint(p, _saveMsg.topLeft() + st::mediaviewSaveMsgCheckPos, width());
@ -2528,7 +2537,7 @@ void OverlayWidget::paintEvent(QPaintEvent *e) {
p.setOpacity(1); p.setOpacity(1);
} }
if (!_blurred) { 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); _saveMsgUpdater.start(nextFrame);
} }
} else { } else {

View File

@ -258,11 +258,11 @@ private:
void refreshClipControllerGeometry(); void refreshClipControllerGeometry();
void refreshCaptionGeometry(); void refreshCaptionGeometry();
void initStreaming(); [[nodiscard]] bool initStreaming();
void startStreamingPlayer(); void startStreamingPlayer();
void initStreamingThumbnail(); void initStreamingThumbnail();
void streamingReady(Streaming::Information &&info); void streamingReady(Streaming::Information &&info);
void createStreamingObjects(); [[nodiscard]] bool createStreamingObjects();
void handleStreamingUpdate(Streaming::Update &&update); void handleStreamingUpdate(Streaming::Update &&update);
void handleStreamingError(Streaming::Error &&error); void handleStreamingError(Streaming::Error &&error);