Implement screencast pause in TDesktop.

This commit is contained in:
John Preston 2021-06-11 12:20:32 +04:00
parent 8d72026cbd
commit 4543656aa3
3 changed files with 145 additions and 40 deletions

View File

@ -544,6 +544,11 @@ rpl::producer<bool> GroupCall::isSharingScreenValue() const {
return _isSharingScreen.value(); return _isSharingScreen.value();
} }
bool GroupCall::isScreenPaused() const {
return _screenOutgoing
&& (_screenOutgoing->state() == Webrtc::VideoState::Paused);
}
const std::string &GroupCall::screenSharingEndpoint() const { const std::string &GroupCall::screenSharingEndpoint() const {
return isSharingScreen() ? _screenEndpoint : EmptyString(); return isSharingScreen() ? _screenEndpoint : EmptyString();
} }
@ -556,6 +561,11 @@ rpl::producer<bool> GroupCall::isSharingCameraValue() const {
return _isSharingCamera.value(); return _isSharingCamera.value();
} }
bool GroupCall::isCameraPaused() const {
return _cameraOutgoing
&& (_cameraOutgoing->state() == Webrtc::VideoState::Paused);
}
const std::string &GroupCall::cameraSharingEndpoint() const { const std::string &GroupCall::cameraSharingEndpoint() const {
return isSharingCamera() ? _cameraEndpoint : EmptyString(); return isSharingCamera() ? _cameraEndpoint : EmptyString();
} }
@ -700,7 +710,7 @@ void GroupCall::subscribeToReal(not_null<Data::GroupCall*> real) {
VideoEndpointType::Camera, VideoEndpointType::Camera,
peer, peer,
wasCameraEndpoint, wasCameraEndpoint,
}, false, wasCameraPaused); }, false, false);
} else if (wasCameraPaused != nowCameraPaused) { } else if (wasCameraPaused != nowCameraPaused) {
markTrackPaused({ markTrackPaused({
VideoEndpointType::Camera, VideoEndpointType::Camera,
@ -728,7 +738,7 @@ void GroupCall::subscribeToReal(not_null<Data::GroupCall*> real) {
VideoEndpointType::Screen, VideoEndpointType::Screen,
peer, peer,
wasScreenEndpoint, wasScreenEndpoint,
}, false, wasScreenPaused); }, false, false);
} else if (wasScreenPaused != nowScreenPaused) { } else if (wasScreenPaused != nowScreenPaused) {
markTrackPaused({ markTrackPaused({
VideoEndpointType::Screen, VideoEndpointType::Screen,
@ -988,7 +998,7 @@ void GroupCall::setScreenEndpoint(std::string endpoint) {
VideoEndpointType::Screen, VideoEndpointType::Screen,
_joinAs, _joinAs,
_screenEndpoint _screenEndpoint
}, true, false); }, true, isScreenPaused());
} }
} }
@ -1012,7 +1022,7 @@ void GroupCall::setCameraEndpoint(std::string endpoint) {
VideoEndpointType::Camera, VideoEndpointType::Camera,
_joinAs, _joinAs,
_cameraEndpoint _cameraEndpoint
}, true, false); }, true, isCameraPaused());
} }
} }
@ -1225,11 +1235,15 @@ void GroupCall::rejoin(not_null<PeerData*> as) {
_peer->session().api().applyUpdates(updates); _peer->session().api().applyUpdates(updates);
applyQueuedSelfUpdates(); applyQueuedSelfUpdates();
checkFirstTimeJoined(); checkFirstTimeJoined();
if (wasVideoStopped == isSharingCamera()) {
sendSelfUpdate(SendUpdateType::VideoStopped);
}
_screenJoinState.nextActionPending = true; _screenJoinState.nextActionPending = true;
checkNextJoinAction(); checkNextJoinAction();
if (wasVideoStopped == isSharingCamera()) {
sendSelfUpdate(SendUpdateType::CameraStopped);
}
if (isCameraPaused()) {
sendSelfUpdate(SendUpdateType::CameraPaused);
}
sendPendingSelfUpdates();
}).fail([=](const MTP::Error &error) { }).fail([=](const MTP::Error &error) {
_joinState.finish(); _joinState.finish();
@ -1323,6 +1337,10 @@ void GroupCall::rejoinPresentation() {
_peer->session().api().applyUpdates(updates); _peer->session().api().applyUpdates(updates);
checkNextJoinAction(); checkNextJoinAction();
if (isScreenPaused()) {
sendSelfUpdate(SendUpdateType::ScreenPaused);
}
sendPendingSelfUpdates();
}).fail([=](const MTP::Error &error) { }).fail([=](const MTP::Error &error) {
_screenJoinState.finish(); _screenJoinState.finish();
@ -1934,22 +1952,35 @@ void GroupCall::emitShareScreenError(Error error) {
void GroupCall::ensureOutgoingVideo() { void GroupCall::ensureOutgoingVideo() {
Expects(_id != 0); Expects(_id != 0);
using Webrtc::VideoState;
if (_cameraOutgoing) { if (_cameraOutgoing) {
return; return;
} }
_cameraOutgoing = std::make_unique<Webrtc::VideoTrack>( _cameraOutgoing = std::make_unique<Webrtc::VideoTrack>(
Webrtc::VideoState::Inactive, VideoState::Inactive,
_requireARGB32); _requireARGB32);
_screenOutgoing = std::make_unique<Webrtc::VideoTrack>( _screenOutgoing = std::make_unique<Webrtc::VideoTrack>(
Webrtc::VideoState::Inactive, VideoState::Inactive,
_requireARGB32); _requireARGB32);
_cameraOutgoing->stateValue( _cameraOutgoing->stateValue(
) | rpl::start_with_next([=](Webrtc::VideoState state) { ) | rpl::combine_previous(
const auto active = (state != Webrtc::VideoState::Inactive); ) | rpl::start_with_next([=](VideoState previous, VideoState state) {
if (active) { const auto wasPaused = (previous == VideoState::Paused);
// Paused not supported right now. const auto wasActive = (previous != VideoState::Inactive);
Assert(state == Webrtc::VideoState::Active); const auto nowPaused = (state == VideoState::Paused);
const auto nowActive = (state != VideoState::Inactive);
if (wasActive == nowActive) {
Assert(wasActive && nowActive);
sendSelfUpdate(SendUpdateType::CameraPaused);
markTrackPaused({
VideoEndpointType::Camera,
_joinAs,
_cameraEndpoint
}, nowPaused);
return;
}
if (nowActive) {
if (emitShareCameraError()) { if (emitShareCameraError()) {
return; return;
} else if (!_cameraCapture) { } else if (!_cameraCapture) {
@ -1957,7 +1988,7 @@ void GroupCall::ensureOutgoingVideo() {
_cameraInputId); _cameraInputId);
if (!_cameraCapture) { if (!_cameraCapture) {
return emitShareCameraError(Error::NoCamera); return emitShareCameraError(Error::NoCamera);
_cameraOutgoing->setState(Webrtc::VideoState::Inactive); _cameraOutgoing->setState(VideoState::Inactive);
_errors.fire_copy(Error::NoCamera); _errors.fire_copy(Error::NoCamera);
return; return;
} }
@ -1971,22 +2002,34 @@ void GroupCall::ensureOutgoingVideo() {
} else if (_cameraCapture) { } else if (_cameraCapture) {
_cameraCapture->setState(tgcalls::VideoState::Inactive); _cameraCapture->setState(tgcalls::VideoState::Inactive);
} }
_isSharingCamera = active; _isSharingCamera = nowActive;
markEndpointActive({ markEndpointActive({
VideoEndpointType::Camera, VideoEndpointType::Camera,
_joinAs, _joinAs,
_cameraEndpoint _cameraEndpoint
}, active, false); }, nowActive, nowPaused);
sendSelfUpdate(SendUpdateType::VideoStopped); sendSelfUpdate(SendUpdateType::CameraStopped);
applyMeInCallLocally(); applyMeInCallLocally();
}, _lifetime); }, _lifetime);
_screenOutgoing->stateValue( _screenOutgoing->stateValue(
) | rpl::start_with_next([=](Webrtc::VideoState state) { ) | rpl::combine_previous(
const auto active = (state != Webrtc::VideoState::Inactive); ) | rpl::start_with_next([=](VideoState previous, VideoState state) {
if (active) { const auto wasPaused = (previous == VideoState::Paused);
// Paused not supported right now. const auto wasActive = (previous != VideoState::Inactive);
Assert(state == Webrtc::VideoState::Active); const auto nowPaused = (state == VideoState::Paused);
const auto nowActive = (state != VideoState::Inactive);
if (wasActive == nowActive) {
Assert(wasActive && nowActive);
sendSelfUpdate(SendUpdateType::ScreenPaused);
markTrackPaused({
VideoEndpointType::Screen,
_joinAs,
_screenEndpoint
}, nowPaused);
return;
}
if (nowActive) {
if (emitShareScreenError()) { if (emitShareScreenError()) {
return; return;
} else if (!_screenCapture) { } else if (!_screenCapture) {
@ -2004,6 +2047,15 @@ void GroupCall::ensureOutgoingVideo() {
emitShareScreenError(Error::ScreenFailed); emitShareScreenError(Error::ScreenFailed);
}); });
}); });
_screenCapture->setOnPause([=](bool paused) {
crl::on_main(weak, [=] {
if (isSharingScreen()) {
_screenOutgoing->setState(paused
? VideoState::Paused
: VideoState::Active);
}
});
});
} else { } else {
_screenCapture->switchToDevice(_screenDeviceId.toStdString()); _screenCapture->switchToDevice(_screenDeviceId.toStdString());
} }
@ -2014,12 +2066,12 @@ void GroupCall::ensureOutgoingVideo() {
} else if (_screenCapture) { } else if (_screenCapture) {
_screenCapture->setState(tgcalls::VideoState::Inactive); _screenCapture->setState(tgcalls::VideoState::Inactive);
} }
_isSharingScreen = active; _isSharingScreen = nowActive;
markEndpointActive({ markEndpointActive({
VideoEndpointType::Screen, VideoEndpointType::Screen,
_joinAs, _joinAs,
_screenEndpoint _screenEndpoint
}, active, false); }, nowActive, nowPaused);
_screenJoinState.nextActionPending = true; _screenJoinState.nextActionPending = true;
checkNextJoinAction(); checkNextJoinAction();
}, _lifetime); }, _lifetime);
@ -2361,7 +2413,11 @@ void GroupCall::updateRequestedVideoChannels() {
.ssrcGroups = (params->camera.endpointId == endpointId .ssrcGroups = (params->camera.endpointId == endpointId
? params->camera.ssrcGroups ? params->camera.ssrcGroups
: params->screen.ssrcGroups), : params->screen.ssrcGroups),
.quality = (video.quality == Group::VideoQuality::Full .minQuality = ((video.quality == Group::VideoQuality::Full
&& endpoint.type == VideoEndpointType::Screen)
? Quality::Full
: Quality::Thumbnail),
.maxQuality = (video.quality == Group::VideoQuality::Full
? Quality::Full ? Quality::Full
: video.quality == Group::VideoQuality::Medium : video.quality == Group::VideoQuality::Medium
? Quality::Medium ? Quality::Medium
@ -2437,8 +2493,13 @@ void GroupCall::fillActiveVideoEndpoints() {
feedOne({ Type::Screen, participant.peer, screen }, paused); feedOne({ Type::Screen, participant.peer, screen }, paused);
} }
} }
feedOne({ Type::Camera, _joinAs, cameraSharingEndpoint() }, false); const auto pausedState = Webrtc::VideoState::Paused;
feedOne({ Type::Screen, _joinAs, screenSharingEndpoint() }, false); feedOne(
{ Type::Camera, _joinAs, cameraSharingEndpoint() },
(_cameraOutgoing && _cameraOutgoing->state() == pausedState));
feedOne(
{ Type::Screen, _joinAs, screenSharingEndpoint() },
(_screenOutgoing && _screenOutgoing->state() == pausedState));
} }
if (large && !largeFound) { if (large && !largeFound) {
setVideoEndpointLarge({}); setVideoEndpointLarge({});
@ -2726,14 +2787,47 @@ void GroupCall::maybeSendMutedUpdate(MuteState previous) {
} }
} }
void GroupCall::sendPendingSelfUpdates() {
if ((state() != State::Connecting && state() != State::Joined)
|| _selfUpdateRequestId) {
return;
}
const auto updates = {
SendUpdateType::Mute,
SendUpdateType::RaiseHand,
SendUpdateType::CameraStopped,
SendUpdateType::CameraPaused,
SendUpdateType::ScreenPaused,
};
for (const auto type : updates) {
if (type == SendUpdateType::ScreenPaused
&& _screenJoinState.action != JoinAction::None) {
continue;
}
if (_pendingSelfUpdates & type) {
_pendingSelfUpdates &= ~type;
sendSelfUpdate(type);
return;
}
}
}
void GroupCall::sendSelfUpdate(SendUpdateType type) { void GroupCall::sendSelfUpdate(SendUpdateType type) {
_api.request(_updateMuteRequestId).cancel(); if ((state() != State::Connecting && state() != State::Joined)
|| _selfUpdateRequestId) {
_pendingSelfUpdates |= type;
return;
}
using Flag = MTPphone_EditGroupCallParticipant::Flag; using Flag = MTPphone_EditGroupCallParticipant::Flag;
_updateMuteRequestId = _api.request(MTPphone_EditGroupCallParticipant( _selfUpdateRequestId = _api.request(MTPphone_EditGroupCallParticipant(
MTP_flags((type == SendUpdateType::RaiseHand) MTP_flags((type == SendUpdateType::RaiseHand)
? Flag::f_raise_hand ? Flag::f_raise_hand
: (type == SendUpdateType::VideoStopped) : (type == SendUpdateType::CameraStopped)
? Flag::f_video_stopped ? Flag::f_video_stopped
: (type == SendUpdateType::CameraPaused)
? Flag::f_video_paused
: (type == SendUpdateType::ScreenPaused)
? Flag::f_presentation_paused
: Flag::f_muted), : Flag::f_muted),
inputCall(), inputCall(),
_joinAs->input, _joinAs->input,
@ -2741,13 +2835,14 @@ void GroupCall::sendSelfUpdate(SendUpdateType type) {
MTP_int(100000), // volume MTP_int(100000), // volume
MTP_bool(muted() == MuteState::RaisedHand), MTP_bool(muted() == MuteState::RaisedHand),
MTP_bool(!isSharingCamera()), MTP_bool(!isSharingCamera()),
MTP_bool(false), // video_paused MTP_bool(_cameraOutgoing->state() == Webrtc::VideoState::Paused),
MTP_bool(false) // presentation_paused MTP_bool(_screenOutgoing->state() == Webrtc::VideoState::Paused)
)).done([=](const MTPUpdates &result) { )).done([=](const MTPUpdates &result) {
_updateMuteRequestId = 0; _selfUpdateRequestId = 0;
_peer->session().api().applyUpdates(result); _peer->session().api().applyUpdates(result);
sendPendingSelfUpdates();
}).fail([=](const MTP::Error &error) { }).fail([=](const MTP::Error &error) {
_updateMuteRequestId = 0; _selfUpdateRequestId = 0;
if (error.type() == u"GROUPCALL_FORBIDDEN"_q) { if (error.type() == u"GROUPCALL_FORBIDDEN"_q) {
LOG(("Call Info: Rejoin after error '%1' in editGroupCallMember." LOG(("Call Info: Rejoin after error '%1' in editGroupCallMember."
).arg(error.type())); ).arg(error.type()));

View File

@ -369,9 +369,11 @@ public:
void setCurrentVideoDevice(const QString &deviceId); void setCurrentVideoDevice(const QString &deviceId);
[[nodiscard]] bool isSharingScreen() const; [[nodiscard]] bool isSharingScreen() const;
[[nodiscard]] rpl::producer<bool> isSharingScreenValue() const; [[nodiscard]] rpl::producer<bool> isSharingScreenValue() const;
[[nodiscard]] bool isScreenPaused() const;
[[nodiscard]] const std::string &screenSharingEndpoint() const; [[nodiscard]] const std::string &screenSharingEndpoint() const;
[[nodiscard]] bool isSharingCamera() const; [[nodiscard]] bool isSharingCamera() const;
[[nodiscard]] rpl::producer<bool> isSharingCameraValue() const; [[nodiscard]] rpl::producer<bool> isSharingCameraValue() const;
[[nodiscard]] bool isCameraPaused() const;
[[nodiscard]] const std::string &cameraSharingEndpoint() const; [[nodiscard]] const std::string &cameraSharingEndpoint() const;
[[nodiscard]] QString screenSharingDeviceId() const; [[nodiscard]] QString screenSharingDeviceId() const;
void toggleVideo(bool active); void toggleVideo(bool active);
@ -429,9 +431,11 @@ private:
Stream, Stream,
}; };
enum class SendUpdateType { enum class SendUpdateType {
Mute, Mute = 0x01,
RaiseHand, RaiseHand = 0x02,
VideoStopped, CameraStopped = 0x04,
CameraPaused = 0x08,
ScreenPaused = 0x10,
}; };
enum class JoinAction { enum class JoinAction {
None, None,
@ -449,6 +453,10 @@ private:
} }
}; };
friend inline constexpr bool is_flag_type(SendUpdateType) {
return true;
}
[[nodiscard]] bool mediaChannelDescriptionsFill( [[nodiscard]] bool mediaChannelDescriptionsFill(
not_null<MediaChannelDescriptionsTask*> task, not_null<MediaChannelDescriptionsTask*> task,
Fn<bool(uint32)> resolved = nullptr); Fn<bool(uint32)> resolved = nullptr);
@ -514,6 +522,7 @@ private:
bool mute, bool mute,
std::optional<int> volume); std::optional<int> volume);
void applyQueuedSelfUpdates(); void applyQueuedSelfUpdates();
void sendPendingSelfUpdates();
void applySelfUpdate(const MTPDgroupCallParticipant &data); void applySelfUpdate(const MTPDgroupCallParticipant &data);
void applyOtherParticipantUpdate(const MTPDgroupCallParticipant &data); void applyOtherParticipantUpdate(const MTPDgroupCallParticipant &data);
@ -574,7 +583,7 @@ private:
TimeId _scheduleDate = 0; TimeId _scheduleDate = 0;
base::flat_set<uint32> _mySsrcs; base::flat_set<uint32> _mySsrcs;
mtpRequestId _createRequestId = 0; mtpRequestId _createRequestId = 0;
mtpRequestId _updateMuteRequestId = 0; mtpRequestId _selfUpdateRequestId = 0;
rpl::variable<InstanceState> _instanceState rpl::variable<InstanceState> _instanceState
= InstanceState::Disconnected; = InstanceState::Disconnected;
@ -597,6 +606,7 @@ private:
rpl::variable<bool> _isSharingScreen = false; rpl::variable<bool> _isSharingScreen = false;
QString _screenDeviceId; QString _screenDeviceId;
base::flags<SendUpdateType> _pendingSelfUpdates;
bool _requireARGB32 = true; bool _requireARGB32 = true;
rpl::event_stream<LevelUpdate> _levelUpdates; rpl::event_stream<LevelUpdate> _levelUpdates;

@ -1 +1 @@
Subproject commit 99c951b9c7c014666f67e1e972dfc43538a47ff7 Subproject commit 9adb220f798cadc0848d3e1efbf32fb2a98a3bcb