diff options
author | Jan-Simon Moeller <jsmoeller@linuxfoundation.org> | 2019-07-09 08:13:54 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@automotivelinux.org> | 2019-07-09 08:13:54 +0000 |
commit | 6b673b5726dea2d2f8d39caee34d0ca850cc146e (patch) | |
tree | 189b961689a2f3b0de09c46a4b1db08b06021149 | |
parent | 2e0789fdb4141807b9367787e3bb4098c40f7e2a (diff) | |
parent | 3344b0a0696c2670ccdc7fa9fb619efdf3764fca (diff) |
Merge "receiver: Introduce waltham-receiver"halibut_8.0.0halibut_7.99.3halibut/8.0.0halibut/7.99.38.0.07.99.3
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | waltham-receiver/CMakeLists.txt | 82 | ||||
-rw-r--r-- | waltham-receiver/README.md | 126 | ||||
-rw-r--r-- | waltham-receiver/include/bitmap.h | 35 | ||||
-rw-r--r-- | waltham-receiver/include/os-compatibility.h | 58 | ||||
-rw-r--r-- | waltham-receiver/include/wth-receiver-comm.h | 549 | ||||
-rw-r--r-- | waltham-receiver/receiver_pipeline_example_general.cfg | 1 | ||||
-rw-r--r-- | waltham-receiver/receiver_pipeline_example_intel.cfg | 1 | ||||
-rw-r--r-- | waltham-receiver/receiver_pipeline_example_rcar.cfg | 1 | ||||
-rw-r--r-- | waltham-receiver/src/utils/bitmap.c | 107 | ||||
-rw-r--r-- | waltham-receiver/src/utils/os-compatibility.c | 204 | ||||
-rw-r--r-- | waltham-receiver/src/wth-receiver-comm.c | 1176 | ||||
-rw-r--r-- | waltham-receiver/src/wth-receiver-gst.c | 879 | ||||
-rw-r--r-- | waltham-receiver/src/wth-receiver-main.c | 334 |
14 files changed, 3554 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 00fd14e..085d3e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,4 @@ project (weston-ivi-plugins) add_subdirectory(waltham-transmitter) +add_subdirectory(waltham-receiver) diff --git a/waltham-receiver/CMakeLists.txt b/waltham-receiver/CMakeLists.txt new file mode 100644 index 0000000..fc6331e --- /dev/null +++ b/waltham-receiver/CMakeLists.txt @@ -0,0 +1,82 @@ +cmake_minimum_required( VERSION 2.8.5 ) + +project (waltham-receiver) + +find_package(PkgConfig) +find_package (Threads) +pkg_check_modules(WAYLAND_CLIENT wayland-client REQUIRED) +pkg_check_modules(WAYLAND_CURSOR wayland-cursor REQUIRED) +pkg_check_modules(WALTHAM waltham REQUIRED) +pkg_check_modules(GLESv2 glesv2 REQUIRED) +pkg_check_modules(WAYLAND_EGL wayland-egl REQUIRED) +pkg_search_module(EGL egl required) +pkg_search_module(GSTREAMER gstreamer-1.0 required) +pkg_search_module(GSTREAMERAPP gstreamer-app-1.0 required) +pkg_search_module(DRM libdrm required) +pkg_check_modules(IVI-APPLICATION ivi-application REQUIRED) + +find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner) +find_library(GST_ALLOCATOR NAMES gstallocators-1.0 PATHs /usr/lib64) +find_library(GST_VIDEO NAMES gstvideo-1.0 PATHs /usr/lib64) +find_library(GSTREAMER_WAYLANDSINK NAMES gstwayland-1.0 PATHs ${LIBS}) + +include_directories( + ${WAYLAND_CLIENT_INCLUDE_DIR} + ${WAYLAND_CURSOR_INCLUDE_DIR} + ${WALTHAM_INCLUDE_DIRS} + ${DRM_INCLUDE_DIRS} + ${GSTREAMER_LIBRARY_DIRS} + ${GSTREAMER_INCLUDE_DIRS} + ${GSTREAMERAPP_INCLUDE_DIRS} + ${EGL_INCLUDE_DIRS} + ${WAYLAND_EGL_INCLUDE_DIR} + ${GLESv2_INCLUDE_DIRS} + ${IVI-APPLICATION_INCLUDE_DIRS} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/waltham-receiver/include/ + ${CMAKE_SOURCE_DIR}/waltham-transmitter/waltham-renderer +) + +link_directories( + ${WAYLAND_CLIENT_LIBRARY_DIRS} + ${WAYLAND_CURSOR_LIBRARY_DIRS} + ${WALTHAM_LIBRARY_DIRS} + ${EGL_LIBRARY_DIRS} + ${WAYLAND_EGL_LIBRAY_DIRS} + ${GLESv2_LIBRARY_DIRS} + ${GSTREAMER_LIBRARY_DIRS} + ${GSTREAMERAPP_LIBRARY_DIRS} + ${IVI-APPLICATION_LIBRARY_DIRS} +) + +SET(LIBS + ${CMAKE_THREAD_LIBS_INIT} + ${WAYLAND_CLIENT_LIBRARIES} + ${WAYLAND_CURSOR_LIBRARIES} + ${WALTHAM_LIBRARIES} + ${EGL_LIBRARIES} + ${WAYLAND_EGL_LIBRARIES} + ${GLESv2_LIBRARIES} + ${GSTREAMER_LIBRARIES} + ${GSTREAMERAPP_LIBRARIES} + ${GST_ALLOCATOR} + ${GST_VIDEO} + ${IVI-APPLICATION_LIBRARIES} + ${GSTREAMER_WAYLANDSINK} +) + +SET(SRC_FILES + src/wth-receiver-main.c + src/wth-receiver-comm.c + src/wth-receiver-gst.c + src/utils/bitmap.c + src/utils/os-compatibility.c +) + +add_executable(${PROJECT_NAME} ${SRC_FILES}) + +add_definitions(${EGL_CFLAGS}) + +target_link_libraries(${PROJECT_NAME} ${LIBS}) + +install (TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/waltham-receiver/README.md b/waltham-receiver/README.md new file mode 100644 index 0000000..d0f63cb --- /dev/null +++ b/waltham-receiver/README.md @@ -0,0 +1,126 @@ +# Waltham-receiver + +waltham-receiver component is a receiver side implementation for using +Waltham protocol to obtain and process remote output received from +waltham-transmitter + +This component is designed to be used for evaluating the functionalities of +waltham-transmitter plugin. + +This component also acts as weston client application to display/handle various +requests from actual weston client at transmitter side. + +###Architecture + +```` + + ECU 1 ECU 2 + +-----------------------------------------------------+ +----------------------------------------------+ + | +-----------------+ | | | + | | IVI-Application | | | +-----------+-----------+ | + | +-----------------+ | | | Gstreamer | | | + | ^ | Buffer -----------------------> (Decode) | | | + | wayland | +----------------------/ | +-----------+ | | + | v | | (Ethernet) | | Waltham-receiver | | + | +----+---------------------+ | | ----------------------------> | | + | | | Transmitter Plugin |<-----------------------------/ | +-----------------------+ | + | | | | | | Waltham-Protocol | ^ | + | | | +-------------------+ | | | wayland | | + | | | | waltham-renderer |------------+ | | v | + | | | |(gstreamer Encode) | | | +---------------------+ | + | | +-+-------------------+ | | | | | + | | | | | | WESTON | | + | | WESTON | | | | | | + | +------+-------------------+ | | +----------------+----+ | + | | | | | | + | v | | v | + | +------------+ | | +----------+ | + | | Display | | | | Display | | + | | | | | | | | + | +------------+ | | +----------+ | + +-----------------------------------------------------+ +----------------------------------------------+ + +```` + +###Build Steps + + +1. Prerequisite before building + + weston, wayland, waltham and gstreamer should be built and available. + +2. In waltham-receiver directory, create build directory + + $cd waltham-receiver + $mkdir build + $cd build/ + +3. Run cmake + + $cmake ../ + $cmake --build . + +4. waltham-receiver binary should be availaible in build directory + +###Configure pipeline +You can use gstreamer pipeline as you want by configuring from "pipeline_receiver.cfg". +This file should be in the folder "/etc/xdg/weston/". + +As an example, please refer to the example file named "pipeline_receiver_example*.cfg". + + -pipeline_receiver_example_general.cfg : Does not use any HW decoder. + -pipeline_receiver_example_intel.cfg : Use Intel's HW decoder. + -pipeline_receiver_example_rcar.cfg : Use Rcar's HW decoder. + +Rename file as "pipeline_receiver.cfg" and put in correct place when you use them. + +###Connection Establishment + +1. Connect two board over ethernet. + +2. Assign IP to both the boards and check if the simple ping works. + + For example:if transmitter IP: 192.168.2.51 and Waltham-Receiver IP: 192.168.2.52 then + + $ping 192.168.2.52 (you can also ping vice versa) + +3. Make sure that IP address specified in the weston.ini under [remote-output] matches the Waltham-Receiver IP. + +4. Make sure that IP address in pipeline.cfg on the transmitter side match the Waltham-Receiver IP. + +###Basic test steps + +1. Start weston at receiver side + + $weston & + +2. Run waltham-receiver + + $waltham-receiver -p < port_number > -v & + +3. Start weston with transmitter plugin at transmitter side, run application and put it on transmitter screen.You should see the application rendered on receiver display. + +Connection established -receiver side logs: + +```` +set_sigint_handler >>> + <<< set_sigint_handler +receiver_listen >>> + <<< receiver_listen +watch_ctl >>> + <<< watch_ctl +Waltham receiver listening on TCP port 34400... +receiver_mainloop >>> +receiver_flush_clients >>> + <<< receiver_flush_clients +listen_socket_handle_data >>> +EPOLLIN evnet received. +receiver_accept_client >>> +client_create >>> +watch_ctl >>> + <<< watch_ctl +Client 0xaaaadc4cde70 connected. + <<< client_create + <<< receiver_accept_client + <<< listen_socket_handle_data +```` diff --git a/waltham-receiver/include/bitmap.h b/waltham-receiver/include/bitmap.h new file mode 100644 index 0000000..3cef52d --- /dev/null +++ b/waltham-receiver/include/bitmap.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2013 DENSO CORPORATION + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef IVICONTROLLER_BITMAP_H_ +#define IVICONTROLLER_BITMAP_H_ + +#include <stdint.h> + +int save_as_bitmap(const char *filename, + const char *buffer, + int32_t image_size, + int32_t width, + int32_t height, + int16_t bpp + ); + +#endif /* IVICONTROLLER_BITMAP_H_*/ diff --git a/waltham-receiver/include/os-compatibility.h b/waltham-receiver/include/os-compatibility.h new file mode 100644 index 0000000..690f229 --- /dev/null +++ b/waltham-receiver/include/os-compatibility.h @@ -0,0 +1,58 @@ +/* + * Copyright © 2012 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef OS_COMPATIBILITY_H +#define OS_COMPATIBILITY_H + +#include <sys/types.h> + +#ifdef HAVE_EXECINFO_H +#include <execinfo.h> +#else +static inline int +backtrace(void **buffer, int size) +{ + return 0; +} +#endif + +int +os_fd_set_cloexec(int fd); + +int +os_socketpair_cloexec(int domain, int type, int protocol, int *sv); + +int +os_epoll_create_cloexec(void); + +int +os_create_anonymous_file(off_t size); + +#ifndef HAVE_STRCHRNUL +char * +strchrnul(const char *s, int c); +#endif + +#endif /* OS_COMPATIBILITY_H */ diff --git a/waltham-receiver/include/wth-receiver-comm.h b/waltham-receiver/include/wth-receiver-comm.h new file mode 100644 index 0000000..285bacf --- /dev/null +++ b/waltham-receiver/include/wth-receiver-comm.h @@ -0,0 +1,549 @@ +/* + * Copyright © 2019 Advanced Driver Information Technology GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/******************************************************************************* +** ** +** TARGET : linux ** +** ** +** PROJECT : waltham-receiver ** +** ** +** PURPOSE : Header file declare macros, extern functions, data types etc, ** +** required to interface with waltham IPC library ** +** ** +*******************************************************************************/ + +#ifndef WTH_SERVER_WALTHAM_COMM_H_ +#define WTH_SERVER_WALTHAM_COMM_H_ + +#include <stdio.h> +#include <stdbool.h> +#include <sys/epoll.h> +#include <errno.h> +#include <netinet/in.h> +#include <string.h> +#include <assert.h> +#include <getopt.h> +#include <unistd.h> + +#include <GLES/gl.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include <wayland-egl.h> +#include <wayland-client.h> +#include <waltham-server.h> +#include <waltham-connection.h> + +#define DEBUG 0 + +struct receiver; +struct client; +struct window; +struct pointer; +struct touch; +static int verbose = 0; + +const struct wth_display_interface display_implementation; + +/** +* receiver_accept_client +* +* Accepts new waltham client connection and instantiates client structure +* +* @param names struct receiver *srv +* @param value socket connection info and client data +* @return none +*/ +void receiver_accept_client(struct receiver *srv); + +/** +* receiver_flush_clients +* +* write all the pending requests from the clients to socket +* +* @param names struct receiver *srv +* @param value socket connection info and client data +* @return none +*/ +void receiver_flush_clients(struct receiver *srv); + +/** +* client_destroy +* +* Destroy client connection +* +* @param names struct client *c +* @param value client data +* @return none +*/ +void client_destroy(struct client *c); + +/** +* waltham_pointer_enter +* +* Send pointer enter event received from weston to waltham client +* +* @param names struct window *window +* uint32_t serial +* wl_fixed_t sx +* wl_fixed_t sy +* @param value window - window information +* serial - serial number of the enter event +* sx - surface-local x coordinate +* sy - surface-local y coordinate +* @return none +*/ +void waltham_pointer_enter(struct window *window, uint32_t serial, + wl_fixed_t sx, wl_fixed_t sy); + +/** +* waltham_pointer_leave +* +* Send pointer leave event received from weston to waltham client +* +* @param names struct window *window +* uint32_t serial +* @param value window - window information +* serial - serial number of the leave event +* @return none +*/ +void waltham_pointer_leave(struct window *window, uint32_t serial); + +/** +* waltham_pointer_motion +* +* Send pointer motion event received from weston to waltham client +* +* @param names struct window *window +* uint32_t time +* wl_fixed_t sx +* wl_fixed_t sy +* @param value window - window information +* time - timestamp with millisecond granularity +* sx - surface-local x coordinate +* sy - surface-local y coordinate +* @return none +*/ +void waltham_pointer_motion(struct window *window, uint32_t time, + wl_fixed_t sx, wl_fixed_t sy); + +/** +* waltham_pointer_button +* +* Send pointer button event received from weston to waltham client +* +* @param names struct window *window +* uint32_t serial +* uint32_t time +* uint32_t button +* uint32_t state +* @param value window - window information +* serial - serial number of the button event +* time - timestamp with millisecond granularity +* button - button that produced the event +* state - physical state of the button +* @return none +*/ +void waltham_pointer_button(struct window *window, uint32_t serial, + uint32_t time, uint32_t button, + uint32_t state); + +/** +* waltham_pointer_axis +* +* Send pointer axis event received from weston to waltham client +* +* @param names struct window *window +* uint32_t time +* uint32_t axis +* wl_fixed_t value +* @param value window - window information +* time - timestamp with millisecond granularity +* axis - axis type +* value - length of vector in surface-local coordinate space +* @return none +*/ +void waltham_pointer_axis(struct window *window, uint32_t time, + uint32_t axis, wl_fixed_t value); + +/** +* waltham_touch_down +* +* Send touch down event received from weston to waltham client +* +* @param names struct window *window +* uint32_t serial +* uint32_t time +* int32_t id +* wl_fixed_t x_w +* wl_fixed_t y_w +* @param value window - window information +* serial - serial number of the touch down event +* time - timestamp with millisecond granularity +* id - the unique ID of this touch point +* x_w - surface-local x coordinate +* y_w - surface-local y coordinate +* @return none +*/ +void waltham_touch_down(struct window *window, uint32_t serial, + uint32_t time, int32_t id, + wl_fixed_t x_w, wl_fixed_t y_w); + +/** +* waltham_touch_up +* +* Send touch up event received from weston to waltham client +* +* @param names struct window *window +* uint32_t serial +* uint32_t time +* int32_t id +* @param value window - window information +* serial - serial number of the touch up event +* time - timestamp with millisecond granularity +* id - the unique ID of this touch point +* @return none +*/ +void waltham_touch_up(struct window *window, uint32_t serial, + uint32_t time, int32_t id); + +/** +* waltham_touch_motion +* +* Send touch motion event received from weston to waltham client +* +* @param names struct window *window +* uint32_t time +* int32_t id +* wl_fixed_t x_w +* wl_fixed_t y_w +* @param value window - window information +* time - timestamp with millisecond granularity +* id - the unique ID of this touch point +* x_w - surface-local x coordinate +* y_w - surface-local y coordinate +* @return none +*/ +void waltham_touch_motion(struct window *window, uint32_t time, + int32_t id, wl_fixed_t x_w, wl_fixed_t y_w); + +/** +* waltham_touch_frame +* +* Send touch frame event received from weston to waltham client +* +* @param names struct window *window +* @param value window - window information +* @return none +*/ +void waltham_touch_frame(struct window *window); + +/** +* waltham_touch_cancel +* +* Send touch cancel event received from weston to waltham client +* +* @param names struct window *window +* @param value window - window information +* @return none +*/ +void waltham_touch_cancel(struct window *window); + +/** + * set verbosity + */ +inline void set_verbosity(int verbosity) +{ + verbose = verbosity; +} + +/** + * get verbosity + */ +inline bool get_verbosity() +{ + if (verbose == 1) + { + return true; + } + else + { + return false; + } +} + +/***** macros *******/ +#define MAX_EPOLL_WATCHES 2 + +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) +#endif + +#define wl_list_last_until_empty(pos, head, member) \ + while (!wl_list_empty(head) && \ + (pos = wl_container_of((head)->prev, pos, member), 1)) + +#ifndef ARRAY_LENGTH +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) +#endif + +#ifndef pr_fmt +# define pr_fmt(fmt) fmt +#endif + +#define wth_error(fmt, ...) \ + ({ fprintf(stderr, pr_fmt(fmt), ## __VA_ARGS__); fflush(stderr); }) + +#if DEBUG +#define wth_verbose(fmt, ...) \ + ({ if (get_verbosity()) { fprintf(stdout, pr_fmt(fmt), ## __VA_ARGS__); fflush(stdout); } }) +#else +#define wth_verbose(fmt, ...)\ + ({}) +#endif + +/****** incline functions *****/ +static inline void * +zalloc(size_t size) +{ + return calloc(1, size); +} + + +/***** Data types *****/ +/* wthp_region protocol object */ +struct region { + struct wthp_region *obj; + /* pixman_region32_t region; */ + struct wl_list link; /* struct client::region_list */ +}; + +/* wthp_compositor protocol object */ +struct compositor { + struct wthp_compositor *obj; + struct client *client; + struct wl_list link; /* struct client::compositor_list */ +}; + +/* wthp_blob_factory protocol object */ +struct blob_factory { + struct wthp_blob_factory *obj; + struct client *client; + struct wl_list link; /* struct client::blob_factory_list */ +}; + +/* wthp_buffer protocol object */ +struct buffer { + struct wthp_buffer *obj; + uint32_t data_sz; + void *data; + int32_t width; + int32_t height; + int32_t stride; + uint32_t format; + struct wl_list link; /* struct client::buffer_list */ +}; + +/* wthp_seat protocol object */ +struct seat { + struct wthp_seat *obj; + struct client *client; + struct pointer *pointer; + struct keyboard *keyboard; + struct touch *touch; + struct wl_list link; /* struct client::seat_list */ +}; + +/* wthp_pointer protocol object */ +struct pointer { + struct wthp_pointer *obj; + struct seat *seat; + struct wl_list link; /* struct client::pointer_list */ +}; + +/* wthp_keyboard protocol object */ +struct keyboard { + struct wthp_keyboard *obj; + struct seat *seat; + struct wl_list link; /* struct client::keyboard_list */ +}; + +/* wthp_touch protocol object */ +struct touch { + struct wthp_touch *obj; + struct seat *seat; + struct wl_list link; /* struct client::touch_list */ +}; + +/* wthp_surface protocol object */ +struct surface { + struct wthp_surface *obj; + uint32_t ivi_id; + struct ivisurface *ivisurf; + struct wthp_callback *cb; + struct window *shm_window; + struct wl_list link; /* struct client::surface_list */ +}; +/* wthp_ivi_surface protocol object */ +struct ivisurface { + struct wthp_ivi_surface *obj; + struct wthp_callback *cb; + struct wl_list link; /* struct client::surface_list */ + struct surface *surf; +}; + +/* wthp_ivi_application protocol object */ +struct application { + struct wthp_ivi_application *obj; + struct client *client; + struct wl_list link; /* struct client::surface_list */ +}; + +/* wthp_registry protocol object */ +struct registry { + struct wthp_registry *obj; + struct client *client; + struct wl_list link; /* struct client::registry_list */ +}; + +enum wthp_seat_capability { + /** + * the seat has pointer devices + */ + WTHP_SEAT_CAPABILITY_POINTER = 1, + /** + * the seat has one or more keyboards + */ + WTHP_SEAT_CAPABILITY_KEYBOARD = 2, + /** + * the seat has touch devices + */ + WTHP_SEAT_CAPABILITY_TOUCH = 4, +}; + +/* epoll structure */ +struct watch { + struct receiver *receiver; + int fd; + void (*cb)(struct watch *w, uint32_t events); +}; + +struct client { + struct wl_list link; /* struct receiver::client_list */ + struct receiver *receiver; + + struct wth_connection *connection; + struct watch conn_watch; + + /* client object lists for clean-up on disconnection */ + struct wl_list registry_list; /* struct registry::link */ + struct wl_list compositor_list; /* struct compositor::link */ + struct wl_list region_list; /* struct region::link */ + struct wl_list surface_list; /* struct surface::link */ + struct wl_list buffer_list; /* struct buffer::link */ + struct wl_list seat_list; /* struct seat::link */ + struct wl_list pointer_list; /* struct pointer::link */ + struct wl_list touch_list; /* struct touch::link */ +}; + +/* receiver structure */ +struct receiver { + int listen_fd; + struct watch listen_watch; + + bool running; + int epoll_fd; + + struct wl_list client_list; /* struct client::link */ +}; + +struct shm_buffer { + struct wl_buffer *buffer; + void *shm_data; + int busy; +}; + +struct display { + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_shm *shm; + bool has_xrgb; + struct ivi_application *ivi_application; + + struct wl_seat *seat; + struct wl_pointer *wl_pointer; + struct wl_keyboard *wl_keyboard; + struct wl_touch *wl_touch; + struct window *window; + struct { + EGLDisplay dpy; + EGLContext ctx; + EGLConfig conf; + + PFNEGLCREATEIMAGEKHRPROC create_image; + PFNEGLDESTROYIMAGEKHRPROC destroy_image; + PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_texture_2d; + } egl; + struct { + GLuint vertex_shader; + GLuint fragment_shader; + GLuint program_object; + GLuint texture; + } gl; +}; + +struct window { + struct display *display; + struct { + GLuint rotation_uniform; + GLuint pos; + GLuint col; + } gl; + int width, height; + struct wl_surface *surface; + struct ivi_surface *ivi_surface; + struct shm_buffer buffers[2]; + struct shm_buffer *prev_buffer; + struct wl_callback *callback; + uint32_t window_frames; + uint32_t window_benchmark_time; + int wait; + struct surface *receiver_surf; + struct wl_egl_window *native; + EGLSurface egl_surface; + EGLImageKHR egl_img; + struct seat *receiver_seat; + struct pointer *receiver_pointer; + bool ready; + uint32_t id_ivisurf; +}; + + +#endif diff --git a/waltham-receiver/receiver_pipeline_example_general.cfg b/waltham-receiver/receiver_pipeline_example_general.cfg new file mode 100644 index 0000000..be4d562 --- /dev/null +++ b/waltham-receiver/receiver_pipeline_example_general.cfg @@ -0,0 +1 @@ + udpsrc port=YOUR_RECIEVER_PORT caps="application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)JPEG,payload=(int)26" ! rtpjpegdepay ! jpegdec ! waylandsink name=sink sync=true diff --git a/waltham-receiver/receiver_pipeline_example_intel.cfg b/waltham-receiver/receiver_pipeline_example_intel.cfg new file mode 100644 index 0000000..3872f28 --- /dev/null +++ b/waltham-receiver/receiver_pipeline_example_intel.cfg @@ -0,0 +1 @@ + udpsrc port=YOUR_RECIEVER_PORT caps="application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)H264,payload=(int)96" ! rtpjitterbuffer latency=0 ! rtph264depay ! h264parse config-interval=1 disable-passthrough=true ! mfxdecode ! waylandsink name=sink sync=true diff --git a/waltham-receiver/receiver_pipeline_example_rcar.cfg b/waltham-receiver/receiver_pipeline_example_rcar.cfg new file mode 100644 index 0000000..15fd4ef --- /dev/null +++ b/waltham-receiver/receiver_pipeline_example_rcar.cfg @@ -0,0 +1 @@ + udpsrc port=YOUR_RECIEVER_PORT caps="application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)H264,payload=(int)96" ! rtpjitterbuffer latency=0 ! rtph264depay ! h264parse config-interval=1 disable-passthrough=true ! omxh264dec no-reorder=true ! waylandsink name=sink diff --git a/waltham-receiver/src/utils/bitmap.c b/waltham-receiver/src/utils/bitmap.c new file mode 100644 index 0000000..2c7fdb5 --- /dev/null +++ b/waltham-receiver/src/utils/bitmap.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2013 DENSO CORPORATION + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "bitmap.h" +#include <stdio.h> + +struct __attribute__ ((__packed__)) BITMAPFILEHEADER { + char bfType[2]; + uint32_t bfSize; + uint16_t bfReserved1; + uint16_t bfReserved2; + uint32_t bfOffBits; +}; + +struct __attribute__ ((__packed__)) BITMAPINFOHEADER { + uint32_t biSize; + uint32_t biWidth; + uint32_t biHeight; + uint16_t biPlanes; + uint16_t biBitCount; + uint32_t biCompression; + uint32_t biSizeImage; + uint32_t biXPixPerMeter; + uint32_t biYPixPerMeter; + uint32_t biClrUsed; + uint32_t biClrImporant; +}; + +static void +create_file_header(struct BITMAPFILEHEADER *file_header, int32_t image_size) +{ + file_header->bfType[0] = 'B'; + file_header->bfType[1] = 'M'; + file_header->bfSize = sizeof(struct BITMAPFILEHEADER) + + sizeof(struct BITMAPINFOHEADER) + + image_size; + file_header->bfOffBits = sizeof(struct BITMAPFILEHEADER) + + sizeof(struct BITMAPINFOHEADER); +} + +static void +create_info_header(struct BITMAPINFOHEADER *info_header, int32_t image_size, int32_t width, int32_t height, int16_t bpp) +{ + info_header->biSize = sizeof(struct BITMAPINFOHEADER); + info_header->biWidth = width; + info_header->biHeight = height; + info_header->biPlanes = 1; + info_header->biBitCount = bpp; + info_header->biSizeImage = image_size; +} + +static int +write_bitmap(const char *filename, + const struct BITMAPFILEHEADER *file_header, + const struct BITMAPINFOHEADER *info_header, + const char *buffer) +{ + FILE *fp = fopen(filename, "w"); + if (fp == NULL) { + return -1; + } + + fwrite(file_header, sizeof(struct BITMAPFILEHEADER), 1, fp); + fwrite(info_header, sizeof(struct BITMAPINFOHEADER), 1, fp); + fwrite(buffer, info_header->biSizeImage, 1, fp); + + fclose(fp); + return 0; +} + +int +save_as_bitmap(const char *filename, + const char *buffer, + int32_t image_size, + int32_t width, + int32_t height, + int16_t bpp) +{ + if ((filename == NULL) || (buffer == NULL)) { + return -1; + } + + struct BITMAPFILEHEADER file_header = {}; + struct BITMAPINFOHEADER info_header = {}; + + create_file_header(&file_header, image_size); + create_info_header(&info_header, image_size, width, height, bpp); + return write_bitmap(filename, &file_header, &info_header, buffer); +} diff --git a/waltham-receiver/src/utils/os-compatibility.c b/waltham-receiver/src/utils/os-compatibility.c new file mode 100644 index 0000000..d9502e5 --- /dev/null +++ b/waltham-receiver/src/utils/os-compatibility.c @@ -0,0 +1,204 @@ +/* + * Copyright © 2012 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/epoll.h> +#include <string.h> +#include <stdlib.h> + +#include "os-compatibility.h" + +int +os_fd_set_cloexec(int fd) +{ + long flags; + + if (fd == -1) + return -1; + + flags = fcntl(fd, F_GETFD); + if (flags == -1) + return -1; + + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) + return -1; + + return 0; +} + +static int +set_cloexec_or_close(int fd) +{ + if (os_fd_set_cloexec(fd) != 0) { + close(fd); + return -1; + } + return fd; +} + +int +os_socketpair_cloexec(int domain, int type, int protocol, int *sv) +{ + int ret; + +#ifdef SOCK_CLOEXEC + ret = socketpair(domain, type | SOCK_CLOEXEC, protocol, sv); + if (ret == 0 || errno != EINVAL) + return ret; +#endif + + ret = socketpair(domain, type, protocol, sv); + if (ret < 0) + return ret; + + sv[0] = set_cloexec_or_close(sv[0]); + sv[1] = set_cloexec_or_close(sv[1]); + + if (sv[0] != -1 && sv[1] != -1) + return 0; + + close(sv[0]); + close(sv[1]); + return -1; +} + +int +os_epoll_create_cloexec(void) +{ + int fd; + +#ifdef EPOLL_CLOEXEC + fd = epoll_create1(EPOLL_CLOEXEC); + if (fd >= 0) + return fd; + if (errno != EINVAL) + return -1; +#endif + + fd = epoll_create(1); + return set_cloexec_or_close(fd); +} + +static int +create_tmpfile_cloexec(char *tmpname) +{ + int fd; + +#ifdef HAVE_MKOSTEMP + fd = mkostemp(tmpname, O_CLOEXEC); + if (fd >= 0) + unlink(tmpname); +#else + fd = mkstemp(tmpname); + if (fd >= 0) { + fd = set_cloexec_or_close(fd); + unlink(tmpname); + } +#endif + + return fd; +} + +/* + * Create a new, unique, anonymous file of the given size, and + * return the file descriptor for it. The file descriptor is set + * CLOEXEC. The file is immediately suitable for mmap()'ing + * the given size at offset zero. + * + * The file should not have a permanent backing store like a disk, + * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. + * + * The file name is deleted from the file system. + * + * The file is suitable for buffer sharing between processes by + * transmitting the file descriptor over Unix sockets using the + * SCM_RIGHTS methods. + * + * If the C library implements posix_fallocate(), it is used to + * guarantee that disk space is available for the file at the + * given size. If disk space is insufficent, errno is set to ENOSPC. + * If posix_fallocate() is not supported, program may receive + * SIGBUS on accessing mmap()'ed file contents instead. + */ +int +os_create_anonymous_file(off_t size) +{ + static const char template[] = "/weston-shared-XXXXXX"; + const char *path; + char *name; + int fd; + int ret; + + path = getenv("XDG_RUNTIME_DIR"); + if (!path) { + errno = ENOENT; + return -1; + } + + name = malloc(strlen(path) + sizeof(template)); + if (!name) + return -1; + + strcpy(name, path); + strcat(name, template); + + fd = create_tmpfile_cloexec(name); + + free(name); + + if (fd < 0) + return -1; + +#ifdef HAVE_POSIX_FALLOCATE + ret = posix_fallocate(fd, 0, size); + if (ret != 0) { + close(fd); + errno = ret; + return -1; + } +#else + ret = ftruncate(fd, size); + if (ret < 0) { + close(fd); + return -1; + } +#endif + + return fd; +} + +#ifndef HAVE_STRCHRNUL +char * +strchrnul(const char *s, int c) +{ + while (*s && *s != c) + s++; + return (char *)s; +} +#endif diff --git a/waltham-receiver/src/wth-receiver-comm.c b/waltham-receiver/src/wth-receiver-comm.c new file mode 100644 index 0000000..af42f1b --- /dev/null +++ b/waltham-receiver/src/wth-receiver-comm.c @@ -0,0 +1,1176 @@ +/* + * Copyright © 2019 Advanced Driver Information Technology GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/******************************************************************************* +** ** +** TARGET : linux ** +** ** +** PROJECT : waltham-receiver ** +** ** +** PURPOSE : This file acts as interface to waltham IPC library ** +** ** +** ** +*******************************************************************************/ + +#include "wth-receiver-comm.h" + +extern int wth_receiver_weston_main(struct window *); + +extern void wth_receiver_weston_shm_attach(struct window *, uint32_t data_sz, void * data, + int32_t width, int32_t height, int32_t stride, uint32_t format); +extern void wth_receiver_weston_shm_damage(struct window *); +extern void wth_receiver_weston_shm_commit(struct window *); + +/* + * utility functions + */ +static int +watch_ctl(struct watch *w, int op, uint32_t events) +{ + wth_verbose("%s >>> \n",__func__); + struct epoll_event ee; + + ee.events = events; + ee.data.ptr = w; + wth_verbose(" <<< %s \n",__func__); + return epoll_ctl(w->receiver->epoll_fd, op, w->fd, &ee); +} + +static void +client_post_out_of_memory(struct client *c) +{ + wth_verbose("%s >>> \n",__func__); + struct wth_display *disp; + + disp = wth_connection_get_display(c->connection); + wth_object_post_error((struct wth_object *)disp, 1, + "out of memory"); + wth_verbose(" <<< %s \n",__func__); +} + +/* + * waltham surface implementation + */ +static void +surface_destroy(struct surface *surface) +{ + wth_verbose("%s >>> \n",__func__); + wth_verbose("surface %p destroy\n", surface->obj); + + wthp_surface_free(surface->obj); + wl_list_remove(&surface->link); + free(surface); + wth_verbose(" <<< %s \n",__func__); +} + +static void +surface_handle_destroy(struct wthp_surface *wthp_surface) +{ + wth_verbose("%s >>> \n",__func__); + struct surface *surface = wth_object_get_user_data((struct wth_object *)wthp_surface); + + assert(wthp_surface == surface->obj); + + surface_destroy(surface); + wth_verbose(" <<< %s \n",__func__); +} + +static void +surface_handle_attach(struct wthp_surface *wthp_surface, + struct wthp_buffer *wthp_buffer, int32_t x, int32_t y) +{ + wth_verbose("%s >>> \n",__func__); + struct surface *surf = wth_object_get_user_data((struct wth_object *)wthp_surface); + struct buffer *buf = NULL; + + buf = container_of(wthp_buffer, struct buffer, obj); + + if (surf->ivi_id != 0) { + wth_receiver_weston_shm_attach(surf->shm_window, + buf->data_sz, + buf->data, + buf->width, + buf->height, + buf->stride, + buf->format); + + wthp_buffer_send_complete(wthp_buffer, 0); + } + wth_verbose(" <<< %s \n",__func__); +} + +static void +surface_handle_damage(struct wthp_surface *wthp_surface, + int32_t x, int32_t y, int32_t width, int32_t height) +{ + wth_verbose("%s >>> \n",__func__); + + wth_verbose("surface %p damage(%d, %d, %d, %d)\n", + wthp_surface, x, y, width, height); + + struct surface *surf = wth_object_get_user_data((struct wth_object *)wthp_surface); + + if (surf->ivi_id != 0) { + wth_receiver_weston_shm_damage(surf->shm_window); + } + wth_verbose(" <<< %s \n",__func__); +} + +static void +surface_handle_frame(struct wthp_surface *wthp_surface, + struct wthp_callback *callback) +{ + wth_verbose("%s >>> \n",__func__); + struct surface *surf = wth_object_get_user_data((struct wth_object *)wthp_surface); + wth_verbose("surface %p callback(%p)\n",wthp_surface, callback); + + surf->cb = callback; + wth_verbose(" <<< %s \n",__func__); +} + +static void +surface_handle_set_opaque_region(struct wthp_surface *wthp_surface, + struct wthp_region *region) +{ + wth_verbose("surface %p set_opaque_region(%p)\n", + wthp_surface, region); +} + +static void +surface_handle_set_input_region(struct wthp_surface *wthp_surface, + struct wthp_region *region) +{ + wth_verbose("surface %p set_input_region(%p)\n", + wthp_surface, region); +} + +static void +surface_handle_commit(struct wthp_surface *wthp_surface) +{ + wth_verbose("%s >>> \n",__func__); + + struct surface *surf = wth_object_get_user_data((struct wth_object *)wthp_surface); + wth_verbose("commit %p\n",wthp_surface); + + if (surf->ivi_id != 0) { + wth_receiver_weston_shm_commit(surf->shm_window); + } + wth_verbose(" <<< %s \n",__func__); +} + +static void +surface_handle_set_buffer_transform(struct wthp_surface *wthp_surface, + int32_t transform) +{ + wth_verbose("surface %p et_buffer_transform(%d)\n", + wthp_surface, transform); +} + +static void +surface_handle_set_buffer_scale(struct wthp_surface *wthp_surface, + int32_t scale) +{ + wth_verbose("surface %p set_buffer_scale(%d)\n", + wthp_surface, scale); +} + +static void +surface_handle_damage_buffer(struct wthp_surface *wthp_surface, + int32_t x, int32_t y, int32_t width, int32_t height) +{ + wth_verbose("surface %p damage_buffer(%d, %d, %d, %d)\n", + wthp_surface, x, y, width, height); +} + +static const struct wthp_surface_interface surface_implementation = { + surface_handle_destroy, + surface_handle_attach, + surface_handle_damage, + surface_handle_frame, + surface_handle_set_opaque_region, + surface_handle_set_input_region, + surface_handle_commit, + surface_handle_set_buffer_transform, + surface_handle_set_buffer_scale, + surface_handle_damage_buffer +}; + + +/* BEGIN wthp_region implementation */ + +static void +buffer_handle_destroy(struct wthp_buffer *wthp_buffer) +{ + struct buffer *buf = wth_object_get_user_data((struct wth_object *)wthp_buffer); + + wthp_buffer_free(wthp_buffer); + wl_list_remove(&buf->link); + free(buf); +} + +static const struct wthp_buffer_interface buffer_implementation = { + buffer_handle_destroy +}; + +/* END wthp_region implementation */ + +/* BEGIN wthp_blob_factory implementation */ + +static void +blob_factory_create_buffer(struct wthp_blob_factory *blob_factory, + struct wthp_buffer *wthp_buffer, uint32_t data_sz, void *data, + int32_t width, int32_t height, int32_t stride, uint32_t format) +{ + struct blob_factory *blob = wth_object_get_user_data((struct wth_object *)blob_factory); + struct buffer *buffer; + + + wth_verbose("wthp_blob_factory %p create_buffer(%p, %d, %p, %d, %d, %d, %d)\n", + blob_factory, wthp_buffer, data_sz, data, width, height, stride, format); + + buffer = zalloc(sizeof *buffer); + if (!buffer) { + client_post_out_of_memory(blob->client); + return; + } + + wl_list_insert(&blob->client->buffer_list, &buffer->link); + + buffer->data_sz = data_sz; + buffer->data = data; + buffer->width = width; + buffer->height = height; + buffer->stride = stride; + buffer->format = format; + buffer->obj = wthp_buffer; + + wthp_buffer_set_interface(wthp_buffer, &buffer_implementation, buffer); +} + +static const struct wthp_blob_factory_interface blob_factory_implementation = { + blob_factory_create_buffer +}; + +static void +client_bind_blob_factory(struct client *c, struct wthp_blob_factory *obj) +{ + struct blob_factory *blob; + + blob = zalloc(sizeof *blob); + if (!blob) { + client_post_out_of_memory(c); + return; + } + + blob->obj = obj; + blob->client = c; + wl_list_insert(&c->compositor_list, &blob->link); + + wthp_blob_factory_set_interface(obj, &blob_factory_implementation, + blob); + fprintf(stderr, "client %p bound wthp_blob_factory\n", c); +} + +/* + * waltam ivi surface implementation + */ +static void +wthp_ivi_surface_destroy(struct wthp_ivi_surface * ivi_surface) +{ + wth_verbose("%s >>> \n",__func__); + struct ivisurface *ivisurf = wth_object_get_user_data((struct wth_object *)ivi_surface); + free(ivisurf); + wth_verbose(" <<< %s \n",__func__); +} + +static const struct wthp_ivi_surface_interface wthp_ivi_surface_implementation = { + wthp_ivi_surface_destroy, +}; + + +/* + * waltham ivi application implementation + */ +static void +wthp_ivi_application_surface_create(struct wthp_ivi_application * ivi_application, uint32_t ivi_id, + struct wthp_surface * wthp_surface, struct wthp_ivi_surface *obj) +{ + wth_verbose("%s >>> \n",__func__); + wth_verbose("ivi_application %p surface_create(%d, %p, %p)\n", + ivi_application, ivi_id, wthp_surface, obj); + struct surface *surface = wth_object_get_user_data((struct wth_object *)wthp_surface); + wth_verbose("----------------------------------\n\n\n"); + wth_verbose("surface [%p]\n", surface); + wth_verbose("shm_window [%p]\n\n\n", surface->shm_window); + wth_verbose("----------------------------------\n"); + + surface->ivi_id = ivi_id + 100; + surface->shm_window->id_ivisurf = surface->ivi_id; + struct ivisurface *ivisurf; + + ivisurf = zalloc(sizeof *ivisurf); + if (!ivisurf) { + return; + } + + ivisurf->obj = obj; + ivisurf->surf = surface; + + wth_receiver_weston_main(surface->shm_window); + + while (!surface->shm_window->ready) + usleep(1); + + wthp_ivi_surface_set_interface(obj, &wthp_ivi_surface_implementation, + ivisurf); + wth_verbose(" <<< %s \n",__func__); +} + +static const struct wthp_ivi_application_interface wthp_ivi_application_implementation = { + wthp_ivi_application_surface_create, +}; + +static void +client_bind_wthp_ivi_application(struct client *c, struct wthp_ivi_application *obj) +{ + wth_verbose("%s >>> \n",__func__); + + struct application *app; + + app = zalloc(sizeof *app); + if (!app) { + client_post_out_of_memory(c); + return; + } + + app->obj = obj; + app->client = c; + wl_list_insert(&c->compositor_list, &app->link); + + wthp_ivi_application_set_interface(obj, &wthp_ivi_application_implementation, + app); + wth_verbose("client %p bound wthp_ivi_application\n", c); + wth_verbose(" <<< %s \n",__func__); +} + +/* + * APIs to send pointer events to waltham client + */ + +void +waltham_pointer_enter(struct window *window, uint32_t serial, + wl_fixed_t sx, wl_fixed_t sy) +{ + wth_verbose("%s >>> \n",__func__); + + struct surface *surface = window->receiver_surf; + struct seat *seat = window->receiver_seat; + struct pointer *pointer = seat->pointer; + + wth_verbose("waltham_pointer_enter [%d]\n", window->receiver_surf->ivi_id); + + wthp_pointer_send_enter (pointer->obj, serial, surface->obj, sx, sy); + + wth_verbose(" <<< %s \n",__func__); + return; +} + +void +waltham_pointer_leave(struct window *window, uint32_t serial) +{ + wth_verbose("%s >>> \n",__func__); + struct surface *surface = window->receiver_surf; + struct seat *seat = window->receiver_seat; + struct pointer *pointer = seat->pointer; + + wth_verbose("waltham_pointer_leave [%d]\n", window->receiver_surf->ivi_id); + + wthp_pointer_send_leave (pointer->obj, serial, surface->obj); + + wth_verbose(" <<< %s \n",__func__); + return; +} + +void +waltham_pointer_motion(struct window *window, uint32_t time, + wl_fixed_t sx, wl_fixed_t sy) +{ + wth_verbose("%s >>> \n",__func__); + struct seat *seat = window->receiver_seat; + struct pointer *pointer = seat->pointer; + + wthp_pointer_send_motion (pointer->obj, time, sx, sy); + + wth_verbose(" <<< %s \n",__func__); + return; +} + +void +waltham_pointer_button(struct window *window, uint32_t serial, + uint32_t time, uint32_t button, + uint32_t state) +{ + wth_verbose("%s >>> \n",__func__); + struct seat *seat = window->receiver_seat; + struct pointer *pointer = seat->pointer; + + wthp_pointer_send_button (pointer->obj, serial, time, button, state); + + wth_verbose(" <<< %s \n",__func__); + return; +} + +void +waltham_pointer_axis(struct window *window, uint32_t time, + uint32_t axis, wl_fixed_t value) +{ + wth_verbose("%s >>> \n",__func__); + struct seat *seat = window->receiver_seat; + struct pointer *pointer = seat->pointer; + + wthp_pointer_send_axis (pointer->obj, time, axis, value); + + wth_verbose(" <<< %s \n",__func__); + return; +} + +/* + * waltham pointer implementation + */ +static void +pointer_set_cursor(struct wthp_pointer *wthp_pointer, int32_t serial, struct wthp_surface *surface, + int32_t hotspot_x, int32_t hotspot_y) +{ + struct pointer *pointer = wth_object_get_user_data((struct wth_object *)wthp_pointer); + + wth_verbose("wthp_pointer %p (%d, %p, %d, %d)\n", + wthp_pointer, serial, surface, hotspot_x, hotspot_y); + +} + +static void +pointer_release(struct wthp_pointer *wthp_pointer) +{ + struct pointer *pointer = wth_object_get_user_data((struct wth_object *)wthp_pointer); + + wth_verbose("wthp_pointer %p\n",wthp_pointer); +} + +static const struct wthp_pointer_interface pointer_implementation = { + pointer_set_cursor, + pointer_release +}; + +/* + * APIs to send touch events to waltham client + */ + +void +waltham_touch_down(struct window *window, uint32_t serial, + uint32_t time, int32_t id, + wl_fixed_t x_w, wl_fixed_t y_w) +{ + wth_verbose("%s >>> \n",__func__); + struct surface *surface = window->receiver_surf; + struct seat *seat = window->receiver_seat; + struct touch *touch = seat->touch; + + wth_verbose("touch_handle_down surface [%d]\n", surface->ivi_id); + wthp_touch_send_down(touch->obj, serial, time, surface->obj, id, x_w, y_w); + + wth_verbose(" <<< %s \n",__func__); + return; +} + +void +waltham_touch_up(struct window *window, uint32_t serial, + uint32_t time, int32_t id) +{ + wth_verbose("%s >>> \n",__func__); + struct seat *seat = window->receiver_seat; + struct touch *touch = seat->touch; + + wthp_touch_send_up(touch->obj, serial, time, id); + + wth_verbose(" <<< %s \n",__func__); + return; +} + +void +waltham_touch_motion(struct window *window, uint32_t time, + int32_t id, wl_fixed_t x_w, wl_fixed_t y_w) +{ + wth_verbose("%s >>> \n",__func__); + struct seat *seat = window->receiver_seat; + struct touch *touch = seat->touch; + + wthp_touch_send_motion(touch->obj, time, id, x_w, y_w); + + wth_verbose(" <<< %s \n",__func__); + return; +} + +void +waltham_touch_frame(struct window *window) +{ + wth_verbose("%s >>> \n",__func__); + struct seat *seat = window->receiver_seat; + struct touch *touch = seat->touch; + + wthp_touch_send_frame(touch->obj); + + wth_verbose(" <<< %s \n",__func__); + return; +} + +void +waltham_touch_cancel(struct window *window) +{ + wth_verbose("%s >>> \n",__func__); + struct seat *seat = window->receiver_seat; + struct touch *touch = seat->touch; + + wthp_touch_send_cancel(touch->obj); + + wth_verbose(" <<< %s \n",__func__); + return; +} + +/* + * waltham touch implementation + */ +static void +touch_release(struct wthp_touch *wthp_touch) +{ + wth_verbose("%s >>> \n",__func__); + struct touch *touch = wth_object_get_user_data((struct wth_object *)wthp_touch); + + wth_verbose("%p\n",wthp_touch); +} + +static const struct wthp_touch_interface touch_implementation = { + touch_release, +}; + +/* + * waltham seat implementation + */ +static void +seat_get_pointer(struct wthp_seat *wthp_seat, struct wthp_pointer *wthp_pointer) +{ + wth_verbose("%s >>> \n",__func__); + + wth_verbose("wthp_seat %p get_pointer(%p)\n", + wthp_seat, wthp_pointer); + + struct seat *seat = wth_object_get_user_data((struct wth_object *)wthp_seat); + struct pointer *pointer; + + pointer = zalloc(sizeof *pointer); + if (!pointer) { + client_post_out_of_memory(seat->client); + return; + } + + pointer->obj = wthp_pointer; + pointer->seat = seat; + seat->pointer = pointer; + wl_list_insert(&seat->client->pointer_list, &pointer->link); + + wthp_pointer_set_interface(wthp_pointer, &pointer_implementation, pointer); + wth_verbose(" <<< %s \n",__func__); +} + +static void +seat_get_touch(struct wthp_seat *wthp_seat, struct wthp_touch *wthp_touch) +{ + wth_verbose("%s >>> \n",__func__); + wth_verbose("wthp_seat %p get_touch(%p)\n", + wthp_seat, wthp_touch); + + struct seat *seat = wth_object_get_user_data((struct wth_object *)wthp_seat); + struct touch *touch; + + touch = zalloc(sizeof *touch); + if (!touch) { + client_post_out_of_memory(seat->client); + return; + } + + touch->obj = wthp_touch; + touch->seat = seat; + seat->touch = touch; + wl_list_insert(&seat->client->touch_list, &touch->link); + + wthp_touch_set_interface(wthp_touch, &touch_implementation, touch); + wth_verbose(" <<< %s \n",__func__); +} + +static void +seat_release(struct wthp_seat *wthp_seat) +{ +} + +static const struct wthp_seat_interface seat_implementation = { + seat_get_pointer, + NULL, + seat_get_touch, + seat_release, + NULL +}; + +static void +seat_send_updated_caps(struct seat *seat) +{ + wth_verbose("%s >>> \n",__func__); + enum wthp_seat_capability caps = 0; + + caps |= WTHP_SEAT_CAPABILITY_POINTER; + wth_verbose("WTHP_SEAT_CAPABILITY_POINTER %d\n", caps); + + caps |= WTHP_SEAT_CAPABILITY_TOUCH; + wth_verbose("WTHP_SEAT_CAPABILITY_TOUCH %d\n", caps); + + wthp_seat_send_capabilities(seat->obj, caps); + wth_verbose(" <<< %s \n",__func__); +} + +static void +client_bind_seat(struct client *c, struct wthp_seat *obj) +{ + wth_verbose("%s >>> \n",__func__); + struct seat *seat; + + seat = zalloc(sizeof *seat); + if (!seat) { + client_post_out_of_memory(c); + return; + } + + seat->obj = obj; + seat->client = c; + wl_list_insert(&c->seat_list, &seat->link); + wth_verbose("wthp_seat object=%p and seat=%p\n",obj,seat); + wthp_seat_set_interface(obj, &seat_implementation, + seat); + wth_verbose("client %p bound wthp_seat\n", c); + seat_send_updated_caps(seat); + wth_verbose(" <<< %s \n",__func__); +} + +/* + * waltham region implementation + */ + +static void +region_destroy(struct region *region) +{ + wth_verbose("%s >>> \n",__func__); + wth_verbose("region %p destroy\n", region->obj); + + wthp_region_free(region->obj); + wl_list_remove(®ion->link); + free(region); + wth_verbose(" <<< %s \n",__func__); +} + +static void +region_handle_destroy(struct wthp_region *wthp_region) +{ + wth_verbose("%s >>> \n",__func__); + struct region *region = wth_object_get_user_data((struct wth_object *)wthp_region); + + assert(wthp_region == region->obj); + + region_destroy(region); + wth_verbose(" <<< %s \n",__func__); +} + +static void +region_handle_add(struct wthp_region *wthp_region, + int32_t x, int32_t y, int32_t width, int32_t height) +{ + wth_verbose("region %p add(%d, %d, %d, %d)\n", + wthp_region, x, y, width, height); +} + +static void +region_handle_subtract(struct wthp_region *wthp_region, + int32_t x, int32_t y, + int32_t width, int32_t height) +{ + wth_verbose("region %p subtract(%d, %d, %d, %d)\n", + wthp_region, x, y, width, height); +} + +static const struct wthp_region_interface region_implementation = { + region_handle_destroy, + region_handle_add, + region_handle_subtract +}; + +/* + * waltham compositor implementation + */ +static void +compositor_destroy(struct compositor *comp) +{ + wth_verbose("%s >>> \n",__func__); + wth_verbose("%s: %p\n", __func__, comp->obj); + + wthp_compositor_free(comp->obj); + wl_list_remove(&comp->link); + free(comp); + wth_verbose(" <<< %s \n",__func__); +} + +static void +compositor_handle_create_surface(struct wthp_compositor *compositor, + struct wthp_surface *id) +{ + wth_verbose("%s >>> \n",__func__); + struct compositor *comp = wth_object_get_user_data((struct wth_object *)compositor); + struct client *client = comp->client; + struct surface *surface; + struct seat *seat, *tmp; + + wth_verbose("client %p create surface %p\n", + comp->client, id); + + surface = zalloc(sizeof *surface); + if (!surface) { + client_post_out_of_memory(comp->client); + return; + } + + surface->obj = id; + wl_list_insert(&comp->client->surface_list, &surface->link); + + wthp_surface_set_interface(id, &surface_implementation, surface); + + surface->shm_window = calloc(1, sizeof *surface->shm_window); + if (!surface->shm_window) + return; + + surface->shm_window->receiver_surf = surface; + surface->shm_window->ready = false; + surface->ivi_id = 0; + + wl_list_for_each_safe(seat, tmp, &client->seat_list, link) { + surface->shm_window->receiver_seat = seat; + } + + wth_verbose(" <<< %s \n",__func__); +} + +static void +compositor_handle_create_region(struct wthp_compositor *compositor, + struct wthp_region *id) +{ + wth_verbose("%s >>> \n",__func__); + struct compositor *comp = wth_object_get_user_data((struct wth_object *)compositor); + struct region *region; + + wth_verbose("client %p create region %p\n", + comp->client, id); + + region = zalloc(sizeof *region); + if (!region) { + client_post_out_of_memory(comp->client); + return; + } + + region->obj = id; + wl_list_insert(&comp->client->region_list, ®ion->link); + + wthp_region_set_interface(id, ®ion_implementation, region); + wth_verbose(" <<< %s \n",__func__); +} + +static const struct wthp_compositor_interface compositor_implementation = { + compositor_handle_create_surface, + compositor_handle_create_region +}; + +static void +client_bind_compositor(struct client *c, struct wthp_compositor *obj) +{ + wth_verbose("%s >>> \n",__func__); + struct compositor *comp; + + comp = zalloc(sizeof *comp); + if (!comp) { + client_post_out_of_memory(c); + return; + } + + comp->obj = obj; + comp->client = c; + wl_list_insert(&c->compositor_list, &comp->link); + + wthp_compositor_set_interface(obj, &compositor_implementation, + comp); + wth_verbose("client %p bound wthp_compositor\n", c); + wth_verbose(" <<< %s \n",__func__); +} + +/* + * waltham registry implementation + */ +static void +registry_destroy(struct registry *reg) +{ + wth_verbose("%s >>> \n",__func__); + wth_verbose("%s: %p\n", __func__, reg->obj); + + wthp_registry_free(reg->obj); + wl_list_remove(®->link); + free(reg); + wth_verbose(" <<< %s \n",__func__); +} + +static void +registry_handle_destroy(struct wthp_registry *registry) +{ + wth_verbose("%s >>> \n",__func__); + struct registry *reg = wth_object_get_user_data((struct wth_object *)registry); + + registry_destroy(reg); + wth_verbose(" <<< %s \n",__func__); +} + +static void +registry_handle_bind(struct wthp_registry *registry, + uint32_t name, + struct wth_object *id, + const char *interface, + uint32_t version) +{ + wth_verbose("%s >>> \n",__func__); + struct registry *reg = wth_object_get_user_data((struct wth_object *)registry); + wth_verbose("Recieved registry : %s\n", interface); + + if (strcmp(interface, "wthp_compositor") == 0) { + client_bind_compositor(reg->client, (struct wthp_compositor *)id); + } else if (strcmp(interface, "wthp_blob_factory") == 0) { + client_bind_blob_factory(reg->client, (struct wthp_blob_factory *)id); + struct client *client = reg->client; + struct seat *seat, *tmp,*get_seat; + wl_list_for_each_safe(seat, tmp, &client->seat_list, link) { + get_seat = seat; + } + wth_verbose("get_seat : %p\n", get_seat); + seat_send_updated_caps(get_seat); + } else if (strcmp(interface, "wthp_ivi_application") == 0) { + client_bind_wthp_ivi_application(reg->client, (struct wthp_ivi_application *)id); + } else if (strcmp(interface, "wthp_seat") == 0) { + client_bind_seat(reg->client, (struct wthp_seat *)id); + } else { + wth_object_post_error((struct wth_object *)registry, 0, + "%s: unknown name %u", __func__, name); + wth_object_delete(id); + } + wth_verbose(" <<< %s \n",__func__); +} + +static const struct wthp_registry_interface registry_implementation = { + registry_handle_destroy, + registry_handle_bind +}; + +/* + * waltham display implementation + */ + +static void +display_handle_client_version(struct wth_display *wth_display, + uint32_t client_version) +{ + wth_verbose("%s >>> \n",__func__); + wth_object_post_error((struct wth_object *)wth_display, 0, + "unimplemented: %s", __func__); + wth_verbose(" <<< %s \n",__func__); +} + +static void +display_handle_sync(struct wth_display * wth_display, struct wthp_callback * callback) +{ + wth_verbose("%s >>> \n",__func__); + struct client *c = wth_object_get_user_data((struct wth_object *)wth_display); + + wth_verbose("Client %p requested wth_display.sync\n", c); + wthp_callback_send_done(callback, 0); + wthp_callback_free(callback); + wth_verbose(" <<< %s \n",__func__); +} + +static void +display_handle_get_registry(struct wth_display *wth_display, + struct wthp_registry *registry) +{ + wth_verbose("%s >>> \n",__func__); + struct client *c = wth_object_get_user_data((struct wth_object *)wth_display); + struct registry *reg; + + reg = zalloc(sizeof *reg); + if (!reg) { + client_post_out_of_memory(c); + return; + } + + reg->obj = registry; + reg->client = c; + wl_list_insert(&c->registry_list, ®->link); + wthp_registry_set_interface(registry, + ®istry_implementation, reg); + + wthp_registry_send_global(registry, 1, "wthp_compositor", 4); + wthp_registry_send_global(registry, 1, "wthp_ivi_application", 1); + wthp_registry_send_global(registry, 1, "wthp_seat", 4); + wthp_registry_send_global(registry, 1, "wthp_blob_factory", 4); + wth_verbose(" <<< %s \n",__func__); +} + +const struct wth_display_interface display_implementation = { + display_handle_client_version, + display_handle_sync, + display_handle_get_registry +}; + +/* + * functions to handle waltham client connections + */ +static void +connection_handle_data(struct watch *w, uint32_t events) +{ + wth_verbose("%s >>> \n",__func__); + struct client *c = container_of(w, struct client, conn_watch); + int ret; + + if (events & EPOLLERR) { + wth_error("Client %p errored out.\n", c); + client_destroy(c); + + return; + } + + if (events & EPOLLHUP) { + wth_error("Client %p hung up.\n", c); + client_destroy(c); + + return; + } + + if (events & EPOLLOUT) { + ret = wth_connection_flush(c->connection); + if (ret == 0) + watch_ctl(&c->conn_watch, EPOLL_CTL_MOD, EPOLLIN); + else if (ret < 0 && errno != EAGAIN){ + wth_error("Client %p flush error.\n", c); + client_destroy(c); + + return; + } + } + + if (events & EPOLLIN) { + ret = wth_connection_read(c->connection); + if (ret < 0) { + wth_error("Client %p read error.\n", c); + client_destroy(c); + + return; + } + + ret = wth_connection_dispatch(c->connection); + if (ret < 0 && errno != EPROTO) { + wth_error("Client %p dispatch error.\n", c); + client_destroy(c); + + return; + } + } + wth_verbose(" <<< %s \n",__func__); +} + +/** +* client_create +* +* Create new client connection +* +* @param srv receiver structure +* @param wth_connection Waltham connection handle +* @return Pointer to client structure +*/ +static struct client * +client_create(struct receiver *srv, struct wth_connection *conn) +{ + wth_verbose("%s >>> \n",__func__); + struct client *c; + struct wth_display *disp; + + c = zalloc(sizeof *c); + if (!c) + return NULL; + + c->receiver = srv; + c->connection = conn; + + c->conn_watch.receiver = srv; + c->conn_watch.fd = wth_connection_get_fd(conn); + c->conn_watch.cb = connection_handle_data; + if (watch_ctl(&c->conn_watch, EPOLL_CTL_ADD, EPOLLIN) < 0) { + free(c); + return NULL; + } + + wth_verbose("Client %p connected.\n", c); + + wl_list_insert(&srv->client_list, &c->link); + + wl_list_init(&c->registry_list); + wl_list_init(&c->compositor_list); + wl_list_init(&c->seat_list); + wl_list_init(&c->pointer_list); + wl_list_init(&c->touch_list); + wl_list_init(&c->region_list); + wl_list_init(&c->surface_list); + wl_list_init(&c->buffer_list); + + disp = wth_connection_get_display(c->connection); + wth_display_set_interface(disp, &display_implementation, c); + + wth_verbose(" <<< %s \n",__func__); + return c; +} + +/** +* client_destroy +* +* Destroy client connection +* +* @param names struct client *c +* @param value client data +* @return none +*/ +void +client_destroy(struct client *c) +{ + wth_verbose("%s >>> \n",__func__); + struct region *region; + struct compositor *comp; + struct registry *reg; + struct surface *surface; + + wth_verbose("Client %p disconnected.\n", c); + + /* clean up remaining client resources in case the client + * did not. + */ + wl_list_last_until_empty(region, &c->region_list, link) + region_destroy(region); + + wl_list_last_until_empty(comp, &c->compositor_list, link) + compositor_destroy(comp); + + wl_list_last_until_empty(reg, &c->registry_list, link) + registry_destroy(reg); + + wl_list_last_until_empty(surface, &c->surface_list, link) + surface_destroy(surface); + + wl_list_remove(&c->link); + watch_ctl(&c->conn_watch, EPOLL_CTL_DEL, 0); + wth_connection_destroy(c->connection); + free(c); + wth_verbose(" <<< %s \n",__func__); +} + +/** +* receiver_flush_clients +* +* write all the pending requests from the clients to socket +* +* @param names struct receiver *srv +* @param value socket connection info and client data +* @return none +*/ +void +receiver_flush_clients(struct receiver *srv) +{ + wth_verbose("%s >>> \n",__func__); + struct client *c, *tmp; + int ret; + + wl_list_for_each_safe(c, tmp, &srv->client_list, link) { + /* Flush out buffered requests. If the Waltham socket is + * full, poll it for writable too. + */ + ret = wth_connection_flush(c->connection); + if (ret < 0 && errno == EAGAIN) { + watch_ctl(&c->conn_watch, EPOLL_CTL_MOD, EPOLLIN | EPOLLOUT); + } else if (ret < 0) { + perror("Connection flush failed"); + client_destroy(c); + return; + } + } + + wth_verbose(" <<< %s \n",__func__); + +} + +/** +* receiver_accept_client +* +* Accepts new waltham client connection and instantiates client structure +* +* @param names struct receiver *srv +* @param value socket connection info and client data +* @return none +*/ +void +receiver_accept_client(struct receiver *srv) +{ + wth_verbose("%s >>> \n",__func__); + struct client *client; + struct wth_connection *conn; + struct sockaddr_in addr; + socklen_t len; + + len = sizeof addr; + conn = wth_accept(srv->listen_fd, (struct sockaddr *)&addr, &len); + if (!conn) { + wth_error("Failed to accept a connection.\n"); + return; + } + + client = client_create(srv, conn); + if (!client) { + wth_error("Failed client_create().\n"); + return; + } + wth_verbose(" <<< %s \n",__func__); +} diff --git a/waltham-receiver/src/wth-receiver-gst.c b/waltham-receiver/src/wth-receiver-gst.c new file mode 100644 index 0000000..6c5f747 --- /dev/null +++ b/waltham-receiver/src/wth-receiver-gst.c @@ -0,0 +1,879 @@ +/* + * Copyright © 2019 Advanced Driver Information Technology GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/******************************************************************************* + ** ** + ** TARGET : linux ** + ** ** + ** PROJECT : waltham-receiver ** + ** ** + ** PURPOSE : This file is acts as interface to weston compositor at receiver ** + ** side ** + ** ** + *******************************************************************************/ + +#include <sys/mman.h> +#include <signal.h> +#include <sys/time.h> +#include <gst/gst.h> +#include <GL/gl.h> +#include <gst/video/gstvideometa.h> +#include <gst/allocators/gstdmabuf.h> +#include <gst/app/gstappsink.h> +#include <pthread.h> +#include <gst/wayland/wayland.h> +#include <gst/video/videooverlay.h> + +#include <xf86drm.h> +#include <drm.h> +#include <drm_fourcc.h> + +#include "wth-receiver-comm.h" +#include "os-compatibility.h" +#include "ivi-application-client-protocol.h" +#include "bitmap.h" +static int running = 1; + +typedef struct _GstAppContext +{ + GMainLoop *loop; + GstBus *bus; + GstElement *pipeline; + GstElement *sink; + struct display *display; + struct window *window; + GstVideoInfo info; +}GstAppContext; + +static const gchar *vertex_shader_str = +"attribute vec4 a_position; \n" +"attribute vec2 a_texCoord; \n" +"varying vec2 v_texCoord; \n" +"void main() \n" +"{ \n" +" gl_Position = a_position; \n" +" v_texCoord = a_texCoord; \n" +"} \n"; + +static const gchar *fragment_shader_str = +"#ifdef GL_ES \n" +"precision mediump float; \n" +"#endif \n" +"varying vec2 v_texCoord; \n" +"uniform sampler2D tex; \n" +"void main() \n" +"{ \n" +"vec2 uv; \n" +"uv = v_texCoord.xy; \n" +"vec4 c = texture2D(tex, uv); \n" +"gl_FragColor = c; \n" +"} \n"; + +/* + * pointer callbcak functions + */ + static void +pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, struct wl_surface *wl_surface, + wl_fixed_t sx, wl_fixed_t sy) +{ + wth_verbose("%s >>> \n",__func__); + + wth_verbose("data [%p]\n", data); + + struct display *display = data; + struct window *window = display->window; + + waltham_pointer_enter(window, serial, sx, sy); + + wth_verbose(" <<< %s \n",__func__); +} + +static void +pointer_handle_leave(void *data, struct wl_pointer *pointer, + uint32_t serial, struct wl_surface *surface) +{ + wth_verbose("%s >>> \n",__func__); + + wth_verbose("data [%p]\n", data); + + struct display *display = data; + struct window *window = display->window; + + waltham_pointer_leave(window, serial); + + wth_verbose(" <<< %s \n",__func__); +} + +static void +pointer_handle_motion(void *data, struct wl_pointer *pointer, + uint32_t time, wl_fixed_t sx, wl_fixed_t sy) +{ + wth_verbose("%s >>> \n",__func__); + + struct display *display = data; + struct window *window = display->window; + + waltham_pointer_motion(window, time, sx, sy); + + wth_verbose(" <<< %s \n",__func__); +} + +static void +pointer_handle_button(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, uint32_t time, uint32_t button, + uint32_t state) +{ + wth_verbose("%s >>> \n",__func__); + + struct display *display = data; + struct window *window = display->window; + + waltham_pointer_button(window, serial, time, button, state); + + wth_verbose(" <<< %s \n",__func__); +} + +static void +pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, + uint32_t time, uint32_t axis, wl_fixed_t value) +{ + wth_verbose("%s >>> \n",__func__); + + struct display *display = data; + struct window *window = display->window; + + waltham_pointer_axis(window, time, axis, value); + + wth_verbose(" <<< %s \n",__func__); +} + +static const struct wl_pointer_listener pointer_listener = { + pointer_handle_enter, + pointer_handle_leave, + pointer_handle_motion, + pointer_handle_button, + pointer_handle_axis, +}; + +/* + * touch callbcak functions + */ + +static void +touch_handle_down(void *data, struct wl_touch *touch, uint32_t serial, + uint32_t time, struct wl_surface *surface, int32_t id, + wl_fixed_t x_w, wl_fixed_t y_w) +{ + wth_verbose("%s >>> \n",__func__); + + struct display *display = data; + struct window *window = display->window; + + int x = (int)wl_fixed_to_double(x_w); + int y = (int)wl_fixed_to_double(y_w); + wth_verbose("%p x %d y %d\n",window, x, y); + + waltham_touch_down(window, serial, time, id, x_w, y_w); + + wth_verbose(" <<< %s \n",__func__); +} + +static void +touch_handle_up(void *data, struct wl_touch *touch, uint32_t serial, + uint32_t time, int32_t id) +{ + wth_verbose("%s >>> \n",__func__); + + struct display *display = data; + struct window *window = display->window; + + waltham_touch_up(window, serial, time, id); +} + +static void +touch_handle_motion(void *data, struct wl_touch *touch, uint32_t time, + int32_t id, wl_fixed_t x_w, wl_fixed_t y_w) +{ + wth_verbose("%s >>> \n",__func__); + + struct display *display = data; + struct window *window = display->window; + + waltham_touch_motion(window, time, id, x_w, y_w); + + wth_verbose(" <<< %s \n",__func__); +} + +static void +touch_handle_frame(void *data, struct wl_touch *touch) +{ + wth_verbose("%s >>> \n",__func__); + + struct display *display = data; + struct window *window = display->window; + + waltham_touch_frame(window); + + wth_verbose(" <<< %s \n",__func__); +} + +static void +touch_handle_cancel(void *data, struct wl_touch *touch) +{ + wth_verbose("%s >>> \n",__func__); + + struct display *display = data; + struct window *window = display->window; + + waltham_touch_cancel(window); + + wth_verbose(" <<< %s \n",__func__); +} + +static const struct wl_touch_listener touch_listener = { + touch_handle_down, + touch_handle_up, + touch_handle_motion, + touch_handle_frame, + touch_handle_cancel +}; + +/* + * seat callback + */ +static void +seat_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps) +{ + wth_verbose("%s >>> \n",__func__); + + struct display *display = data; + + wth_verbose("caps = %d\n", caps); + + if ((caps & WL_SEAT_CAPABILITY_POINTER) && !display->wl_pointer) + { + wth_verbose("WL_SEAT_CAPABILITY_POINTER\n"); + display->wl_pointer = wl_seat_get_pointer(wl_seat); + wl_pointer_set_user_data(display->wl_pointer, display); + wl_pointer_add_listener(display->wl_pointer, &pointer_listener, display); + wl_display_roundtrip(display->display); + } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && display->wl_pointer) { + wth_verbose("!WL_SEAT_CAPABILITY_POINTER\n"); + wl_pointer_destroy(display->wl_pointer); + display->wl_pointer = NULL; + } + + if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !display->wl_touch) + { + wth_verbose("WL_SEAT_CAPABILITY_TOUCH\n"); + display->wl_touch = wl_seat_get_touch(wl_seat); + wl_touch_set_user_data(display->wl_touch, display); + wl_touch_add_listener(display->wl_touch, &touch_listener, display); + wl_display_roundtrip(display->display); + } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && display->wl_touch) { + wth_verbose("!WL_SEAT_CAPABILITY_TOUCH\n"); + wl_touch_destroy(display->wl_touch); + display->wl_touch = NULL; + } + + wth_verbose(" <<< %s \n",__func__); +} + +static const struct wl_seat_listener seat_listener = { + seat_capabilities, + NULL +}; + +static void +add_seat(struct display *display, uint32_t id, uint32_t version) +{ + wth_verbose("%s >>> \n",__func__); + + display->wl_pointer = NULL; + display->wl_touch = NULL; + display->wl_keyboard = NULL; + display->seat = wl_registry_bind(display->registry, id, + &wl_seat_interface, 1); + wl_seat_add_listener(display->seat, &seat_listener, display); + wth_verbose(" <<< %s \n",__func__); +} + +gboolean bus_message(GstBus *bus, GstMessage *message, gpointer p) +{ + GstAppContext *gstctx = p; + + fprintf(stderr, "mesage: %s\n", GST_MESSAGE_TYPE_NAME(message)); + + switch( GST_MESSAGE_TYPE(message)) { + case GST_MESSAGE_ERROR: + { + GError *err; + gchar *debug; + + gst_message_parse_error(message, &err, &debug); + g_print("ERROR: %s\n", err->message); + + g_error_free(err); + g_free(debug); + g_main_loop_quit(gstctx->loop); + break; + } + + case GST_MESSAGE_STATE_CHANGED: + { + GstState oldstate, newstate; + + gst_message_parse_state_changed(message, &oldstate, &newstate, NULL); + fprintf(stderr, "#%s state changed\n", GST_MESSAGE_SRC_NAME(message)); + switch (newstate){ + case GST_STATE_NULL: + fprintf(stderr, "%s: state is NULL\n", GST_MESSAGE_SRC_NAME(message)); + break; + case GST_STATE_READY: + fprintf(stderr, "%s: state is READY\n", GST_MESSAGE_SRC_NAME(message)); + break; + case GST_STATE_PAUSED: + fprintf(stderr, "%s: state is PAUSED\n", GST_MESSAGE_SRC_NAME(message)); + break; + case GST_STATE_PLAYING: + fprintf(stderr, "%s: state is PLAYING\n", GST_MESSAGE_SRC_NAME(message)); + break; + } + break; + } + default: + fprintf(stderr, "Unhandled message\n"); + break; + } + fprintf(stderr, "-----------------\n"); +} + +/* + * registry callback + */ +static void +registry_handle_global(void *data, struct wl_registry *registry, + uint32_t id, const char *interface, uint32_t version) +{ + wth_verbose("%s >>> \n",__func__); + + struct display *d = data; + + if (strcmp(interface, "wl_compositor") == 0) { + d->compositor = + wl_registry_bind(registry, + id, &wl_compositor_interface, 1); + } else if (strcmp(interface, "ivi_application") == 0) { + d->ivi_application = + wl_registry_bind(registry, id, + &ivi_application_interface, 1); + } else if (strcmp(interface, "wl_seat") == 0) { + add_seat(d, id, version); + } + wth_verbose(" <<< %s \n",__func__); +} + +static void +registry_handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ + /* stub */ +} + +static const struct wl_registry_listener registry_listener = { + registry_handle_global, + registry_handle_global_remove +}; + +wth_receiver_weston_shm_attach(struct window *window, uint32_t data_sz, void * data, + int32_t width, int32_t height, int32_t stride, uint32_t format) +{ + /* stub */ +} +void +wth_receiver_weston_shm_damage(struct window *window) +{ + /* stub */ +} + +void +wth_receiver_weston_shm_commit(struct window *window) +{ + /* stub */ +} + +static struct display * +create_display(void) +{ + wth_verbose("%s >>> \n",__func__); + + struct display *display; + + display = malloc(sizeof *display); + if (display == NULL) { + wth_error("out of memory\n"); + exit(1); + } + display->display = wl_display_connect(NULL); + assert(display->display); + + display->has_xrgb = false; + display->registry = wl_display_get_registry(display->display); + wl_registry_add_listener(display->registry, + ®istry_listener, display); + wl_display_roundtrip(display->display); + + wth_verbose(" <<< %s \n",__func__); + return display; +} + +static void +destroy_display(struct display *display) +{ + wth_verbose("%s >>> \n",__func__); + + if (display->compositor) + wl_compositor_destroy(display->compositor); + + wl_registry_destroy(display->registry); + wl_display_flush(display->display); + wl_display_disconnect(display->display); + free(display); + + wth_verbose(" <<< %s \n",__func__); +} + +/* + * ivi surface callback + */ +static void +handle_ivi_surface_configure(void *data, struct ivi_surface *ivi_surface, + int32_t width, int32_t height) +{ + /* Simple-shm is resizable */ +} + +static const struct ivi_surface_listener ivi_surface_listener = { + handle_ivi_surface_configure, +}; + +static void +init_egl(struct display *display) +{ + wth_verbose("%s >>> \n",__func__); + EGLint config_attribs[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_NONE + }; + + static const EGLint context_attribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + EGLint major, minor, count; + EGLBoolean ret; + + display->egl.dpy = eglGetDisplay(display->display); + assert(display->egl.dpy); + + ret = eglInitialize(display->egl.dpy, &major, &minor); + assert(ret == EGL_TRUE); + ret = eglBindAPI(EGL_OPENGL_ES_API); + assert(ret == EGL_TRUE); + + ret = eglChooseConfig(display->egl.dpy, config_attribs, + &display->egl.conf, 1, &count); + assert(ret && count >= 1); + + display->egl.ctx = eglCreateContext(display->egl.dpy, + display->egl.conf, + EGL_NO_CONTEXT, context_attribs); + assert(display->egl.ctx); + + eglSwapInterval(display->egl.dpy, 1); + + display->egl.create_image = + (void *) eglGetProcAddress("eglCreateImageKHR"); + assert(display->egl.create_image); + + display->egl.image_texture_2d = + (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES"); + assert(display->egl.image_texture_2d); + + display->egl.destroy_image = + (void *) eglGetProcAddress("eglDestroyImageKHR"); + assert(display->egl.destroy_image); + wth_verbose("%s <<< \n",__func__); +} + +GLuint load_shader(GLenum type, const char *shaderSrc) +{ + wth_verbose("%s >>> \n",__func__); + GLuint shader; + GLint compiled; + + /* Create the shader object */ + shader = glCreateShader(type); + if (shader == 0) + { + printf("\n Failed to create shader \n"); + return 0; + } + /* Load the shader source */ + glShaderSource(shader, 1, &shaderSrc, NULL); + /* Compile the shader */ + glCompileShader(shader); + /* Check the compile status */ + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + if (!compiled) + { + GLint infoLen = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen > 1) + { + char* infoLog = (char*)malloc (sizeof(char) * infoLen ); + glGetShaderInfoLog(shader, infoLen, NULL, infoLog); + fprintf(stderr, "Error compiling shader:%s\n",infoLog); + free(infoLog); + } + glDeleteShader(shader); + return 0; + } + return shader; +} + +void init_gl(struct display *display) +{ + wth_verbose("%s >>> \n",__func__); + GLint linked; + + /* load vertext/fragment shader */ + display->gl.vertex_shader = load_shader(GL_VERTEX_SHADER, vertex_shader_str); + display->gl.fragment_shader = load_shader(GL_FRAGMENT_SHADER, fragment_shader_str); + + /* Create the program object */ + display->gl.program_object = glCreateProgram(); + if (display->gl.program_object == 0) + { + fprintf(stderr, "error program object\n"); + return; + } + + glAttachShader(display->gl.program_object, display->gl.vertex_shader); + glAttachShader(display->gl.program_object, display->gl.fragment_shader); + /* Bind vPosition to attribute 0 */ + glBindAttribLocation(display->gl.program_object, 0, "a_position"); + /* Link the program */ + glLinkProgram(display->gl.program_object); + /* Check the link status */ + glGetProgramiv(display->gl.program_object, GL_LINK_STATUS, &linked); + if (!linked) + { + GLint infoLen = 0; + glGetProgramiv(display->gl.program_object, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen > 1) + { + char* infoLog = (char*)malloc(sizeof(char) * infoLen); + glGetProgramInfoLog(display->gl.program_object, infoLen, NULL, infoLog); + fprintf(stderr, "Error linking program:%s\n", infoLog); + free(infoLog); + } + glDeleteProgram(display->gl.program_object); + } + + glGenTextures(1, &display->gl.texture); + + return; +} + +static void +create_surface(struct window *window) +{ + wth_verbose("%s >>> \n",__func__); + struct display *display = window->display; + int ret; + + window->surface = wl_compositor_create_surface(display->compositor); + assert(window->surface); + + window->native = wl_egl_window_create(window->surface, + window->width, window->height); + assert(window->native); + + window->egl_surface = eglCreateWindowSurface(display->egl.dpy, + display->egl.conf, + (NativeWindowType)window->native, NULL); + + wl_display_roundtrip(display->display); + if (display->ivi_application ) { + uint32_t id_ivisurf = window->id_ivisurf; + window->ivi_surface = + ivi_application_surface_create(display->ivi_application, + id_ivisurf, window->surface); + if (window->ivi_surface == NULL) { + wth_error("Failed to create ivi_client_surface\n"); + abort(); + } + + ivi_surface_add_listener(window->ivi_surface, + &ivi_surface_listener, window); + } else { + assert(0); + } + ret = eglMakeCurrent(display->egl.dpy, window->egl_surface, + window->egl_surface, display->egl.ctx); + assert(ret == EGL_TRUE); + + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + eglSwapBuffers(display->egl.dpy, window->egl_surface); + wth_verbose(" <<< %s \n",__func__); +} + +static void +create_window(struct window *window, struct display *display, int width, int height) +{ + wth_verbose("%s >>> \n",__func__); + + window->callback = NULL; + + window->display = display; + window->width = width; + window->height = height; + window->window_frames = 0; + window->window_benchmark_time = 0; + + create_surface(window); + + wth_verbose(" <<< %s \n",__func__); + return; +} + +static void +destroy_window(struct window *window) +{ + wth_verbose("%s >>> \n",__func__); + + if (window->callback) + wl_callback_destroy(window->callback); + + if (window->buffers[0].buffer) + wl_buffer_destroy(window->buffers[0].buffer); + if (window->buffers[1].buffer) + wl_buffer_destroy(window->buffers[1].buffer); + + wl_surface_destroy(window->surface); + free(window); + + wth_verbose(" <<< %s \n",__func__); +} + +static void +signal_int(int signum) +{ + running = 0; +} + +void *stream_thread(void *data) +{ + wth_verbose("%s >>> \n",__func__); + GMainLoop *loop = data; + g_main_loop_run(loop); + wth_verbose(" <<< %s \n",__func__); +} + +static GstPadProbeReturn +pad_probe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) +{ + wth_verbose("%s >>> \n",__func__); + GstAppContext *dec = user_data; + GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info); + GstCaps *caps; + + (void)pad; + + if (GST_EVENT_TYPE(event) != GST_EVENT_CAPS) + return GST_PAD_PROBE_OK; + + gst_event_parse_caps(event, &caps); + + if (!caps) { + GST_ERROR("caps event without caps"); + return GST_PAD_PROBE_OK; + } + + if (!gst_video_info_from_caps(&dec->info, caps)) { + GST_ERROR("caps event with invalid video caps"); + return GST_PAD_PROBE_OK; + } + + dec->window->width=GST_VIDEO_INFO_WIDTH(&dec->info); + dec->window->height=GST_VIDEO_INFO_HEIGHT(&dec->info); + gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY (dec->sink),0,0,dec->window->width,dec->window->height); + wl_surface_commit(dec->window->surface); + + wth_verbose(" <<< %s \n",__func__); + return GST_PAD_PROBE_OK; +} + +/** + * wth_receiver_weston_main + * + * This is the main function which will handle connection to the compositor at receiver side + * + * @param names void *data + * @param value struct window data + * @return 0 on success, -1 on error + */ +int +wth_receiver_weston_main(struct window *window) +{ + wth_verbose("%s >>> \n",__func__); + + struct sigaction sigint; + pthread_t pthread; + GstAppContext gstctx; + int ret = 0; + GError *gerror = NULL; + char * pipe = NULL; + FILE *pFile; + long lSize; + size_t res; + GstContext *context; + + memset(&gstctx, 0, sizeof(gstctx)); + /* Initialization for window creation */ + gstctx.display = create_display(); + init_egl(gstctx.display); + /* ToDo: fix the hardcoded value of width, height */ + create_window(window, gstctx.display,1920,1080); + init_gl(gstctx.display); + gstctx.window = window; + + gstctx.display->window = window; + + wth_verbose("display %p\n", gstctx.display); + wth_verbose("display->window %p\n", gstctx.display->window); + wth_verbose("window %p\n", window); + + sigint.sa_handler = signal_int; + sigemptyset(&sigint.sa_mask); + sigint.sa_flags = SA_RESETHAND; + sigaction(SIGINT, &sigint, NULL); + + /* create gstreamer pipeline */ + gst_init(NULL, NULL); + gstctx.loop = g_main_loop_new(NULL, FALSE); + + /* Read pipeline from file */ + pFile = fopen ( "/etc/xdg/weston/receiver_pipeline.cfg" , "rb" ); + if (pFile==NULL){ + fprintf(stderr, "failed to open file\n"); + return -1; + } + + /* obtain file size */ + fseek (pFile , 0 , SEEK_END); + lSize = ftell (pFile); + rewind (pFile); + + /* allocate memory to contain the whole file */ + pipe = (char*) zalloc (sizeof(char)*lSize); + if (pipe == NULL){ + fprintf(stderr,"Cannot allocate memory\n"); + return -1; + } + + /* copy the file into the buffer */ + res = fread (pipe,1,lSize,pFile); + if (res != lSize){ + fprintf(stderr,"File read error\n"); + return -1; + } + + wth_verbose("Gst Pipeline=%s",pipe); + /* close file */ + fclose (pFile); + + /* parse the pipeline */ + gstctx.pipeline = gst_parse_launch(pipe, &gerror); + + if(!gstctx.pipeline) + fprintf(stderr,"Could not create gstreamer pipeline.\n"); + free(pipe); + + gstctx.bus = gst_pipeline_get_bus((GstPipeline*)((void*)gstctx.pipeline)); + gst_bus_add_watch(gstctx.bus, bus_message, &gstctx); + fprintf(stderr, "registered bus signal\n"); + + /* get sink element */ + gstctx.sink = gst_bin_get_by_name(GST_BIN(gstctx.pipeline), "sink"); + /* get display context */ + context = gst_wayland_display_handle_context_new(gstctx.display->display); + /* set external display from context to sink */ + gst_element_set_context(gstctx.sink,context); + /* Attach existing surface to sink */ + gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY (gstctx.sink),window->surface); + + gst_pad_add_probe(gst_element_get_static_pad(gstctx.sink, "sink"), + GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, + pad_probe, &gstctx, NULL); + + fprintf(stderr, "set state as playing\n"); + gst_element_set_state((GstElement*)((void*)gstctx.pipeline), GST_STATE_PLAYING); + + + pthread_create(&pthread, NULL, &stream_thread, gstctx.loop); + + fprintf(stderr, "rendering part\n"); + + wth_verbose("in render loop\n"); + while (running && ret != -1) + ret=wl_display_dispatch_pending(gstctx.display->display); + + + wth_verbose("wth_receiver_gst_main exiting\n"); + + if (window->display->ivi_application) { + ivi_surface_destroy(window->ivi_surface); + ivi_application_destroy(window->display->ivi_application); + } + + gst_element_set_state((GstElement*)((void*)gstctx.pipeline), GST_STATE_NULL); + destroy_window(window); + destroy_display(gstctx.display); + + wth_verbose(" <<< %s \n",__func__); + + return 0; +} diff --git a/waltham-receiver/src/wth-receiver-main.c b/waltham-receiver/src/wth-receiver-main.c new file mode 100644 index 0000000..cce1e83 --- /dev/null +++ b/waltham-receiver/src/wth-receiver-main.c @@ -0,0 +1,334 @@ +/* + * Copyright © 2019 Advanced Driver Information Technology GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/******************************************************************************* +** ** +** TARGET : linux ** +** ** +** PROJECT : waltham-receiver ** +** ** +** PURPOSE : This file handles connection with remote-client ** +** ** +*******************************************************************************/ + +#include <signal.h> +#include "wth-receiver-comm.h" + +#define MAX_EPOLL_WATCHES 2 + +uint16_t tcp_port; + +/** Print out the application help + */ +static void usage(void) +{ + printf("Usage: waltham receiver [options]\n"); + printf("Options:\n"); + printf(" -p --port number TCP port number\n"); + printf(" -h --help Usage\n"); + printf(" -v --verbose Set verbose flag (Default:%d)\n", get_verbosity()); +} + +static struct option long_options[] = { + {"port", required_argument, 0, 'p'}, + {"verbose", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} +}; + +/** + * parse_args + * + * Parses the application arguments + * The arguments are parsed and saved in static structure for future use. + * + * @param argc The amount of arguments + * @param argv The table of arguments + * + * @return 0 on success, -1 otherwise + */ +static int parse_args(int argc, char *argv[]) +{ + int c = -1; + int long_index = 0; + + while ((c = getopt_long(argc, + argv, + "p:vh", + long_options, + &long_index)) != -1) + { + switch (c) + { + case 'p': + tcp_port = atoi(optarg); + break; + case 'v': +#if DEBUG + set_verbosity(1); +#else + printf("No verbose logs for release mode"); +#endif + break; + case 'h': + usage(); + return -1; + default: + wth_error("Try %s -h for more information.\n", argv[0]); + return -1; + } + } + + if (tcp_port == 0) + { + wth_error("TCP port not set \n"); + wth_error("Try %s -h for more information.\n", argv[0]); + return -1; + } + + return 0; +} + +static int +watch_ctl(struct watch *w, int op, uint32_t events) +{ + wth_verbose("%s >>> \n",__func__); + struct epoll_event ee; + + ee.events = events; + ee.data.ptr = w; + wth_verbose(" <<< %s \n",__func__); + return epoll_ctl(w->receiver->epoll_fd, op, w->fd, &ee); +} + +/** +* listen_socket_handle_data +* +* Handles all incoming events on socket +* +* @param names struct watch *w ,uint32_t events +* @param value pointer to watch connection it holds receiver information, Incoming events information +* @return none +*/ +static void +listen_socket_handle_data(struct watch *w, uint32_t events) +{ + wth_verbose("%s >>> \n",__func__); + struct receiver *srv = container_of(w, struct receiver, listen_watch); + + if (events & EPOLLERR) { + wth_error("Listening socket errored out.\n"); + srv->running = false; + + return; + } + + if (events & EPOLLHUP) { + wth_error("Listening socket hung up.\n"); + srv->running = false; + + return; + } + + if (events & EPOLLIN) + { + wth_verbose("EPOLLIN evnet received. \n"); + receiver_accept_client(srv); + } + wth_verbose(" <<< %s \n",__func__); +} + +/** +* receiver_mainloop +* +* This is the main loop, which will flush all pending clients requests and +* listen to input events from socket +* +* @param names void *data +* @param value pointer to receiver struct - +* struct holds the client connection information +* @return none +*/ +static void +receiver_mainloop(struct receiver *srv) +{ + wth_verbose("%s >>> \n",__func__); + + struct epoll_event ee[MAX_EPOLL_WATCHES]; + struct watch *w; + int count; + int i; + + srv->running = true; + + while (srv->running) { + /* Run any idle tasks at this point. */ + + receiver_flush_clients(srv); + + /* Wait for events or signals */ + count = epoll_wait(srv->epoll_fd, + ee, ARRAY_LENGTH(ee), -1); + if (count < 0 && errno != EINTR) { + perror("Error with epoll_wait"); + break; + } + + /* Handle all fds, both the listening socket + * (see listen_socket_handle_data()) and clients + * (see connection_handle_data()). + */ + for (i = 0; i < count; i++) { + w = ee[i].data.ptr; + w->cb(w, ee[i].events); + } + } + wth_verbose(" <<< %s \n",__func__); +} + +static int +receiver_listen(uint16_t tcp_port) +{ + wth_verbose("%s >>> \n",__func__); + int fd; + int reuse = 1; + struct sockaddr_in addr; + + fd = socket(AF_INET, SOCK_STREAM, 0); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(tcp_port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof reuse); + + if (bind(fd, (struct sockaddr *)&addr, sizeof addr) < 0) { + wth_error("Failed to bind to port %d", tcp_port); + close(fd); + return -1; + } + + if (listen(fd, 1024) < 0) { + wth_error("Failed to listen to port %d", tcp_port); + close (fd); + return -1; + } + + wth_verbose(" <<< %s \n",__func__); + return fd; +} + +static bool *signal_int_handler_run_flag; + +static void +signal_int_handler(int signum) +{ + wth_verbose("%s >>> \n",__func__); + if (!*signal_int_handler_run_flag) + abort(); + + *signal_int_handler_run_flag = false; + wth_verbose(" <<< %s \n",__func__); +} + +static void +set_sigint_handler(bool *running) +{ + wth_verbose("%s >>> \n",__func__); + struct sigaction sigint; + + signal_int_handler_run_flag = running; + sigint.sa_handler = signal_int_handler; + sigemptyset(&sigint.sa_mask); + sigint.sa_flags = SA_RESETHAND; + sigaction(SIGINT, &sigint, NULL); + wth_verbose(" <<< %s \n",__func__); +} + +/** +* main +* +* waltham receiver main function, it accepts tcp port number as argument. +* Establishes connection on the port and listen to port for incoming connection +* request from waltham clients +* +* @param names argv - argument list and argc -argument count +* @param value tcp port number as argument +* @return 0 on success, -1 on error +*/ +int +main(int argc, char *argv[]) +{ + struct receiver srv = { 0 }; + struct client *c; + + wth_verbose("%s >>> \n",__func__); + + /* Get command line arguments */ + if (parse_args(argc, argv) != 0) + { + return -1; + } + + set_sigint_handler(&srv.running); + + wl_list_init(&srv.client_list); + + srv.epoll_fd = epoll_create1(EPOLL_CLOEXEC); + if (srv.epoll_fd == -1) { + perror("Error on epoll_create1"); + exit(1); + } + + srv.listen_fd = receiver_listen(tcp_port); + if (srv.listen_fd < 0) { + perror("Error setting up listening socket"); + exit(1); + } + + srv.listen_watch.receiver = &srv; + srv.listen_watch.cb = listen_socket_handle_data; + srv.listen_watch.fd = srv.listen_fd; + if (watch_ctl(&srv.listen_watch, EPOLL_CTL_ADD, EPOLLIN) < 0) { + perror("Error setting up listen polling"); + exit(1); + } + + wth_verbose("Waltham receiver listening on TCP port %u...\n",tcp_port); + + + receiver_mainloop(&srv); + + /* destroy all things */ + wl_list_last_until_empty(c, &srv.client_list, link) + client_destroy(c); + + close(srv.listen_fd); + close(srv.epoll_fd); + + wth_verbose(" <<< %s \n",__func__); + return 0; +} |