mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-01-10 16:59:55 +00:00
Allow stopping audio without stopping video.
This commit is contained in:
parent
a2b6e05cdf
commit
40d4353d05
@ -394,6 +394,7 @@ void Instance::playStreamed(
|
||||
data->streamed = std::make_unique<Streamed>(
|
||||
audioId,
|
||||
std::move(shared));
|
||||
data->streamed->instance.lockPlayer();
|
||||
|
||||
data->streamed->instance.player().updates(
|
||||
) | rpl::start_with_next_error([=](Streaming::Update &&update) {
|
||||
|
@ -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<crl::time> AudioTrack::playPosition() {
|
||||
}
|
||||
|
||||
AudioTrack::~AudioTrack() {
|
||||
if (_audioId.externalPlayId()) {
|
||||
Media::Player::mixer()->stop(_audioId);
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
} // namespace Streaming
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -36,6 +36,8 @@ public:
|
||||
Fn<void()> 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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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<Streamed>(
|
||||
_doc,
|
||||
fileOrigin(),
|
||||
this,
|
||||
static_cast<PlaybackControls::Delegate*>(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 {
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user