mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-30 15:30:20 +00:00
Implement file reference update in streaming.
This commit is contained in:
parent
648cd44ddd
commit
c574119718
@ -361,8 +361,8 @@ public:
|
||||
|
||||
AudioMsgId() = default;
|
||||
AudioMsgId(
|
||||
DocumentData *audio,
|
||||
const FullMsgId &msgId,
|
||||
not_null<DocumentData*> 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:
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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<MTPFileHash> &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<LoadedPart> LoaderMtproto::parts() const {
|
||||
return _parts.events();
|
||||
}
|
||||
|
@ -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<MTPFileHash> &hashes);
|
||||
|
||||
[[nodiscard]] QByteArray locationFileReference() const;
|
||||
|
||||
const not_null<ApiWrap*> _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;
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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<PhotoData*> 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<Streamed>(
|
||||
&_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();
|
||||
|
@ -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<HistoryItem*> row, MsgId newId);
|
||||
|
||||
QRect contentRect() const;
|
||||
void contentSizeChanged();
|
||||
|
||||
// Radial animation interface.
|
||||
float64 radialProgress() const;
|
||||
|
Loading…
Reference in New Issue
Block a user