-
Notifications
You must be signed in to change notification settings - Fork 6.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(1) A new VideoConferenceAshFeatureClient is added to track individual features that are VC related (accessing mic and camera) (2) When VmCameraMicManager updates camera or mic capturing state, the notification is sent to VideoConferenceAshFeatureClient. (3) The class is intentionally written close to VideoConferenceAppServiceClient so that there can be an easy refactoring if we ever need to. (4) For CrostiniVm, PluginVm or Borealis, we can't know individual apps, so they are all treated as an individual app than a container of apps, this will be the case for sometime. And because of that, ReturnToApp is not implemented. Bug=b:273820331 TEST="autoninja -C out/Test chrome/test:browser_tests && out/Test/browser_tests --gtest_filter=VideoConferenceAshfeatureClientTest.*" Change-Id: Ia41e8be0ad0cac40256b602dfa37b70af50fe7f9 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4573953 Quick-Run: Charles Zhao <charleszhao@chromium.org> Commit-Queue: Charles Zhao <charleszhao@chromium.org> Reviewed-by: Andre Le <leandre@chromium.org> Reviewed-by: Takashi Toyoshima <toyoshim@chromium.org> Reviewed-by: Xiyuan Xia <xiyuan@chromium.org> Cr-Commit-Position: refs/heads/main@{#1153591}
- Loading branch information
Guoxing Zhao
authored and
Chromium LUCI CQ
committed
Jun 6, 2023
1 parent
1d48e1e
commit 7c615e3
Showing
10 changed files
with
690 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
274 changes: 274 additions & 0 deletions
274
chrome/browser/ash/video_conference/video_conference_ash_feature_client.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,274 @@ | ||
// Copyright 2023 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "chrome/browser/ash/video_conference/video_conference_ash_feature_client.h" | ||
|
||
#include "base/containers/contains.h" | ||
#include "base/strings/utf_string_conversions.h" | ||
#include "base/unguessable_token.h" | ||
#include "chrome/browser/ash/borealis/borealis_prefs.h" | ||
#include "chrome/browser/ash/crosapi/crosapi_ash.h" | ||
#include "chrome/browser/ash/crosapi/crosapi_manager.h" | ||
#include "chrome/browser/ash/crostini/crostini_pref_names.h" | ||
#include "chrome/browser/ash/plugin_vm/plugin_vm_pref_names.h" | ||
#include "chrome/browser/ash/video_conference/video_conference_manager_ash.h" | ||
#include "chrome/browser/profiles/profile_manager.h" | ||
#include "components/prefs/pref_service.h" | ||
|
||
namespace ash { | ||
namespace { | ||
|
||
VideoConferenceAshFeatureClient* g_client_instance = nullptr; | ||
|
||
constexpr char kCrostiniVmId[] = "Linux"; | ||
constexpr char kPluginVmId[] = "PluginVm"; | ||
constexpr char kBorealisId[] = "Borealis"; | ||
|
||
// Returns an "Id" as an identifier for the VmType. | ||
std::string ToVideoConferenceAppId(VmCameraMicManager::VmType vm_type) { | ||
switch (vm_type) { | ||
case VmCameraMicManager::VmType::kCrostiniVm: | ||
return kCrostiniVmId; | ||
case VmCameraMicManager::VmType::kPluginVm: | ||
return kPluginVmId; | ||
case VmCameraMicManager::VmType::kBorealis: | ||
return kBorealisId; | ||
} | ||
} | ||
|
||
} // namespace | ||
|
||
VideoConferenceAshFeatureClient::VideoConferenceAshFeatureClient() | ||
: client_id_(base::UnguessableToken::Create()), | ||
status_(crosapi::mojom::VideoConferenceMediaUsageStatus::New( | ||
/*client_id=*/client_id_, | ||
/*has_media_app=*/false, | ||
/*has_camera_permission=*/false, | ||
/*has_microphone_permission=*/false, | ||
/*is_capturing_camera=*/false, | ||
/*is_capturing_microphone=*/false, | ||
/*is_capturing_screen=*/false)) { | ||
crosapi::CrosapiManager::Get() | ||
->crosapi_ash() | ||
->video_conference_manager_ash() | ||
->RegisterCppClient(this, client_id_); | ||
|
||
CHECK(!g_client_instance); | ||
g_client_instance = this; | ||
} | ||
|
||
VideoConferenceAshFeatureClient::~VideoConferenceAshFeatureClient() { | ||
// C++ clients are responsible for manually calling |UnregisterClient| on the | ||
// manager when disconnecting. | ||
crosapi::CrosapiManager::Get() | ||
->crosapi_ash() | ||
->video_conference_manager_ash() | ||
->UnregisterClient(client_id_); | ||
|
||
g_client_instance = nullptr; | ||
} | ||
|
||
void VideoConferenceAshFeatureClient::GetMediaApps( | ||
GetMediaAppsCallback callback) { | ||
std::vector<crosapi::mojom::VideoConferenceMediaAppInfoPtr> apps; | ||
|
||
for (const auto& [app_id, app_state] : id_to_app_state_) { | ||
const std::string app_name = GetAppName(app_id); | ||
|
||
apps.push_back(crosapi::mojom::VideoConferenceMediaAppInfo::New( | ||
/*id=*/app_state.token, | ||
/*last_activity_time=*/app_state.last_activity_time, | ||
/*is_capturing_camera=*/app_state.is_capturing_camera, | ||
/*is_capturing_microphone=*/app_state.is_capturing_microphone, | ||
/*is_capturing_screen=*/false, | ||
/*title=*/base::UTF8ToUTF16(app_name), | ||
/*url=*/absl::nullopt, | ||
/*app_type=*/GetAppType(app_id))); | ||
} | ||
|
||
std::move(callback).Run(std::move(apps)); | ||
} | ||
|
||
void VideoConferenceAshFeatureClient::ReturnToApp( | ||
const base::UnguessableToken& token, | ||
ReturnToAppCallback callback) { | ||
// Currently, for Vms, we treat the whole VM as one app, so it is not clear | ||
// which one to return to. | ||
std::move(callback).Run(true); | ||
} | ||
|
||
void VideoConferenceAshFeatureClient::SetSystemMediaDeviceStatus( | ||
crosapi::mojom::VideoConferenceMediaDevice device, | ||
bool disabled, | ||
SetSystemMediaDeviceStatusCallback callback) { | ||
switch (device) { | ||
case crosapi::mojom::VideoConferenceMediaDevice::kCamera: | ||
camera_system_disabled_ = disabled; | ||
std::move(callback).Run(true); | ||
return; | ||
case crosapi::mojom::VideoConferenceMediaDevice::kMicrophone: | ||
microphone_system_disabled_ = disabled; | ||
std::move(callback).Run(true); | ||
return; | ||
case crosapi::mojom::VideoConferenceMediaDevice::kUnusedDefault: | ||
std::move(callback).Run(false); | ||
return; | ||
} | ||
} | ||
|
||
void VideoConferenceAshFeatureClient::OnVmDeviceUpdated( | ||
VmCameraMicManager::VmType vm_type, | ||
VmCameraMicManager::DeviceType device_type, | ||
bool is_capturing) { | ||
const AppIdString& app_id = ToVideoConferenceAppId(vm_type); | ||
|
||
const bool is_already_tracked = base::Contains(id_to_app_state_, app_id); | ||
|
||
// We only want to start tracking a app if it starts to accessing | ||
// microphone/camera. | ||
if (!is_already_tracked && !is_capturing) { | ||
return; | ||
} | ||
|
||
AppState& state = GetOrAddAppState(app_id); | ||
const std::string app_name = GetAppName(app_id); | ||
|
||
if (device_type == VmCameraMicManager::DeviceType::kCamera) { | ||
state.is_capturing_camera = is_capturing; | ||
} | ||
|
||
if (device_type == VmCameraMicManager::DeviceType::kMic) { | ||
state.is_capturing_microphone = is_capturing; | ||
} | ||
|
||
MaybeRemoveApp(app_id); | ||
HandleMediaUsageUpdate(); | ||
|
||
// This will be an AnchoredNudge, which is only visible if the tray is | ||
// visible; so we have to call this after HandleMediaUsageUpdate. | ||
if (device_type == VmCameraMicManager::DeviceType::kCamera && is_capturing && | ||
camera_system_disabled_) { | ||
crosapi::CrosapiManager::Get() | ||
->crosapi_ash() | ||
->video_conference_manager_ash() | ||
->NotifyDeviceUsedWhileDisabled( | ||
crosapi::mojom::VideoConferenceMediaDevice::kCamera, | ||
base::UTF8ToUTF16(app_name), base::DoNothingAs<void(bool)>()); | ||
} | ||
|
||
if (device_type == VmCameraMicManager::DeviceType::kMic && is_capturing && | ||
microphone_system_disabled_) { | ||
crosapi::CrosapiManager::Get() | ||
->crosapi_ash() | ||
->video_conference_manager_ash() | ||
->NotifyDeviceUsedWhileDisabled( | ||
crosapi::mojom::VideoConferenceMediaDevice::kMicrophone, | ||
base::UTF8ToUTF16(app_name), base::DoNothingAs<void(bool)>()); | ||
} | ||
} | ||
|
||
// static | ||
VideoConferenceAshFeatureClient* VideoConferenceAshFeatureClient::Get() { | ||
return g_client_instance; | ||
} | ||
|
||
// For Ash Features, we simply keep the app_id and app_name as the same. | ||
std::string VideoConferenceAshFeatureClient::GetAppName( | ||
const AppIdString& app_id) { | ||
return app_id; | ||
} | ||
|
||
// Get current camera/microphone permission of the `app_id`. | ||
VideoConferenceAshFeatureClient::VideoConferencePermissions | ||
VideoConferenceAshFeatureClient::GetAppPermission(const AppIdString& app_id) { | ||
VideoConferencePermissions permissions{false, false}; | ||
|
||
// Get permission from prefs based in the app_id. | ||
auto* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs(); | ||
if (app_id == kCrostiniVmId) { | ||
permissions.has_microphone_permission = | ||
prefs->GetBoolean(crostini::prefs::kCrostiniMicAllowed); | ||
} | ||
if (app_id == kBorealisId) { | ||
permissions.has_microphone_permission = | ||
prefs->GetBoolean(borealis::prefs::kBorealisMicAllowed); | ||
} | ||
if (app_id == kPluginVmId) { | ||
permissions.has_camera_permission = | ||
prefs->GetBoolean(plugin_vm ::prefs::kPluginVmCameraAllowed); | ||
permissions.has_microphone_permission = | ||
prefs->GetBoolean(plugin_vm ::prefs::kPluginVmMicAllowed); | ||
} | ||
return permissions; | ||
} | ||
|
||
crosapi::mojom::VideoConferenceAppType | ||
VideoConferenceAshFeatureClient::GetAppType(const AppIdString& app_id) { | ||
if (app_id == kCrostiniVmId) { | ||
return crosapi::mojom::VideoConferenceAppType::kCrostiniVm; | ||
} | ||
|
||
if (app_id == kPluginVmId) { | ||
return crosapi::mojom::VideoConferenceAppType::kPluginVm; | ||
} | ||
|
||
if (app_id == kBorealisId) { | ||
return crosapi::mojom::VideoConferenceAppType::kBorealis; | ||
} | ||
|
||
return crosapi::mojom::VideoConferenceAppType::kAshClientUnknown; | ||
} | ||
|
||
VideoConferenceAshFeatureClient::AppState& | ||
VideoConferenceAshFeatureClient::GetOrAddAppState(const std::string& app_id) { | ||
if (!base::Contains(id_to_app_state_, app_id)) { | ||
id_to_app_state_[app_id] = AppState{base::UnguessableToken::Create(), | ||
base::Time::Now(), false, false}; | ||
} | ||
return id_to_app_state_[app_id]; | ||
} | ||
|
||
void VideoConferenceAshFeatureClient::MaybeRemoveApp( | ||
const AppIdString& app_id) { | ||
if (!id_to_app_state_[app_id].is_capturing_microphone && | ||
!id_to_app_state_[app_id].is_capturing_camera) { | ||
id_to_app_state_.erase(app_id); | ||
} | ||
} | ||
|
||
void VideoConferenceAshFeatureClient::HandleMediaUsageUpdate() { | ||
crosapi::mojom::VideoConferenceMediaUsageStatusPtr new_status = | ||
crosapi::mojom::VideoConferenceMediaUsageStatus::New(); | ||
new_status->client_id = client_id_; | ||
new_status->has_media_app = !id_to_app_state_.empty(); | ||
|
||
for (const auto& [app_id, app_state] : id_to_app_state_) { | ||
new_status->is_capturing_camera |= app_state.is_capturing_camera; | ||
new_status->is_capturing_microphone |= app_state.is_capturing_microphone; | ||
|
||
VideoConferencePermissions permissions = GetAppPermission(app_id); | ||
new_status->has_camera_permission |= permissions.has_camera_permission; | ||
new_status->has_microphone_permission |= | ||
permissions.has_microphone_permission; | ||
} | ||
|
||
// If `status` equals the previously sent status, don't notify manager. | ||
if (new_status.Equals(status_)) { | ||
return; | ||
} | ||
status_ = new_status->Clone(); | ||
|
||
auto callback = base::BindOnce([](bool success) { | ||
if (!success) { | ||
LOG(ERROR) | ||
<< "VideoConferenceManager::NotifyMediaUsageUpdate did not succeed."; | ||
} | ||
}); | ||
crosapi::CrosapiManager::Get() | ||
->crosapi_ash() | ||
->video_conference_manager_ash() | ||
->NotifyMediaUsageUpdate(std::move(new_status), std::move(callback)); | ||
} | ||
|
||
} // namespace ash |
Oops, something went wrong.