blob: 01fd3c52297e40629454bd6b737bbcec792fca98 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <ddk/debug.h>
#include "garnet/drivers/usb_video/camera_control_impl.h"
#include "garnet/drivers/usb_video/usb-video-stream.h"
namespace camera {
void ControlImpl::OnFrameAvailable(
const fuchsia::camera::driver::FrameAvailableEvent& frame) {
stream_->OnFrameAvailable(frame);
}
ControlImpl::ControlImpl(video::usb::UsbVideoStream* usb_video_stream,
fidl::InterfaceRequest<Control> control,
async_dispatcher_t* dispatcher,
fit::closure on_connection_closed)
: binding_(this, fbl::move(control), dispatcher),
usb_video_stream_(usb_video_stream) {
binding_.set_error_handler(fbl::move(on_connection_closed));
}
void ControlImpl::GetFormats(uint32_t index, GetFormatsCallback callback) {
if (index == 0) {
zx_status_t status = usb_video_stream_->GetFormats(formats_);
if ((status == ZX_OK) &&
(formats_->size() >
fuchsia::camera::driver::MAX_FORMATS_PER_RESPONSE)) {
fidl::VectorPtr<fuchsia::camera::driver::VideoFormat> formats;
for (uint32_t i = 0;
i < fuchsia::camera::driver::MAX_FORMATS_PER_RESPONSE; i++) {
formats.push_back((*formats_)[i]);
}
callback(fbl::move(formats), formats_->size(), ZX_OK);
} else {
callback(fbl::move(formats_), formats_->size(), status);
}
} else {
uint32_t formats_to_send =
std::min(static_cast<uint32_t>(formats_->size() - index),
fuchsia::camera::driver::MAX_FORMATS_PER_RESPONSE);
fidl::VectorPtr<fuchsia::camera::driver::VideoFormat> formats;
if (index < formats_->size()) {
for (uint32_t i = 0; i < formats_to_send; i++) {
formats.push_back((*formats_)[index + i]);
}
callback(fbl::move(formats), formats_->size(), ZX_OK);
} else {
callback(fbl::move(formats), formats_->size(), ZX_ERR_INVALID_ARGS);
}
}
}
void ControlImpl::CreateStream(
fuchsia::sysmem::BufferCollectionInfo buffer_collection,
fuchsia::camera::driver::FrameRate frame_rate,
fidl::InterfaceRequest<fuchsia::camera::driver::Stream> stream) {
zx_status_t status =
usb_video_stream_->CreateStream(std::move(buffer_collection), frame_rate);
if (status != ZX_OK) {
zxlogf(ERROR, "Failed to set format. Closing channel.\n");
binding_.Unbind(); // Close the channel on error.
return;
}
stream_ = fbl::make_unique<StreamImpl>(*this, fbl::move(stream));
}
void ControlImpl::StreamImpl::OnFrameAvailable(
const fuchsia::camera::driver::FrameAvailableEvent& frame) {
binding_.events().OnFrameAvailable(frame);
}
void ControlImpl::StreamImpl::Start() {
zx_status_t status = owner_.usb_video_stream_->StartStreaming();
if (status != ZX_OK) {
zxlogf(ERROR, "Failed to start. Closing channel.\n");
binding_.Unbind(); // Close the channel on error.
}
}
void ControlImpl::StreamImpl::Stop() {
zx_status_t status = owner_.usb_video_stream_->StopStreaming();
if (status != ZX_OK) {
zxlogf(ERROR, "Failed to stop. Closing channel.\n");
binding_.Unbind(); // Close the channel on error.
}
}
void ControlImpl::StreamImpl::ReleaseFrame(uint32_t buffer_index) {
zx_status_t status = owner_.usb_video_stream_->FrameRelease(buffer_index);
if (status != ZX_OK) {
zxlogf(ERROR, "Failed to release frame. Closing channel.\n");
binding_.Unbind(); // Close the channel on error.
}
}
ControlImpl::StreamImpl::StreamImpl(
ControlImpl& owner,
fidl::InterfaceRequest<fuchsia::camera::driver::Stream> stream)
: owner_(owner), binding_(this, fbl::move(stream)) {
binding_.set_error_handler(
[this] { owner_.usb_video_stream_->DeactivateVideoBuffer(); });
}
} // namespace camera