Skip to content

Commit

Permalink
media: add ARC++ camera HAL v3 Mojo service
Browse files Browse the repository at this point in the history
The ARC++ camera HAL v3 Mojo service serves as a proxy to establish the
Mojo connections between the camera clients (i.e. VideoCaptureDeviceFactory
in Chrome and HAL v3 shim in cameraserver process in the Android container)
and the camera HALv3 process in Chrome OS.

BUG=b:32690003
TEST=Make sure camera preview works in hangout.
TEST=unit tests

Change-Id: I9e4e35a49b8efdc158b2c3ef30de352e32198064
Reviewed-on: https://chromium-review.googlesource.com/540956
Commit-Queue: Ricky Liang <[email protected]>
Reviewed-by: Ken Buchanan <[email protected]>
Reviewed-by: Christian Fremerey <[email protected]>
Reviewed-by: Kuang-che Wu <[email protected]>
Reviewed-by: Wu-cheng Li <[email protected]>
Cr-Commit-Position: refs/heads/master@{#482587}
  • Loading branch information
Ricky Liang authored and Commit Bot committed Jun 27, 2017
1 parent 23503cd commit 6b4ec7b
Show file tree
Hide file tree
Showing 11 changed files with 813 additions and 78 deletions.
2 changes: 2 additions & 0 deletions media/capture/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ component("capture_lib") {
"video/chromeos/camera_device_context.cc",
"video/chromeos/camera_device_delegate.cc",
"video/chromeos/camera_hal_delegate.cc",
"video/chromeos/camera_hal_dispatcher_impl.cc",
"video/chromeos/camera_metadata_utils.cc",
"video/chromeos/display_rotation_observer.cc",
"video/chromeos/pixel_format_utils.cc",
Expand Down Expand Up @@ -249,6 +250,7 @@ test("capture_unittests") {
sources += [
"video/chromeos/camera_device_delegate_unittest.cc",
"video/chromeos/camera_hal_delegate_unittest.cc",
"video/chromeos/camera_hal_dispatcher_impl_unittest.cc",
"video/chromeos/mock_camera_module.cc",
"video/chromeos/mock_video_capture_client.cc",
"video/chromeos/stream_buffer_manager_unittest.cc",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class CameraDeviceDelegateTest : public ::testing::Test {
hal_delegate_thread_.Start();
camera_hal_delegate_ =
new CameraHalDelegate(hal_delegate_thread_.task_runner());
camera_hal_delegate_->StartForTesting(
camera_hal_delegate_->SetCameraModule(
mock_camera_module_.GetInterfacePtrInfo());

ResetCaptureClient();
Expand Down
123 changes: 54 additions & 69 deletions media/capture/video/chromeos/camera_hal_delegate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,10 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/strings/string_piece.h"
#include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h"
#include "media/capture/video/chromeos/camera_metadata_utils.h"
#include "media/capture/video/chromeos/pixel_format_utils.h"
#include "media/capture/video/chromeos/video_capture_device_arc_chromeos.h"
#include "mojo/edk/embedder/embedder.h"
#include "mojo/edk/embedder/incoming_broker_client_invitation.h"
#include "mojo/edk/embedder/named_platform_handle.h"
#include "mojo/edk/embedder/named_platform_handle_utils.h"
#include "mojo/edk/embedder/platform_channel_pair.h"
#include "mojo/edk/embedder/platform_channel_utils_posix.h"
#include "mojo/edk/embedder/platform_handle_vector.h"

namespace media {

Expand All @@ -33,11 +27,29 @@ const base::StringPiece kArcCamera3SocketPath("/var/run/camera/camera3.sock");
const base::TimeDelta kEventWaitTimeoutMs =
base::TimeDelta::FromMilliseconds(3000);

class LocalCameraClientObserver : public CameraClientObserver {
public:
explicit LocalCameraClientObserver(
scoped_refptr<CameraHalDelegate> camera_hal_delegate)
: camera_hal_delegate_(std::move(camera_hal_delegate)) {}

void OnChannelCreated(arc::mojom::CameraModulePtr camera_module) override {
camera_hal_delegate_->SetCameraModule(camera_module.PassInterface());
}

private:
scoped_refptr<CameraHalDelegate> camera_hal_delegate_;
DISALLOW_IMPLICIT_CONSTRUCTORS(LocalCameraClientObserver);
};

} // namespace

CameraHalDelegate::CameraHalDelegate(
scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner)
: builtin_camera_info_updated_(
: camera_module_has_been_set_(
base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED),
builtin_camera_info_updated_(
base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED),
num_builtin_cameras_(0),
Expand All @@ -48,62 +60,16 @@ CameraHalDelegate::CameraHalDelegate(

CameraHalDelegate::~CameraHalDelegate() {}

bool CameraHalDelegate::StartCameraModuleIpc() {
// Non-blocking socket handle.
mojo::edk::ScopedPlatformHandle socket_handle = mojo::edk::CreateClientHandle(
mojo::edk::NamedPlatformHandle(kArcCamera3SocketPath));

// Set socket to blocking
int flags = HANDLE_EINTR(fcntl(socket_handle.get().handle, F_GETFL));
if (flags == -1) {
PLOG(ERROR) << "fcntl(F_GETFL) failed: ";
return false;
}
if (HANDLE_EINTR(fcntl(socket_handle.get().handle, F_SETFL,
flags & ~O_NONBLOCK)) == -1) {
PLOG(ERROR) << "fcntl(F_SETFL) failed: ";
return false;
}

const size_t kTokenSize = 32;
char token[kTokenSize] = {};
std::deque<mojo::edk::PlatformHandle> platform_handles;
ssize_t ret = mojo::edk::PlatformChannelRecvmsg(
socket_handle.get(), token, sizeof(token), &platform_handles, true);
if (ret == -1) {
PLOG(ERROR) << "PlatformChannelRecvmsg failed: ";
return false;
}
if (platform_handles.size() != 1) {
LOG(ERROR) << "Unexpected number of handles received, expected 1: "
<< platform_handles.size();
return false;
}
mojo::edk::ScopedPlatformHandle parent_pipe(platform_handles.back());
platform_handles.pop_back();
if (!parent_pipe.is_valid()) {
LOG(ERROR) << "Invalid parent pipe";
return false;
}
std::unique_ptr<mojo::edk::IncomingBrokerClientInvitation> invitation =
mojo::edk::IncomingBrokerClientInvitation::Accept(
mojo::edk::ConnectionParams(mojo::edk::TransportProtocol::kLegacy,
std::move(parent_pipe)));
mojo::ScopedMessagePipeHandle child_pipe =
invitation->ExtractMessagePipe(token);
if (!child_pipe.is_valid()) {
LOG(ERROR) << "Invalid child pipe";
return false;
}

camera_module_ =
mojo::MakeProxy(mojo::InterfacePtrInfo<arc::mojom::CameraModule>(
std::move(child_pipe), 0u),
ipc_task_runner_);

VLOG(1) << "Camera module IPC connection established";
void CameraHalDelegate::RegisterCameraClient() {
CameraHalDispatcherImpl::GetInstance()->AddClientObserver(
base::MakeUnique<LocalCameraClientObserver>(this));
}

return true;
void CameraHalDelegate::SetCameraModule(
arc::mojom::CameraModulePtrInfo camera_module_ptr_info) {
ipc_task_runner_->PostTask(
FROM_HERE, base::Bind(&CameraHalDelegate::SetCameraModuleOnIpcThread,
this, base::Passed(&camera_module_ptr_info)));
}

void CameraHalDelegate::Reset() {
Expand Down Expand Up @@ -233,8 +199,10 @@ void CameraHalDelegate::GetDeviceDescriptors(

void CameraHalDelegate::GetCameraInfo(int32_t camera_id,
const GetCameraInfoCallback& callback) {
// This method may be called on any thread. Currently this method is used by
// CameraDeviceDelegate to query camera info.
DCHECK(!ipc_task_runner_->BelongsToCurrentThread());
// This method may be called on any thread except |ipc_task_runner_|.
// Currently this method is used by CameraDeviceDelegate to query camera info.
camera_module_has_been_set_.Wait();
ipc_task_runner_->PostTask(
FROM_HERE, base::Bind(&CameraHalDelegate::GetCameraInfoOnIpcThread, this,
camera_id, callback));
Expand All @@ -244,16 +212,28 @@ void CameraHalDelegate::OpenDevice(
int32_t camera_id,
arc::mojom::Camera3DeviceOpsRequest device_ops_request,
const OpenDeviceCallback& callback) {
// This method may be called on any thread. Currently this method is used by
// CameraDeviceDelegate to open a camera device.
DCHECK(!ipc_task_runner_->BelongsToCurrentThread());
// This method may be called on any thread except |ipc_task_runner_|.
// Currently this method is used by CameraDeviceDelegate to open a camera
// device.
camera_module_has_been_set_.Wait();
ipc_task_runner_->PostTask(
FROM_HERE,
base::Bind(&CameraHalDelegate::OpenDeviceOnIpcThread, this, camera_id,
base::Passed(&device_ops_request), callback));
}

void CameraHalDelegate::StartForTesting(arc::mojom::CameraModulePtrInfo info) {
camera_module_.Bind(std::move(info), ipc_task_runner_);
void CameraHalDelegate::SetCameraModuleOnIpcThread(
arc::mojom::CameraModulePtrInfo camera_module_ptr_info) {
DCHECK(ipc_task_runner_->BelongsToCurrentThread());
if (camera_module_.is_bound()) {
LOG(ERROR) << "CameraModule is already bound";
return;
}
camera_module_ = mojo::MakeProxy(std::move(camera_module_ptr_info));
camera_module_.set_connection_error_handler(
base::Bind(&CameraHalDelegate::ResetMojoInterfaceOnIpcThread, this));
camera_module_has_been_set_.Signal();
}

void CameraHalDelegate::ResetMojoInterfaceOnIpcThread() {
Expand All @@ -262,10 +242,15 @@ void CameraHalDelegate::ResetMojoInterfaceOnIpcThread() {
if (camera_module_callbacks_.is_bound()) {
camera_module_callbacks_.Close();
}
builtin_camera_info_updated_.Reset();
camera_module_has_been_set_.Reset();
}

bool CameraHalDelegate::UpdateBuiltInCameraInfo() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!ipc_task_runner_->BelongsToCurrentThread());

camera_module_has_been_set_.Wait();
if (builtin_camera_info_updated_.IsSignaled()) {
return true;
}
Expand Down
14 changes: 8 additions & 6 deletions media/capture/video/chromeos/camera_hal_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ class CAPTURE_EXPORT CameraHalDelegate final
explicit CameraHalDelegate(
scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner);

// Establishes the Mojo IPC channel to the camera HAL adapter. This method
// should be called before any other methods of CameraHalDelegate is called.
bool StartCameraModuleIpc();
// Registers the camera client observer to the CameraHalDispatcher instance.
void RegisterCameraClient();

void SetCameraModule(arc::mojom::CameraModulePtrInfo camera_module_ptr_info);

// Resets |camera_module_| and |camera_module_callbacks_|.
void Reset();
Expand Down Expand Up @@ -75,9 +76,8 @@ class CAPTURE_EXPORT CameraHalDelegate final

~CameraHalDelegate() final;

friend class CameraHalDelegateTest;
friend class CameraDeviceDelegateTest;
void StartForTesting(arc::mojom::CameraModulePtrInfo info);
void SetCameraModuleOnIpcThread(
arc::mojom::CameraModulePtrInfo camera_module_ptr_info);

// Resets the Mojo interface and bindings.
void ResetMojoInterfaceOnIpcThread();
Expand Down Expand Up @@ -112,6 +112,8 @@ class CAPTURE_EXPORT CameraHalDelegate final
int32_t camera_id,
arc::mojom::CameraDeviceStatus new_status) final;

base::WaitableEvent camera_module_has_been_set_;

// Signaled when |num_builtin_cameras_| and |camera_info_| are updated.
// Queried and waited by UpdateBuiltInCameraInfo, signaled by
// OnGotCameraInfoOnIpcThread.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class CameraHalDelegateTest : public ::testing::Test {
hal_delegate_thread_.Start();
camera_hal_delegate_ =
new CameraHalDelegate(hal_delegate_thread_.task_runner());
camera_hal_delegate_->StartForTesting(
camera_hal_delegate_->SetCameraModule(
mock_camera_module_.GetInterfacePtrInfo());
}

Expand Down
Loading

0 comments on commit 6b4ec7b

Please sign in to comment.