diff --git a/Telegram/SourceFiles/data/data_types.h b/Telegram/SourceFiles/data/data_types.h index 4f313c6406..4574299f78 100644 --- a/Telegram/SourceFiles/data/data_types.h +++ b/Telegram/SourceFiles/data/data_types.h @@ -361,8 +361,8 @@ public: AudioMsgId() = default; AudioMsgId( - DocumentData *audio, - const FullMsgId &msgId, + not_null audio, + FullMsgId msgId, uint32 externalPlayId = 0) : _audio(audio) , _contextId(msgId) @@ -373,21 +373,20 @@ public: [[nodiscard]] static uint32 CreateExternalPlayId(); [[nodiscard]] static AudioMsgId ForVideo(); - Type type() const { + [[nodiscard]] Type type() const { return _type; } - DocumentData *audio() const { + [[nodiscard]] DocumentData *audio() const { return _audio; } - FullMsgId contextId() const { + [[nodiscard]] FullMsgId contextId() const { return _contextId; } - uint32 externalPlayId() const { + [[nodiscard]] uint32 externalPlayId() const { return _externalPlayId; } - - explicit operator bool() const { - return _audio != nullptr; + [[nodiscard]] explicit operator bool() const { + return (_audio != nullptr) || (_externalPlayId != 0); } private: diff --git a/Telegram/SourceFiles/history/media/history_media_document.cpp b/Telegram/SourceFiles/history/media/history_media_document.cpp index 9d1eec2555..4d95cf6733 100644 --- a/Telegram/SourceFiles/history/media/history_media_document.cpp +++ b/Telegram/SourceFiles/history/media/history_media_document.cpp @@ -711,11 +711,10 @@ void HistoryDocument::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool const auto type = AudioMsgId::Type::Voice; const auto state = Media::Player::instance()->getState(type); if (state.id == AudioMsgId(_data, _parent->data()->fullId(), state.id.externalPlayId()) && state.length) { - auto currentProgress = voice->seekingCurrent(); - auto currentPosition = state.frequency - ? qRound(currentProgress * state.length * 1000. / state.frequency) - : 0; - Media::Player::mixer()->seek(type, currentPosition); + const auto currentProgress = voice->seekingCurrent(); + Media::Player::instance()->finishSeeking( + AudioMsgId::Type::Voice, + currentProgress); voice->ensurePlayback(this); voice->_playback->_position = 0; diff --git a/Telegram/SourceFiles/media/audio/media_audio.cpp b/Telegram/SourceFiles/media/audio/media_audio.cpp index 319ce04f0d..d53aceee1c 100644 --- a/Telegram/SourceFiles/media/audio/media_audio.cpp +++ b/Telegram/SourceFiles/media/audio/media_audio.cpp @@ -1242,7 +1242,9 @@ void Mixer::setStoppedState(Track *current, State state) { alSourceStop(current->stream.source); alSourcef(current->stream.source, AL_GAIN, 1); } - emit loaderOnCancel(current->state.id); + if (current->state.id) { + emit loaderOnCancel(current->state.id); + } } void Mixer::clearStoppedAtStart(const AudioMsgId &audio) { diff --git a/Telegram/SourceFiles/media/audio/media_audio_loaders.cpp b/Telegram/SourceFiles/media/audio/media_audio_loaders.cpp index 7839ff87b7..c0de29ce49 100644 --- a/Telegram/SourceFiles/media/audio/media_audio_loaders.cpp +++ b/Telegram/SourceFiles/media/audio/media_audio_loaders.cpp @@ -413,6 +413,8 @@ Mixer::Track *Loaders::checkLoader(AudioMsgId::Type type) { } void Loaders::onCancel(const AudioMsgId &audio) { + Expects(audio.type() != AudioMsgId::Type::Unknown); + switch (audio.type()) { case AudioMsgId::Type::Voice: if (_audio == audio) clear(audio.type()); break; case AudioMsgId::Type::Song: if (_song == audio) clear(audio.type()); break; diff --git a/Telegram/SourceFiles/media/player/media_player_instance.cpp b/Telegram/SourceFiles/media/player/media_player_instance.cpp index 226d6c53d5..71ba6b9f75 100644 --- a/Telegram/SourceFiles/media/player/media_player_instance.cpp +++ b/Telegram/SourceFiles/media/player/media_player_instance.cpp @@ -112,10 +112,11 @@ Instance::Instance() Instance::~Instance() = default; AudioMsgId::Type Instance::getActiveType() const { - auto voiceData = getData(AudioMsgId::Type::Voice); + const auto voiceData = getData(AudioMsgId::Type::Voice); if (voiceData->current) { const auto state = getState(voiceData->type); - if (voiceData->current == state.id && !IsStoppedOrStopping(state.state)) { + if (voiceData->current == state.id + && !IsStoppedOrStopping(state.state)) { return voiceData->type; } } @@ -149,11 +150,9 @@ void Instance::setCurrent(const AudioMsgId &audioId) { data->current = audioId; data->isPlaying = false; - auto history = data->history; - auto migrated = data->migrated; - auto item = data->current - ? App::histItemById(data->current.contextId()) - : nullptr; + const auto history = data->history; + const auto migrated = data->migrated; + const auto item = App::histItemById(data->current.contextId()); if (item) { data->history = item->history()->migrateToOrMe(); data->migrated = data->history->migrateFrom(); @@ -333,7 +332,7 @@ void Instance::play(AudioMsgId::Type type) { } else { mixer()->resume(state.id); } - } else if (data->current) { + } else { play(data->current); } data->resumeOnCallEnd = false; @@ -342,7 +341,7 @@ void Instance::play(AudioMsgId::Type type) { void Instance::play(const AudioMsgId &audioId) { const auto document = audioId.audio(); - if (!audioId || !document) { + if (!document) { return; } if (document->isAudioFile()) { @@ -465,9 +464,7 @@ void Instance::playPause(AudioMsgId::Type type) { mixer()->pause(state.id); } } else if (auto data = getData(type)) { - if (data->current) { - play(data->current); - } + play(data->current); } } data->resumeOnCallEnd = false; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.cpp index 4b70c3eb96..3acb29a4cd 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.cpp @@ -99,6 +99,7 @@ void LoaderMtproto::sendNext() { } static auto DcIndex = 0; + const auto reference = locationFileReference(); const auto id = _sender.request(MTPupload_GetFile( _location, MTP_int(offset), @@ -106,7 +107,7 @@ void LoaderMtproto::sendNext() { )).done([=](const MTPupload_File &result) { requestDone(offset, result); }).fail([=](const RPCError &error) { - requestFailed(offset, error); + requestFailed(offset, error, reference); }).toDC( MTP::downloadDcId(_dcId, (++DcIndex) % MTP::kDownloadSessionsCount) ).send(); @@ -138,21 +139,57 @@ void LoaderMtproto::changeCdnParams( const QByteArray &encryptionKey, const QByteArray &encryptionIV, const QVector &hashes) { - // #TODO streaming cdn + // #TODO streaming later cdn + _parts.fire({ LoadedPart::kFailedOffset }); } -void LoaderMtproto::requestFailed(int offset, const RPCError &error) { +void LoaderMtproto::requestFailed( + int offset, + const RPCError &error, + const QByteArray &usedFileReference) { const auto &type = error.type(); - if (error.code() != 400 || !type.startsWith(qstr("FILE_REFERENCE_"))) { + const auto fail = [=] { _parts.fire({ LoadedPart::kFailedOffset }); - return; + }; + if (error.code() != 400 || !type.startsWith(qstr("FILE_REFERENCE_"))) { + return fail(); } const auto callback = [=](const Data::UpdatedFileReferences &updated) { - // #TODO streaming file_reference + _location.match([&](const MTPDinputDocumentFileLocation &location) { + const auto i = updated.data.find(location.vid.v); + if (i == end(updated.data)) { + return fail(); + } + const auto reference = i->second; + if (reference == usedFileReference) { + return fail(); + } else if (reference != location.vfile_reference.v) { + _location = MTP_inputDocumentFileLocation( + MTP_long(location.vid.v), + MTP_long(location.vaccess_hash.v), + MTP_bytes(reference)); + } + if (!_requests.take(offset)) { + // Request with such offset was already cancelled. + return; + } + _requested.add(offset); + sendNext(); + }, [](auto &&) { + Unexpected("Not implemented file location type."); + }); }; _api->refreshFileReference(_origin, crl::guard(this, callback)); } +QByteArray LoaderMtproto::locationFileReference() const { + return _location.match([&](const MTPDinputDocumentFileLocation &data) { + return data.vfile_reference.v; + }, [](auto &&) -> QByteArray { + Unexpected("Not implemented file location type."); + }); +} + rpl::producer LoaderMtproto::parts() const { return _parts.events(); } diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.h b/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.h index 3174b62367..c2a9058d6b 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.h @@ -43,7 +43,10 @@ private: void sendNext(); void requestDone(int offset, const MTPupload_File &result); - void requestFailed(int offset, const RPCError &error); + void requestFailed( + int offset, + const RPCError &error, + const QByteArray &usedFileReference); void changeCdnParams( int offset, MTP::DcId dcId, @@ -52,9 +55,14 @@ private: const QByteArray &encryptionIV, const QVector &hashes); + [[nodiscard]] QByteArray locationFileReference() const; + const not_null _api; const MTP::DcId _dcId = 0; - const MTPInputFileLocation _location; + + // _location can be changed with an updated file_reference. + MTPInputFileLocation _location; + const int _size = 0; const Data::FileOrigin _origin; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp index a5acce8227..3218dd0397 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp @@ -218,7 +218,7 @@ void Player::fileReady(Stream &&video, Stream &&audio) { }; const auto mode = _options.mode; if (audio.codec && (mode == Mode::Audio || mode == Mode::Both)) { - if (_options.audioId) { + if (_options.audioId.audio() != nullptr) { _audioId = AudioMsgId( _options.audioId.audio(), _options.audioId.contextId(), diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index ccc583444a..961ec312ef 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -676,6 +676,39 @@ QRect OverlayWidget::contentRect() const { return { _x, _y, _w, _h }; } +void OverlayWidget::contentSizeChanged() { + _width = _w; + _height = _h; + if (_w > 0 && _h > 0) { + _zoomToScreen = float64(width()) / _w; + if (_h * _zoomToScreen > height()) { + _zoomToScreen = float64(height()) / _h; + } + if (_zoomToScreen >= 1.) { + _zoomToScreen -= 1.; + } else { + _zoomToScreen = 1. - (1. / _zoomToScreen); + } + } else { + _zoomToScreen = 0; + } + if ((_w > width()) || (_h > height()) || _fullScreenVideo) { + _zoom = ZoomToScreenLevel; + if (_zoomToScreen >= 0) { + _w = qRound(_w * (_zoomToScreen + 1)); + _h = qRound(_h * (_zoomToScreen + 1)); + } else { + _w = qRound(_w / (-_zoomToScreen + 1)); + _h = qRound(_h / (-_zoomToScreen + 1)); + } + snapXY(); + } else { + _zoom = 0; + } + _x = (width() - _w) / 2; + _y = (height() - _h) / 2; +} + float64 OverlayWidget::radialProgress() const { if (_doc) { return _doc->progress(); @@ -1645,18 +1678,7 @@ void OverlayWidget::displayPhoto(not_null photo, HistoryItem *item) if (isHidden()) { moveToScreen(); } - if (_w > width()) { - _h = qRound(_h * width() / float64(_w)); - _w = width(); - } - if (_h > height()) { - _w = qRound(_w * height() / float64(_h)); - _h = height(); - } - _x = (width() - _w) / 2; - _y = (height() - _h) / 2; - _width = _w; - _height = _h; + contentSizeChanged(); if (_msgid && item) { _from = item->senderOriginal(); } else { @@ -1798,36 +1820,7 @@ void OverlayWidget::displayDocument(DocumentData *doc, HistoryItem *item) { if (isHidden()) { moveToScreen(); } - _width = _w; - _height = _h; - if (_w > 0 && _h > 0) { - _zoomToScreen = float64(width()) / _w; - if (_h * _zoomToScreen > height()) { - _zoomToScreen = float64(height()) / _h; - } - if (_zoomToScreen >= 1.) { - _zoomToScreen -= 1.; - } else { - _zoomToScreen = 1. - (1. / _zoomToScreen); - } - } else { - _zoomToScreen = 0; - } - if ((_w > width()) || (_h > height()) || _fullScreenVideo) { - _zoom = ZoomToScreenLevel; - if (_zoomToScreen >= 0) { - _w = qRound(_w * (_zoomToScreen + 1)); - _h = qRound(_h * (_zoomToScreen + 1)); - } else { - _w = qRound(_w / (-_zoomToScreen + 1)); - _h = qRound(_h / (-_zoomToScreen + 1)); - } - snapXY(); - } else { - _zoom = 0; - } - _x = (width() - _w) / 2; - _y = (height() - _h) / 2; + contentSizeChanged(); if (_msgid && item) { _from = item->senderOriginal(); } else { @@ -1927,6 +1920,19 @@ void OverlayWidget::initStreamingThumbnail() { _current.setDevicePixelRatio(cRetinaFactor()); } +void OverlayWidget::streamingReady(Streaming::Information &&info) { + _streamed->info = std::move(info); + validateStreamedGoodThumbnail(); + if (videoShown()) { + const auto contentSize = ConvertScale(videoSize()); + _w = contentSize.width(); + _h = contentSize.height(); + contentSizeChanged(); + } + this->update(contentRect()); + playbackWaitingChange(false); +} + void OverlayWidget::createStreamingObjects() { _streamed = std::make_unique( &_doc->owner(), @@ -1978,10 +1984,7 @@ void OverlayWidget::handleStreamingUpdate(Streaming::Update &&update) { using namespace Streaming; update.data.match([&](Information &update) { - _streamed->info = std::move(update); - validateStreamedGoodThumbnail(); - this->update(contentRect()); - playbackWaitingChange(false); + streamingReady(std::move(update)); }, [&](const PreloadedVideo &update) { _streamed->info.video.state.receivedTill = update.till; //updatePlaybackState(); diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index 1a90c76cb6..c9bcd2afd8 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -37,6 +37,7 @@ namespace Player { struct TrackState; } // namespace Player namespace Streaming { +struct Information; struct Update; struct Error; } // namespace Streaming @@ -236,6 +237,7 @@ private: void initStreaming(); void initStreamingThumbnail(); + void streamingReady(Streaming::Information &&info); void createStreamingObjects(); void handleStreamingUpdate(Streaming::Update &&update); void handleStreamingError(Streaming::Error &&error); @@ -249,6 +251,7 @@ private: void changingMsgId(not_null row, MsgId newId); QRect contentRect() const; + void contentSizeChanged(); // Radial animation interface. float64 radialProgress() const;