From 0e7f93379d8cdc61e9d9e2ef0ae633feab98a1be Mon Sep 17 00:00:00 2001 From: Grishka Date: Sun, 30 Sep 2018 18:42:50 +0300 Subject: [PATCH] Added support for platform-specific microphone permission in calls --- Telegram/Resources/langs/lang.strings | 2 + Telegram/SourceFiles/calls/calls_call.cpp | 4 ++ Telegram/SourceFiles/calls/calls_call.h | 2 + Telegram/SourceFiles/calls/calls_instance.cpp | 31 ++++++++++++- Telegram/SourceFiles/calls/calls_instance.h | 1 + .../platform/linux/specific_linux.cpp | 12 +++++ .../SourceFiles/platform/mac/specific_mac.mm | 46 +++++++++++++++++++ .../SourceFiles/platform/platform_specific.h | 12 +++++ .../SourceFiles/platform/win/specific_win.cpp | 31 +++++++++++++ 9 files changed, 140 insertions(+), 1 deletion(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 196b30b24490cc..f6ac8bc6ca81dd 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1403,6 +1403,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_call_rate_label" = "Please rate the quality of your call"; "lng_call_rate_comment" = "Comment (optional)"; +"lng_no_mic_permission" = "Telegram needs access to your microphone so that you can make calls and record voice messages."; + "lng_player_message_today" = "Today at {time}"; "lng_player_message_yesterday" = "Yesterday at {time}"; "lng_player_message_date" = "{date} at {time}"; diff --git a/Telegram/SourceFiles/calls/calls_call.cpp b/Telegram/SourceFiles/calls/calls_call.cpp index 73a9b401cefd38..40efaa9a9f522e 100644 --- a/Telegram/SourceFiles/calls/calls_call.cpp +++ b/Telegram/SourceFiles/calls/calls_call.cpp @@ -241,6 +241,10 @@ void Call::startIncoming() { } void Call::answer() { + _delegate->requestMicrophonePermissionOrFail([this](){ actuallyAnswer(); }); +} + +void Call::actuallyAnswer() { Expects(_type == Type::Incoming); if (_state != State::Starting && _state != State::WaitingIncoming) { diff --git a/Telegram/SourceFiles/calls/calls_call.h b/Telegram/SourceFiles/calls/calls_call.h index b45ff42400a6ec..1ab360bd5d9408 100644 --- a/Telegram/SourceFiles/calls/calls_call.h +++ b/Telegram/SourceFiles/calls/calls_call.h @@ -46,6 +46,7 @@ class Call : public base::has_weak_ptr, private MTP::Sender { Ended, }; virtual void playSound(Sound sound) = 0; + virtual void requestMicrophonePermissionOrFail(Fn result) = 0; virtual ~Delegate(); @@ -167,6 +168,7 @@ class Call : public base::has_weak_ptr, private MTP::Sender { bool checkCallFields(const MTPDphoneCall &call); bool checkCallFields(const MTPDphoneCallAccepted &call); + void actuallyAnswer(); void confirmAcceptedCall(const MTPDphoneCallAccepted &call); void startConfirmedCall(const MTPDphoneCall &call); void setState(State state); diff --git a/Telegram/SourceFiles/calls/calls_instance.cpp b/Telegram/SourceFiles/calls/calls_instance.cpp index 9ebb92a8612bc8..1ce388a3f3e9c8 100644 --- a/Telegram/SourceFiles/calls/calls_instance.cpp +++ b/Telegram/SourceFiles/calls/calls_instance.cpp @@ -16,6 +16,8 @@ For license and copyright information please follow this link: #include "calls/calls_call.h" #include "calls/calls_panel.h" #include "media/media_audio_track.h" +#include "platform/platform_specific.h" +#include "mainwidget.h" #include "boxes/rate_call_box.h" namespace Calls { @@ -38,7 +40,9 @@ void Instance::startOutgoingCall(not_null user) { Ui::show(Box(lng_call_error_not_available(lt_user, App::peerName(user)))); return; } - createCall(user, Call::Type::Outgoing); + requestMicrophonePermissionOrFail([this, user](){ + createCall(user, Call::Type::Outgoing); + }); } void Instance::callFinished(not_null call) { @@ -284,6 +288,31 @@ void Instance::handleCallUpdate(const MTPPhoneCall &call) { bool Instance::alreadyInCall() { return (_currentCall && _currentCall->state() != Call::State::Busy); } + +void Instance::requestMicrophonePermissionOrFail(Fn onSuccess) { + Platform::PermissionStatus status=Platform::GetPermissionStatus(Platform::PermissionType::Microphone); + if (status==Platform::PermissionStatus::Granted) { + onSuccess(); + } else if(status==Platform::PermissionStatus::CanRequest) { + Platform::RequestPermission(Platform::PermissionType::Microphone, [this, onSuccess](Platform::PermissionStatus status){ + if (status==Platform::PermissionStatus::Granted) { + crl::on_main(onSuccess); + } else { + if (_currentCall) { + _currentCall->hangup(); + } + } + }); + } else { + if (alreadyInCall()) { + _currentCall->hangup(); + } + Ui::show(Box(lang(lng_no_mic_permission), lang(lng_menu_settings), [](){ + Platform::OpenSystemSettingsForPermission(Platform::PermissionType::Microphone); + Ui::hideLayer(); + })); + } +} Instance::~Instance() { for (auto panel : _pendingPanels) { diff --git a/Telegram/SourceFiles/calls/calls_instance.h b/Telegram/SourceFiles/calls/calls_instance.h index 29e7aa6fcfe2b8..4e9f26cf8a6cd4 100644 --- a/Telegram/SourceFiles/calls/calls_instance.h +++ b/Telegram/SourceFiles/calls/calls_instance.h @@ -63,6 +63,7 @@ class Instance : private MTP::Sender, private Call::Delegate, private base::Subs void createCall(not_null user, Call::Type type); void destroyCall(not_null call); void destroyCurrentPanel(); + void requestMicrophonePermissionOrFail(Fn onSuccess) override; void refreshDhConfig(); void refreshServerConfig(); diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp index d5bc23832aca37..a8fdd79af53926 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp @@ -433,6 +433,18 @@ void RegisterCustomScheme() { #endif // !TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME } +PermissionStatus GetPermissionStatus(PermissionType type){ + return PermissionStatus::Granted; +} + +void RequestPermission(PermissionType type, Fn resultCallback){ + +} + +void OpenSystemSettingsForPermission(PermissionType type){ + +} + namespace ThirdParty { void start() { diff --git a/Telegram/SourceFiles/platform/mac/specific_mac.mm b/Telegram/SourceFiles/platform/mac/specific_mac.mm index ea503e6a2a7f58..d2883e0076f841 100644 --- a/Telegram/SourceFiles/platform/mac/specific_mac.mm +++ b/Telegram/SourceFiles/platform/mac/specific_mac.mm @@ -26,6 +26,7 @@ #include #include #include +#include namespace { @@ -283,6 +284,51 @@ void RegisterCustomScheme() { #endif // !TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME } +// I do check for availability, just not in the exact way clang is content with +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" +PermissionStatus GetPermissionStatus(PermissionType type) { + switch(type) { + case PermissionType::Microphone: + if([AVCaptureDevice respondsToSelector: @selector(authorizationStatusForMediaType:)]) { // Available starting with 10.14 + switch([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio]) { + case AVAuthorizationStatusNotDetermined: + return PermissionStatus::CanRequest; + case AVAuthorizationStatusAuthorized: + return PermissionStatus::Granted; + case AVAuthorizationStatusDenied: + case AVAuthorizationStatusRestricted: + return PermissionStatus::Denied; + } + } + return PermissionStatus::Granted; + } + return PermissionStatus::Granted; +} + +void RequestPermission(PermissionType type, Fn resultCallback) { + switch(type) { + case PermissionType::Microphone: + if([AVCaptureDevice respondsToSelector: @selector(requestAccessForMediaType:completionHandler:)]) { // Available starting with 10.14 + [AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL granted) { + resultCallback(granted ? PermissionStatus::Granted : PermissionStatus::Denied); + }]; + }else{ + resultCallback(PermissionStatus::Granted); + } + break; + } +} +#pragma clang diagnostic pop // -Wunguarded-availability + +void OpenSystemSettingsForPermission(PermissionType type) { + switch(type) { + case PermissionType::Microphone: + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"x-apple.systempreferences:com.apple.preference.security?Privacy_Microphone"]]; + break; + } +} + } // namespace Platform void psNewVersion() { diff --git a/Telegram/SourceFiles/platform/platform_specific.h b/Telegram/SourceFiles/platform/platform_specific.h index 92485c7b6fa3bb..266e23d36bf65c 100644 --- a/Telegram/SourceFiles/platform/platform_specific.h +++ b/Telegram/SourceFiles/platform/platform_specific.h @@ -11,6 +11,15 @@ namespace Platform { void start(); void finish(); + +enum class PermissionStatus { + Granted, + CanRequest, + Denied, +}; +enum class PermissionType { + Microphone, +}; void SetWatchingMediaKeys(bool watching); bool IsApplicationActive(); @@ -20,6 +29,9 @@ void InitOnTopPanel(QWidget *panel); void DeInitOnTopPanel(QWidget *panel); void ReInitOnTopPanel(QWidget *panel); void RegisterCustomScheme(); +PermissionStatus GetPermissionStatus(PermissionType type); +void RequestPermission(PermissionType type, Fn resultCallback); +void OpenSystemSettingsForPermission(PermissionType type); QString SystemLanguage(); QString SystemCountry(); diff --git a/Telegram/SourceFiles/platform/win/specific_win.cpp b/Telegram/SourceFiles/platform/win/specific_win.cpp index a13d741d8a6428..1a8aab63d12739 100644 --- a/Telegram/SourceFiles/platform/win/specific_win.cpp +++ b/Telegram/SourceFiles/platform/win/specific_win.cpp @@ -626,6 +626,37 @@ void RegisterCustomScheme() { #endif // !TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME } +PermissionStatus GetPermissionStatus(PermissionType type) { + if(type==PermissionType::Microphone) { + PermissionStatus result=PermissionStatus::Granted; + HKEY hKey; + LSTATUS res=RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\CapabilityAccessManager\\ConsentStore\\microphone", 0, KEY_QUERY_VALUE, &hKey); + if(res==ERROR_SUCCESS) { + wchar_t buf[20]; + DWORD length=sizeof(buf); + res=RegQueryValueEx(hKey, L"Value", NULL, NULL, (LPBYTE)buf, &length); + if(res==ERROR_SUCCESS) { + if(wcscmp(buf, L"Deny")==0) { + result=PermissionStatus::Denied; + } + } + RegCloseKey(hKey); + } + return result; + } + return PermissionStatus::Granted; +} + +void RequestPermission(PermissionType type, Fn resultCallback) { + +} + +void OpenSystemSettingsForPermission(PermissionType type) { + if(type==PermissionType::Microphone) { + ShellExecute(NULL, L"open", L"ms-settings:privacy-microphone", NULL, NULL, SW_SHOWDEFAULT); + } +} + } // namespace Platform void psNewVersion() {