Implement file reference update in streaming.

This commit is contained in:
John Preston 2019-03-01 16:22:47 +04:00
parent 648cd44ddd
commit c574119718
10 changed files with 132 additions and 82 deletions

View File

@ -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:

View File

@ -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;

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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();
}

View File

@ -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;

View File

@ -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(),

View File

@ -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();

View File

@ -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;