Added support for platform-specific microphone permission in calls

This commit is contained in:
Grishka 2018-09-30 18:42:50 +03:00 committed by John Preston
parent 500ecb464c
commit 44eac2bf07
9 changed files with 140 additions and 1 deletions

View File

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

View File

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

View File

@ -46,6 +46,7 @@ public:
Ended,
};
virtual void playSound(Sound sound) = 0;
virtual void requestMicrophonePermissionOrFail(Fn<void()> result) = 0;
virtual ~Delegate();
@ -167,6 +168,7 @@ private:
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);

View File

@ -16,6 +16,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#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<UserData*> user) {
Ui::show(Box<InformBox>(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*> 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<void()> 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<ConfirmBox>(lang(lng_no_mic_permission), lang(lng_menu_settings), [](){
Platform::OpenSystemSettingsForPermission(Platform::PermissionType::Microphone);
Ui::hideLayer();
}));
}
}
Instance::~Instance() {
for (auto panel : _pendingPanels) {

View File

@ -63,6 +63,7 @@ private:
void createCall(not_null<UserData*> user, Call::Type type);
void destroyCall(not_null<Call*> call);
void destroyCurrentPanel();
void requestMicrophonePermissionOrFail(Fn<void()> onSuccess) override;
void refreshDhConfig();
void refreshServerConfig();

View File

@ -433,6 +433,18 @@ void RegisterCustomScheme() {
#endif // !TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME
}
PermissionStatus GetPermissionStatus(PermissionType type){
return PermissionStatus::Granted;
}
void RequestPermission(PermissionType type, Fn<void(PermissionStatus)> resultCallback){
}
void OpenSystemSettingsForPermission(PermissionType type){
}
namespace ThirdParty {
void start() {

View File

@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <IOKit/hidsystem/ev_keymap.h>
#include <SPMediaKeyTap.h>
#include <mach-o/dyld.h>
#include <AVFoundation/AVFoundation.h>
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<void(PermissionStatus)> 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() {

View File

@ -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<void(PermissionStatus)> resultCallback);
void OpenSystemSettingsForPermission(PermissionType type);
QString SystemLanguage();
QString SystemCountry();

View File

@ -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<void(PermissionStatus)> 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() {