blob: 22866770b5e2601ed2f4cfee9b6765427ec0088e [file] [log] [blame]
// Copyright 2019 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 <fuchsia/camera2/cpp/fidl.h>
#include <fuchsia/camera2/hal/cpp/fidl.h>
#include <fuchsia/io/cpp/fidl.h>
#include <fuchsia/sysmem/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/namespace.h>
#include <lib/fzl/fdio.h>
#include <lib/gtest/real_loop_fixture.h>
#include <lib/sys/cpp/component_context.h>
#include <initializer_list>
#include <memory>
#include <vector>
#include "gtest/gtest.h"
#include "src/lib/syslog/cpp/logger.h"
namespace {
constexpr uint32_t kBufferCountForCamping = 2;
constexpr uint32_t kFakeImageMinWidth = 10;
constexpr uint32_t kFakeImageMaxWidth = 0; // Treated as max
constexpr uint32_t kFakeImageMinHeight = 10;
constexpr uint32_t kFakeImageMaxHeight = 0; // Treated as max.
constexpr uint32_t kFakeImageMinBytesPerRow = 10;
constexpr uint32_t kFakeImageMaxBytesPerRow = 0; // Treated as max.
constexpr uint32_t kFakeImageBytesPerRowDivisor = 128;
constexpr uint32_t kNumberOfLayers = 1;
fuchsia::sysmem::BufferCollectionConstraints GetFakeConstraints() {
fuchsia::sysmem::BufferCollectionConstraints constraints;
constraints.min_buffer_count_for_camping = kBufferCountForCamping;
constraints.image_format_constraints_count = 1;
auto& image_constraints = constraints.image_format_constraints[0];
image_constraints.pixel_format.type = fuchsia::sysmem::PixelFormatType::NV12;
image_constraints.pixel_format.type = fuchsia::sysmem::PixelFormatType::NV12;
image_constraints.min_coded_width = kFakeImageMinWidth;
image_constraints.max_coded_width = kFakeImageMaxWidth;
image_constraints.min_coded_height = kFakeImageMinHeight;
image_constraints.max_coded_height = kFakeImageMaxHeight;
image_constraints.min_bytes_per_row = kFakeImageMinBytesPerRow;
image_constraints.max_bytes_per_row = kFakeImageMaxBytesPerRow;
image_constraints.layers = kNumberOfLayers;
image_constraints.bytes_per_row_divisor = kFakeImageBytesPerRowDivisor;
image_constraints.color_spaces_count = 1;
image_constraints.color_space[0].type = fuchsia::sysmem::ColorSpaceType::REC601_PAL;
constraints.usage.video = fuchsia::sysmem::videoUsageHwEncoder;
return constraints;
}
class CameraManagerTest : public gtest::RealLoopFixture {
public:
CameraManagerTest() : context_(sys::ComponentContext::Create()) {}
// testing::Test implementation.
void SetUp() override {
ASSERT_EQ(ZX_OK, context_->svc()->Connect(sysmem_allocator_.NewRequest()));
ASSERT_EQ(ZX_OK, context_->svc()->Connect(camera_manager_.NewRequest()));
}
void TearDown() override {
if (buffer_collection_.is_bound()) {
buffer_collection_->Close();
}
}
void GetToken(fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>* out_token) {
// Create client_token which we'll hold on to to get our buffer_collection.
fuchsia::sysmem::BufferCollectionTokenSyncPtr client_token;
// Create camera_token to send to the camera manager
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> camera_token;
// Start the allocation process
ASSERT_EQ(ZX_OK, sysmem_allocator_->AllocateSharedCollection(client_token.NewRequest()));
// Duplicate the token:
client_token->Duplicate(std::numeric_limits<uint32_t>::max(), camera_token.NewRequest());
ASSERT_EQ(ZX_OK, client_token->Sync());
// Now convert our side into a Logical BufferCollection:
sysmem_allocator_->BindSharedCollection(client_token.Unbind(), buffer_collection_.NewRequest());
ASSERT_EQ(ZX_OK, buffer_collection_->SetConstraints(true, GetFakeConstraints()));
*out_token = std::move(camera_token);
}
protected:
fuchsia::sysmem::BufferCollectionSyncPtr buffer_collection_;
std::unique_ptr<sys::ComponentContext> context_;
fuchsia::camera2::ManagerSyncPtr camera_manager_;
fuchsia::sysmem::AllocatorSyncPtr sysmem_allocator_;
};
TEST_F(CameraManagerTest, CanConnectToStream) {
EXPECT_EQ(ZX_OK, camera_manager_->AcknowledgeDeviceEvent());
fuchsia::camera2::StreamProperties stream_properties{};
stream_properties.set_stream_type(fuchsia::camera2::CameraStreamType::MONITORING);
fuchsia::camera2::StreamConstraints constraints{};
constraints.set_properties(std::move(stream_properties));
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> token;
fuchsia::camera2::StreamPtr stream;
fuchsia::sysmem::ImageFormat_2 format;
GetToken(&token);
ASSERT_EQ(ZX_OK, camera_manager_->ConnectToStream(0, std::move(constraints), std::move(token),
stream.NewRequest(), &format));
// Check that the other side of the stream channel has not been closed. This is the
// signal that the interface gives that ConnectToStream failed.
ASSERT_EQ(ZX_ERR_TIMED_OUT,
stream.channel().wait_one(ZX_CHANNEL_PEER_CLOSED, zx::time::infinite_past(), nullptr))
<< "CameraManagerTest::CanConnectToStream: Failed to connect to stream";
bool passed = false;
bool stream_failure = false;
stream.set_error_handler([&stream_failure](zx_status_t status) {
stream_failure = true;
FX_PLOGS(ERROR, status) << "Stream failed with error ";
});
stream.events().OnFrameAvailable = [&passed](fuchsia::camera2::FrameAvailableInfo frame) {
passed = true;
};
stream->Start();
RunLoopUntil([&passed, &stream_failure]() { return passed || stream_failure; });
EXPECT_TRUE(passed);
}
} // namespace