From 895b7306d837862b7fe1b706bb26307007f69c32 Mon Sep 17 00:00:00 2001 From: Marius Vlad Date: Fri, 24 Nov 2023 14:59:17 +0200 Subject: [PATCH] app: Convert to meson build system and use gRPC This converts to using newer meson build system, and makes use of gRPC API rather using native agl-shell-desktop protocol. We still need to use wayland for window set-up so xdg-shell is still there and supported. Bug-AGL: SPEC-4987 Signed-off-by: Marius Vlad Change-Id: I81eefe103c67b8d490fd33c14cc8f4b04feceaed --- app/AglShellGrpcClient.cpp | 208 ++++++++++++++++++++++++++++++++++++++++++ app/AglShellGrpcClient.h | 114 +++++++++++++++++++++++ app/CMakeLists.txt | 121 ------------------------ app/main.cpp | 56 +----------- app/meson.build | 120 ++++++++++++++++++++++++ app/protocol/agl_shell.proto | 110 ++++++++++++++++++++++ CMakeLists.txt => meson.build | 25 +++-- 7 files changed, 576 insertions(+), 178 deletions(-) create mode 100644 app/AglShellGrpcClient.cpp create mode 100644 app/AglShellGrpcClient.h delete mode 100644 app/CMakeLists.txt create mode 100644 app/meson.build create mode 100644 app/protocol/agl_shell.proto rename CMakeLists.txt => meson.build (57%) diff --git a/app/AglShellGrpcClient.cpp b/app/AglShellGrpcClient.cpp new file mode 100644 index 0000000..8577f16 --- /dev/null +++ b/app/AglShellGrpcClient.cpp @@ -0,0 +1,208 @@ +//include stuff here +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "AglShellGrpcClient.h" +#include "agl_shell.grpc.pb.h" + +using namespace std::chrono; + +namespace { + const char kDefaultGrpcServiceAddress[] = "127.0.0.1:14005"; +} + +GrpcClient::GrpcClient() +{ + m_channel = grpc::CreateChannel(kDefaultGrpcServiceAddress, + grpc::InsecureChannelCredentials()); + + // init the stub here + m_stub = agl_shell_ipc::AglShellManagerService::NewStub(m_channel); + reader = new Reader(m_stub.get()); +} + +void +GrpcClient::WaitForConnected(int wait_time_ms, int tries_timeout) +{ + struct timespec ts; + grpc_connectivity_state state; + int try_ = 0; + + clock_gettime(CLOCK_MONOTONIC, &ts); + ts.tv_sec = 0; + ts.tv_nsec = 500 * 1000 * 1000; // 500ms + + while (((state = m_channel->GetState(true)) != GRPC_CHANNEL_READY) && + try_++ < tries_timeout) { + fprintf(stderr, "waiting for channel state to be ready, current state %d", state); + nanosleep(&ts, NULL); + } + +} + + +bool +GrpcClient::ActivateApp(const std::string& app_id, const std::string& output_name) +{ + agl_shell_ipc::ActivateRequest request; + + request.set_app_id(app_id); + request.set_output_name(output_name); + + grpc::ClientContext context; + ::agl_shell_ipc::ActivateResponse reply; + + grpc::Status status = m_stub->ActivateApp(&context, request, &reply); + return status.ok(); +} + +bool +GrpcClient::DeactivateApp(const std::string& app_id) +{ + agl_shell_ipc::DeactivateRequest request; + + request.set_app_id(app_id); + + grpc::ClientContext context; + ::agl_shell_ipc::DeactivateResponse reply; + + grpc::Status status = m_stub->DeactivateApp(&context, request, &reply); + return status.ok(); +} + +bool +GrpcClient::SetAppFloat(const std::string& app_id, int32_t x_pos, int32_t y_pos) +{ + agl_shell_ipc::FloatRequest request; + + request.set_app_id(app_id); + + request.set_x_pos(x_pos); + request.set_y_pos(y_pos); + + grpc::ClientContext context; + ::agl_shell_ipc::FloatResponse reply; + + grpc::Status status = m_stub->SetAppFloat(&context, request, &reply); + return status.ok(); +} + +bool +GrpcClient::SetAppNormal(const std::string& app_id) +{ + agl_shell_ipc::NormalRequest request; + + request.set_app_id(app_id); + + grpc::ClientContext context; + ::agl_shell_ipc::NormalResponse reply; + + grpc::Status status = m_stub->SetAppNormal(&context, request, &reply); + return status.ok(); +} + +bool +GrpcClient::SetAppFullscreen(const std::string& app_id) +{ + agl_shell_ipc::FullscreenRequest request; + + request.set_app_id(app_id); + + grpc::ClientContext context; + ::agl_shell_ipc::FullscreenResponse reply; + + grpc::Status status = m_stub->SetAppFullscreen(&context, request, &reply); + return status.ok(); +} + +bool +GrpcClient::SetAppOnOutput(const std::string& app_id, const std::string &output) +{ + agl_shell_ipc::AppOnOutputRequest request; + + request.set_app_id(app_id); + request.set_output(output); + + grpc::ClientContext context; + ::agl_shell_ipc::AppOnOutputResponse reply; + + grpc::Status status = m_stub->SetAppOnOutput(&context, request, &reply); + return status.ok(); +} + +bool +GrpcClient::SetAppPosition(const std::string& app_id, int32_t x, int32_t y) +{ + agl_shell_ipc::AppPositionRequest request; + + request.set_app_id(app_id); + request.set_x(x); + request.set_y(y); + + grpc::ClientContext context; + ::agl_shell_ipc::AppPositionResponse reply; + + grpc::Status status = m_stub->SetAppPosition(&context, request, &reply); + return status.ok(); +} + +bool +GrpcClient::SetAppScale(const std::string& app_id, int32_t width, int32_t height) +{ + agl_shell_ipc::AppScaleRequest request; + + request.set_app_id(app_id); + request.set_width(width); + request.set_height(height); + + grpc::ClientContext context; + ::agl_shell_ipc::AppScaleResponse reply; + + grpc::Status status = m_stub->SetAppScale(&context, request, &reply); + return status.ok(); +} + + +grpc::Status +GrpcClient::Wait(void) +{ + return reader->Await(); +} + +void +GrpcClient::AppStatusState(Callback callback, void *data) +{ + reader->AppStatusState(callback, data); +} + +std::vector +GrpcClient::GetOutputs() +{ + grpc::ClientContext context; + std::vector v; + + ::agl_shell_ipc::OutputRequest request; + ::agl_shell_ipc::ListOutputResponse response; + + grpc::Status status = m_stub->GetOutputs(&context, request, &response); + if (!status.ok()) + return std::vector(); + + for (int i = 0; i < response.outputs_size(); i++) { + ::agl_shell_ipc::OutputResponse rresponse = response.outputs(i); + v.push_back(rresponse.name()); + } + + return v; +} diff --git a/app/AglShellGrpcClient.h b/app/AglShellGrpcClient.h new file mode 100644 index 0000000..19cfb75 --- /dev/null +++ b/app/AglShellGrpcClient.h @@ -0,0 +1,114 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "agl_shell.grpc.pb.h" + +typedef void (*Callback)(agl_shell_ipc::AppStateResponse app_response, void *data); + +class Reader : public grpc::ClientReadReactor<::agl_shell_ipc::AppStateResponse> { +public: + Reader(agl_shell_ipc::AglShellManagerService::Stub *stub) + : m_stub(stub) + { + } + + void AppStatusState(Callback callback, void *_data) + { + ::agl_shell_ipc::AppStateRequest request; + + // set up the callback + m_callback = callback; + m_data = _data; + m_stub->async()->AppStatusState(&m_context, &request, this); + + StartRead(&m_app_state); + StartCall(); + } + + void OnReadDone(bool ok) override + { + if (ok) { + m_callback(m_app_state, m_data); + + // blocks in StartRead() if the server doesn't send + // antyhing + StartRead(&m_app_state); + } + } + + void SetDone() + { + fprintf(stderr, "%s()\n", __func__); + std::unique_lock l(m_mutex); + m_done = true; + } + + void OnDone(const grpc::Status& s) override + { + fprintf(stderr, "%s()\n", __func__); + std::unique_lock l(m_mutex); + + m_status = s; + + fprintf(stderr, "%s() done\n", __func__); + m_cv.notify_one(); + } + + grpc::Status Await() + { + std::unique_lock l(m_mutex); + + m_cv.wait(l, [this] { return m_done; }); + + return std::move(m_status); + } +private: + grpc::ClientContext m_context; + ::agl_shell_ipc::AppStateResponse m_app_state; + void *m_data; + agl_shell_ipc::AglShellManagerService::Stub *m_stub; + + Callback m_callback; + + + std::mutex m_mutex; + std::condition_variable m_cv; + grpc::Status m_status; + bool m_done = false; +}; + +class GrpcClient { +public: + GrpcClient(); + void WaitForConnected(int wait_time_ms, int tries_timeout); + bool ActivateApp(const std::string& app_id, const std::string& output_name); + bool DeactivateApp(const std::string& app_id); + bool SetAppFloat(const std::string& app_id, int32_t x_pos, int32_t y_pos); + bool SetAppFullscreen(const std::string& app_id); + bool SetAppOnOutput(const std::string& app_id, const std::string& output); + bool SetAppNormal(const std::string& app_id); + bool SetAppPosition(const std::string& app_id, int32_t x, int32_t y); + bool SetAppScale(const std::string& app_id, int32_t width, int32_t height); + std::vector GetOutputs(); + void GetAppState(); + void AppStatusState(Callback callback, void *data); + grpc::Status Wait(); + +private: + Reader *reader; + std::unique_ptr m_stub; + std::shared_ptr m_channel; +}; + diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt deleted file mode 100644 index d7935f3..0000000 --- a/app/CMakeLists.txt +++ /dev/null @@ -1,121 +0,0 @@ -########################################################################### -# Copyright 2018,2022 Konsulko Group -# Copyright 2020 Collabora, Ltd. -# -# Author: Scott Murray -# Author: Marius Vlad -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -########################################################################### - -project(camera-gstreamer) - -if(CMAKE_VERSION VERSION_LESS "3.7.0") - set(CMAKE_INCLUDE_CURRENT_DIR ON) -endif() - -set(CMAKE_CXX_STANDARD 14) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -find_package(PkgConfig REQUIRED) -find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner) - -add_custom_command( - OUTPUT agl-shell-desktop-client-protocol.h - COMMAND ${WAYLAND_SCANNER_EXECUTABLE} client-header - < ${CMAKE_SOURCE_DIR}/app/protocol/agl-shell-desktop.xml - > ${CMAKE_SOURCE_DIR}/app/agl-shell-desktop-client-protocol.h - DEPENDS ${CMAKE_SOURCE_DIR}/app/protocol/agl-shell-desktop.xml -) - -add_custom_command( - OUTPUT ${CMAKE_BINARY_DIR}/app/agl-shell-desktop-client-protocol.h - COMMAND ${WAYLAND_SCANNER_EXECUTABLE} client-header - < ${CMAKE_SOURCE_DIR}/app/protocol/agl-shell-desktop.xml - > ${CMAKE_SOURCE_DIR}/app/agl-shell-desktop-client-protocol.h - DEPENDS ${CMAKE_SOURCE_DIR}/app/protocol/agl-shell-desktop.xml -) - -add_custom_command( - OUTPUT agl-shell-desktop-protocol.c - COMMAND ${WAYLAND_SCANNER_EXECUTABLE} code - < ${CMAKE_SOURCE_DIR}/app/protocol/agl-shell-desktop.xml - > ${CMAKE_BINARY_DIR}/app/agl-shell-desktop-protocol.c - DEPENDS ${CMAKE_SOURCE_DIR}/app/protocol/agl-shell-desktop.xml -) - -pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0) -pkg_check_modules(GSTREAMER_PLUGINS_BASE REQUIRED gstreamer-plugins-base-1.0) -pkg_check_modules(GSTREAMER_VIDEO REQUIRED gstreamer-video-1.0) -pkg_check_modules(GSTREAMER_PLUGINS_BAD REQUIRED gstreamer-plugins-bad-1.0) - -pkg_check_modules(WAYLAND_CLIENT REQUIRED wayland-client) -pkg_check_modules(WAYLAND_PROTOCOLS REQUIRED wayland-protocols>=1.18) -pkg_get_variable(WAYLAND_PROTOCOLS_BASE wayland-protocols pkgdatadir) - -add_custom_command( - OUTPUT xdg-shell-client-protocol.h - COMMAND ${WAYLAND_SCANNER_EXECUTABLE} client-header - < ${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml - > ${CMAKE_SOURCE_DIR}/app/xdg-shell-client-protocol.h - DEPENDS ${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml -) - -add_custom_command( - OUTPUT ${CMAKE_BINARY_DIR}/app/xdg-shell-client-protocol.h - COMMAND ${WAYLAND_SCANNER_EXECUTABLE} client-header - < ${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml - > ${CMAKE_SOURCE_DIR}/app/xdg-shell-client-protocol.h - DEPENDS ${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml -) - -add_custom_command( - OUTPUT xdg-shell-protocol.c - COMMAND ${WAYLAND_SCANNER_EXECUTABLE} code - < ${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml - > ${CMAKE_BINARY_DIR}/app/xdg-shell-protocol.c - DEPENDS ${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml -) - -add_executable(${PROJECT_NAME} - main.cpp - utils.h - utils.cpp - agl-shell-desktop-protocol.c - agl-shell-desktop-client-protocol.h - xdg-shell-protocol.c - xdg-shell-client-protocol.h - ${RESOURCES} -) - -include_directories( - "${GSTREAMER_INCLUDE_DIRS}" - "${GSTREAMER_PLUGINS_BASE_INCLUDE_DIRS}" - "${GSTREAMER_PLUGINS_BAD_INCLUDE_DIRS}" - "${GSTREAMER_VIDEO_INCLUDE_DIRS}" -) - -target_link_libraries(${PROJECT_NAME} - ${GSTREAMER_LIBRARIES} - "${GSTREAMER_PLUGINS_BASE_LIBRARIES}" - "${GSTREAMER_PLUGINS_BAD_LIBRARIES}" - "${GSTREAMER_VIDEO_LIBRARIES}" - ${WAYLAND_CLIENT_LIBRARIES} - -lgstwayland-1.0 -) - -install(TARGETS ${PROJECT_NAME} DESTINATION bin) -include(GNUInstallDirs) -install(FILES ${PROJECT_NAME}.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) -install(FILES still-image.jpg DESTINATION ${CMAKE_INSTALL_DATADIR}/applications/data) -add_definitions(-DAPP_DATA_PATH=${CMAKE_INSTALL_FULL_DATADIR}/applications/data) diff --git a/app/main.cpp b/app/main.cpp index 83f7c28..0247d3e 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -14,9 +14,8 @@ #include #include -#include "xdg-shell-client-protocol.h" -#include "agl-shell-desktop-client-protocol.h" #include "utils.h" +#include "xdg-shell-client-protocol.h" #include @@ -28,6 +27,10 @@ #define gst_wl_display_handle_context_new gst_wayland_display_handle_context_new #endif +#ifndef APP_DATA_PATH +#define APP_DATA_PATH /usr/share/applications/data +#endif + // these only applies if the window is a dialog/pop-up one // by default the compositor make the window maximized #define WINDOW_WIDTH_SIZE 640 @@ -57,8 +60,6 @@ struct display { } output_data; struct xdg_wm_base *wm_base; - struct agl_shell_desktop *agl_shell_desktop; - int has_xrgb; }; @@ -366,32 +367,6 @@ static const struct wl_output_listener output_listener = { display_handle_scale }; -static void -application_id(void *data, struct agl_shell_desktop *agl_shell_desktop, - const char *app_id) -{ - (void) data; - (void) agl_shell_desktop; - (void) app_id; -} - -static void -application_id_state(void *data, struct agl_shell_desktop *agl_shell_desktop, - const char *app_id, const char *app_data, - uint32_t app_state, uint32_t app_role) -{ - (void) data; - (void) app_data; - (void) agl_shell_desktop; - (void) app_id; - (void) app_state; - (void) app_role; -} - -static const struct agl_shell_desktop_listener agl_shell_desktop_listener = { - application_id, - application_id_state, -}; static void registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, @@ -411,12 +386,6 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, d->shm = static_cast(wl_registry_bind(registry, id, &wl_shm_interface, 1)); wl_shm_add_listener(d->shm, &shm_listener, d); - } else if (strcmp(interface, "agl_shell_desktop") == 0) { - d->agl_shell_desktop = static_cast(wl_registry_bind(registry, id, - &agl_shell_desktop_interface, 1)); - /* as an example, show how to register for events from the compositor */ - agl_shell_desktop_add_listener(d->agl_shell_desktop, - &agl_shell_desktop_listener, d); } else if (strcmp(interface, "wl_output") == 0) { d->wl_output = static_cast(wl_registry_bind(registry, id, &wl_output_interface, 1)); @@ -682,11 +651,6 @@ create_display(int argc, char *argv[]) return NULL; } - if (display->agl_shell_desktop == NULL) { - fprintf(stderr, "No agl_shell extension present\n"); - return NULL; - } - wl_display_roundtrip(display->wl_display); if (!display->has_xrgb) { @@ -706,9 +670,6 @@ destroy_display(struct display *display) if (display->wm_base) xdg_wm_base_destroy(display->wm_base); - if (display->agl_shell_desktop) - agl_shell_desktop_destroy(display->agl_shell_desktop); - if (display->wl_compositor) wl_compositor_destroy(display->wl_compositor); @@ -819,13 +780,6 @@ int main(int argc, char* argv[]) if (!display) return -1; - // if you'd want to place the video in a pop-up/dialog type of window: - // agl_shell_desktop_set_app_property(display->agl_shell_desktop, app_id, - // AGL_SHELL_DESKTOP_APP_ROLE_POPUP, - // WINDOW_WIDTH_POS_X, WINDOW_WIDTH_POS_Y, - // 0, 0, WINDOW_WIDTH_SIZE, WINDOW_HEIGHT_SIZE, - // display->wl_output); - // we use the role to set a correspondence between the top level // surface and our application, with the previous call letting the // compositor know that we're one and the same diff --git a/app/meson.build b/app/meson.build new file mode 100644 index 0000000..2eba85c --- /dev/null +++ b/app/meson.build @@ -0,0 +1,120 @@ +cpp = meson.get_compiler('cpp') +dep_wayland_client = dependency('wayland-client', version: '>= 1.20.0') + +dep_wp = dependency('wayland-protocols', version: '>= 1.24') +dir_wp_base = dep_wp.get_pkgconfig_variable('pkgdatadir') + +grpcpp_reflection_dep = cpp.find_library('grpc++_reflection') +protoc = find_program('protoc') +grpc_cpp = find_program('grpc_cpp_plugin') + +dep_scanner = dependency('wayland-scanner') +prog_scanner = find_program('wayland-scanner') + +protoc_gen = generator(protoc, \ + output : ['@BASENAME@.pb.cc', '@BASENAME@.pb.h'], + arguments : ['--proto_path=@CURRENT_SOURCE_DIR@/protocol', + '--cpp_out=@BUILD_DIR@', + '@INPUT@']) + +generated_protoc_sources = protoc_gen.process('protocol/agl_shell.proto') + +grpc_gen = generator(protoc, \ + output : ['@BASENAME@.grpc.pb.cc', '@BASENAME@.grpc.pb.h'], + arguments : ['--proto_path=@CURRENT_SOURCE_DIR@/protocol', + '--grpc_out=@BUILD_DIR@', + '--plugin=protoc-gen-grpc=' + grpc_cpp.path(), + '@INPUT@']) + +generated_grpc_sources = grpc_gen.process('protocol/agl_shell.proto') + +grpc_deps = [ + dependency('protobuf'), + dependency('grpc'), + dependency('grpc++'), + grpcpp_reflection_dep, +] + + +protocols = [ + [ 'xdg-shell', 'stable' ], +] + +foreach proto: protocols + proto_name = proto[0] + if proto[1] == 'internal' + base_file = proto_name + xml_path = '@0@.xml'.format(proto_name) + elif proto[1] == 'stable' + base_file = proto_name + xml_path = '@0@/stable/@1@/@1@.xml'.format(dir_wp_base, base_file) + else + base_file = '@0@-unstable-@1@'.format(proto_name, proto[1]) + xml_path = '@0@/unstable/@1@/@2@.xml'.format(dir_wp_base, proto_name, base_file) + endif + + foreach output_type: [ 'client-header', 'server-header', 'private-code' ] + if output_type == 'client-header' + output_file = '@0@-client-protocol.h'.format(base_file) + elif output_type == 'server-header' + output_file = '@0@-server-protocol.h'.format(base_file) + else + output_file = '@0@-protocol.c'.format(base_file) + if dep_scanner.version().version_compare('< 1.14.91') + output_type = 'code' + endif + endif + + var_name = output_file.underscorify() + target = custom_target( + '@0@ @1@'.format(base_file, output_type), + command: [ prog_scanner, output_type, '@INPUT@', '@OUTPUT@' ], + input: xml_path, + output: output_file, + ) + + set_variable(var_name, target) + endforeach +endforeach + +depnames_gstreamer = [ + 'gstreamer-1.0', 'gstreamer-plugins-bad-1.0', 'gstreamer-wayland-1.0', + 'gstreamer-video-1.0', 'gstreamer-plugins-base-1.0', +] + +deps_gstreamer = [] +foreach depname : depnames_gstreamer + dep = dependency(depname, required: false) + if not dep.found() + error('Required @0@ which was not found. '.format(depname) + user_hint) + endif + deps_gstreamer += dep +endforeach + + +camera_gstreamer_dep = [ + dep_wayland_client, + deps_gstreamer, + grpc_deps +] + +camera_gstreamer_src_headers = [ + xdg_shell_client_protocol_h, + 'utils.h', + 'AglShellGrpcClient.h', +] + +camera_gstreamer_src = [ + xdg_shell_protocol_c, + 'utils.cpp', + 'AglShellGrpcClient.cpp', + 'main.cpp', + generated_protoc_sources, + generated_grpc_sources +] + +install_data('still-image.jpg', install_dir: get_option('datadir') / 'applications/data') + +executable('camera-gstreamer', camera_gstreamer_src, camera_gstreamer_src_headers, + dependencies : camera_gstreamer_dep, + install: true) diff --git a/app/protocol/agl_shell.proto b/app/protocol/agl_shell.proto new file mode 100644 index 0000000..c4f3dfe --- /dev/null +++ b/app/protocol/agl_shell.proto @@ -0,0 +1,110 @@ +syntax = "proto3"; +// using empty Response suitable better for forward compat +//import "google/protobuf/empty.proto"; +package agl_shell_ipc; + +service AglShellManagerService { + rpc ActivateApp(ActivateRequest) returns (ActivateResponse) {} + rpc DeactivateApp(DeactivateRequest) returns (DeactivateResponse) {} + rpc SetAppSplit(SplitRequest) returns (SplitResponse) {} + rpc SetAppFloat(FloatRequest) returns (FloatResponse) {} + rpc SetAppFullscreen(FullscreenRequest) returns (FullscreenResponse) {} + rpc AppStatusState(AppStateRequest) returns (stream AppStateResponse) {} + rpc GetOutputs(OutputRequest) returns (ListOutputResponse) {} + rpc SetAppNormal(NormalRequest) returns (NormalResponse) {} + rpc SetAppOnOutput(AppOnOutputRequest) returns (AppOnOutputResponse) {} + rpc SetAppPosition(AppPositionRequest) returns (AppPositionResponse) {} + rpc SetAppScale(AppScaleRequest) returns (AppScaleResponse) {} +} + +message ActivateRequest { + string app_id = 1; + string output_name = 2; +} + +message ActivateResponse { +}; + + +message DeactivateRequest { + string app_id = 1; +} + +message DeactivateResponse { +} + +message SplitRequest { + string app_id = 1; + int32 tile_orientation = 2; +} + +message SplitResponse { +} + +message FloatRequest { + string app_id = 1; + int32 x_pos = 2; + int32 y_pos = 3; +} + +message FloatResponse { +} + +message AppStateRequest { +} + +message AppStateResponse { + int32 state = 1; + string app_id = 2; +} + +message OutputRequest { +}; + +message OutputResponse { + string name = 1; +}; + +message ListOutputResponse { + repeated OutputResponse outputs = 1; +}; + +message NormalRequest { + string app_id = 1; +}; + +message NormalResponse { +}; + +message FullscreenRequest { + string app_id = 1; +}; + +message FullscreenResponse { +}; + +message AppOnOutputRequest { + string app_id = 1; + string output = 2; +}; + +message AppOnOutputResponse { +}; + +message AppPositionRequest { + string app_id = 1; + int32 x = 2; + int32 y = 3; +}; + +message AppPositionResponse { +}; + +message AppScaleRequest { + string app_id = 1; + int32 width = 2; + int32 height = 3; +}; + +message AppScaleResponse { +}; diff --git a/CMakeLists.txt b/meson.build similarity index 57% rename from CMakeLists.txt rename to meson.build index c21c5bf..f941aee 100644 --- a/CMakeLists.txt +++ b/meson.build @@ -1,19 +1,32 @@ -# Copyright 2021 Collabora, Ltd. -# Copyright 2022 Konsulko Group +# +# Copyright ©, 2023 Collabora, Ltd. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -########################################################################### +# -CMAKE_MINIMUM_REQUIRED(VERSION 3.3) +project ( + 'camera-gstreamer', + ['c', 'cpp'], + version : '1.0.0', + license : 'Apache-2.0', + meson_version : '>= 0.60.0', + default_options : + [ + 'warning_level=1', + 'buildtype=debugoptimized', + 'c_std=c17', + 'cpp_std=c++17' + ], +) -add_subdirectory(app) +subdir('app') -- 2.16.6