Skip to content

Commit

Permalink
chromebox_for_meetings: GetCtrl through ControlMapping for XU Camera …
Browse files Browse the repository at this point in the history
…Service.

BUG=b:257061017

Change-Id: I2676808f26504f5a9c04cb6869fbe42b9c40c91a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4111336
Auto-Submit: Jazbel Wang <jazbel@chromium.org>
Reviewed-by: Kyle Williams <kdgwill@chromium.org>
Commit-Queue: Kyle Williams <kdgwill@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1084865}
  • Loading branch information
Jazbel Wang authored and Chromium LUCI CQ committed Dec 19, 2022
1 parent 06cc97e commit ee9addb
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 19 deletions.
Expand Up @@ -190,9 +190,8 @@ void XuCameraService::GetCtrl(const mojom::WebcamIdPtr id,
const mojom::CtrlTypePtr ctrl,
const mojom::GetFn fn,
GetCtrlCallback callback) {
uint8_t error_code = ENOSYS;
uint8_t error_code = 0;
std::vector<uint8_t> data;
mojom::ControlQueryPtr query;
std::string dev_path = id->is_device_id() ? GetDevicePath(id->get_device_id())
: id->get_dev_path();

Expand All @@ -211,8 +210,8 @@ void XuCameraService::GetCtrl(const mojom::WebcamIdPtr id,
data, GetRequest(fn));
break;
case mojom::CtrlType::Tag::kMappingCtrl:
NOTIMPLEMENTED();
error_code = ENOSYS;
error_code = CtrlThroughMapping(
file_descriptor, std::move(ctrl->get_mapping_ctrl()), data, fn);
break;
default:
LOG(ERROR) << __func__ << ": Invalid CtrlType::Tag";
Expand Down Expand Up @@ -289,7 +288,7 @@ std::string XuCameraService::GetDevicePath(const std::string& device_id) {
uint8_t XuCameraService::CtrlThroughQuery(int file_descriptor,
const mojom::ControlQueryPtr& query,
std::vector<uint8_t>& data,
unsigned int request) {
const uint8_t& request) {
if (UVC_SET_CUR == request) {
uint8_t error_code =
QueryXuControl(file_descriptor, query->unit_id, query->selector,
Expand Down Expand Up @@ -319,4 +318,76 @@ uint8_t XuCameraService::CtrlThroughQuery(int file_descriptor,

return error_code;
}

uint8_t XuCameraService::CtrlThroughMapping(
int file_descriptor,
const mojom::ControlMappingPtr& mapping,
std::vector<uint8_t>& data,
const mojom::GetFn& fn) {
uint8_t error_code = 0;

// Early return for kCur/kLen vs other info that requires VIDIOC_QUERYCTRL
if (mojom::GetFn::kLen == fn) {
// User set up the map so they should know that the size returned will be
// in bits.
data.push_back(mapping->size);
return error_code;
} else if (mojom::GetFn::kCur == fn) {
struct v4l2_control control = {.id = mapping->id};
error_code = delegate_->Ioctl(file_descriptor, VIDIOC_G_CTRL, &control);
CopyToData<int32_t>(&control.value, data, sizeof(control.value));
return error_code;
}

struct v4l2_queryctrl query = {
.id = mapping->id,
};

error_code = delegate_->Ioctl(file_descriptor, VIDIOC_QUERYCTRL, &query);

if (error_code != 0) {
return error_code;
}

switch (fn) {
case mojom::GetFn::kMin: {
CopyToData<int32_t>(&query.minimum, data, sizeof(query.minimum));
break;
}
case mojom::GetFn::kMax: {
CopyToData<int32_t>(&query.maximum, data, sizeof(query.maximum));
break;
}
case mojom::GetFn::kDef: {
CopyToData<int32_t>(&query.default_value, data,
sizeof(query.default_value));
break;
}
case mojom::GetFn::kRes: {
CopyToData<int32_t>(&query.step, data, sizeof(query.step));
break;
}
case mojom::GetFn::kInfo: {
// Get control info bitmap for get/set
CopyToData<uint32_t>(&query.flags, data, sizeof(query.flags));
break;
}
default:
LOG(ERROR) << __func__ << ": Invalid GetFn. ";
return EINVAL;
}
return error_code;
}

template <typename T>
void XuCameraService::CopyToData(T* value,
std::vector<uint8_t>& data,
size_t size) {
data.reserve(size);
uint8_t* valueAsUint8 = reinterpret_cast<uint8_t*>(value);
for (size_t i = 0; i < size; ++i) {
data.push_back(*valueAsUint8);
valueAsUint8++;
}
}
} // namespace ash::cfm
Expand Up @@ -95,8 +95,14 @@ class XuCameraService : public CfmObserver,
uint8_t CtrlThroughQuery(int file_descriptor,
const mojom::ControlQueryPtr& query,
std::vector<uint8_t>& data,
unsigned int request);

const uint8_t& query_request);
uint8_t CtrlThroughMapping(int file_descriptor,
const mojom::ControlMappingPtr& mapping,
std::vector<uint8_t>& data,
const mojom::GetFn& fn);
void ConvertLength(std::vector<uint8_t>& data, uint32_t type);
template <typename T>
void CopyToData(T* value, std::vector<uint8_t>& data, size_t size);
Delegate* delegate_;
ServiceAdaptor service_adaptor_;
mojo::ReceiverSet<XuCamera> receivers_;
Expand Down
Expand Up @@ -38,13 +38,16 @@ const auto kMenuEntries = mojom::MenuEntries::New();
const std::vector<uint8_t> kName(32, 'a');
const std::vector<uint8_t> kData = {0x43, 0x21};
const std::vector<uint8_t> kLen = {0x02, 0x00}; // little-endian uint16
const int32_t kValue = 123; // Fake v4l2 value
const std::vector<uint8_t> kValueAsUint8 = {
(std::uint8_t*)&(kValue), (std::uint8_t*)&(kValue) + sizeof(std::int32_t)};

class TestDelegate : public XuCameraService::Delegate {
public:
int Ioctl(int fd, unsigned int request, void* query) override {
if (VIDIOC_G_CTRL == request) {
struct v4l2_control* control = static_cast<v4l2_control*>(query);
control->value = {'fake'};
control->value = kValue;
} else if (UVCIOC_CTRL_QUERY == request) {
uvc_xu_control_query* control_query =
static_cast<uvc_xu_control_query*>(query);
Expand All @@ -60,17 +63,22 @@ class TestDelegate : public XuCameraService::Delegate {
}
int OpenFile(std::string path) override {
if (path.empty()) {
fd_ = -1;
LOG(ERROR) << "Filepath is empty";
return -1;
}
if (fd_ == 1) {
LOG(ERROR) << "Already opened file.";
return -1;
}
fd_ = 1;
return fd_;
}

void CloseFile(int file_descriptor) override {
if (fd_ == file_descriptor) {
fd_ = 0;
} else {
if (fd_ != file_descriptor) {
LOG(ERROR) << "No such file.";
}
fd_ = 0;
}

private:
Expand Down Expand Up @@ -190,7 +198,8 @@ TEST_F(XuCameraServiceTest, GetXuCameraMapCtrl) {
auto devPath = mojom::WebcamId::NewDevPath("/fake/device/path");
auto mapping = mojom::ControlMapping::New(
/* id= */ 1, /* name= */ kName, /* guid= */ kGuid, /* selector= */ 1,
/* size= */ 1, /* offset= */ 1, /* v4l2_type= */ V4L2_CTRL_TYPE_INTEGER,
/* size= */ 1, /* offset= */ 1,
/* v4l2_type= */ V4L2_CTRL_TYPE_INTEGER,
/* data_type= */ UVC_CTRL_DATA_TYPE_SIGNED, /* menu_entries= */
kMenuEntries->Clone());
base::RunLoop run_loop;
Expand All @@ -209,7 +218,8 @@ TEST_F(XuCameraServiceTest, XuCameraGetCtrlWithDeviceIdCtrlMapping) {
auto devId = mojom::WebcamId::NewDeviceId("123");
auto mapping = mojom::CtrlType::NewMappingCtrl(mojom::ControlMapping::New(
/* id= */ 1, /* name= */ kName, /* guid= */ kGuid, /* selector= */ 1,
/* size= */ 1, /* offset= */ 1, /* v4l2_type= */ V4L2_CTRL_TYPE_INTEGER,
/* size= */ 1, /* offset= */ 1,
/* v4l2_type= */ V4L2_CTRL_TYPE_INTEGER,
/* data_type= */ UVC_CTRL_DATA_TYPE_SIGNED, /* menu_entries= */
kMenuEntries->Clone()));
GetXuCameraRemote()->GetCtrl(
Expand Down Expand Up @@ -240,9 +250,8 @@ TEST_F(XuCameraServiceTest, XuCameraGetCtrlWithDevPathCtrlMapping) {
/* fn= */ mojom::GetFn::kCur,
base::BindLambdaForTesting(
[&](const uint8_t error_code, const std::vector<uint8_t>& data) {
const std::vector<uint8_t> vec;
EXPECT_EQ(error_code, ENOSYS);
EXPECT_EQ(data, vec);
EXPECT_EQ(error_code, 0);
EXPECT_EQ(data, kValueAsUint8);
run_loop.Quit();
}));
run_loop.Run();
Expand Down Expand Up @@ -286,7 +295,8 @@ TEST_F(XuCameraServiceTest, XuCameraGetCtrlWithDevPathCtrlQuery) {
run_loop.Run();
}

// This test ensure that the XU camera can get control length given a ctrl query
// This test ensure that the XU camera can get control length given a ctrl
// query
TEST_F(XuCameraServiceTest, XuCameraGetCtrlLenWithDevPathCtrlQuery) {
base::RunLoop run_loop;
auto devPath = mojom::WebcamId::NewDevPath("/fake/device/path");
Expand All @@ -310,7 +320,8 @@ TEST_F(XuCameraServiceTest, XuCameraSetCtrlWithDeviceIdCtrlMapping) {
auto devId = mojom::WebcamId::NewDeviceId("123");
auto mapping = mojom::CtrlType::NewMappingCtrl(mojom::ControlMapping::New(
/* id= */ 1, /* name= */ kName, /* guid= */ kGuid, /* selector= */ 1,
/* size= */ 1, /* offset= */ 1, /* v4l2_type= */ V4L2_CTRL_TYPE_INTEGER,
/* size= */ 1, /* offset= */ 1,
/* v4l2_type= */ V4L2_CTRL_TYPE_INTEGER,
/* data_type= */ UVC_CTRL_DATA_TYPE_SIGNED, /* menu_entries= */
kMenuEntries->Clone()));
std::vector<uint8_t> data{'a', 'b', 'c'};
Expand Down

0 comments on commit ee9addb

Please sign in to comment.