--- /dev/null
+/*
+* Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef __TIZEN_MEDIA_BRIDGE_INTERNAL_H__
+#define __TIZEN_MEDIA_BRIDGE_INTERNAL_H__
+
+#include <stdint.h>
+#include <tizen.h>
+#include <media_packet.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file media_bridge_internal.h
+ * @brief This file contains the media bridge internal API.
+ */
+
+/**
+ * @addtogroup CAPI_MEDIA_TOOL_MEDIA_BRIDGE_INTERNAL_MODULE
+ * @{
+ */
+
+/**
+ * @internal
+ * @brief Media Bridge handle type.
+ * @since_tizen 6.5
+ */
+typedef struct media_bridge_s *media_bridge_h;
+
+/**
+ * @internal
+ * @brief Enumerations of media bridge error.
+ * @since_tizen 6.5
+ */
+typedef enum {
+ MEDIA_BRIDGE_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */
+ MEDIA_BRIDGE_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */
+ MEDIA_BRIDGE_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */
+ MEDIA_BRIDGE_ERROR_INVALID_OPERATION = TIZEN_ERROR_INVALID_OPERATION, /**< Invalid operation */
+ MEDIA_BRIDGE_ERROR_INVALID_STATE = TIZEN_ERROR_MEDIA_TOOL | 0x11, /**< Invalid state */
+ MEDIA_BRIDGE_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< The feature is not supported */
+} media_bridge_error_e;
+
+/**
+ * @internal
+ * @brief Enumeration for the media bridge state.
+ * @since_tizen 6.5
+ */
+typedef enum {
+ MEDIA_BRIDGE_STATE_NONE, /**< None */
+ MEDIA_BRIDGE_STATE_CREATED, /**< Created */
+ MEDIA_BRIDGE_STATE_STREAMING /**< Now streaming */
+} media_bridge_state_e;
+
+/**
+ * @internal
+ * @brief Enumeration for source of sink module of the media bridge.
+ * @since_tizen 6.5
+ */
+typedef enum {
+ MEDIA_BRIDGE_MODULE_CAMERA, /**< Media camera */
+ MEDIA_BRIDGE_MODULE_CODEC, /**< Media codec */
+ MEDIA_BRIDGE_MODULE_PLAYER, /**< Media player */
+ MEDIA_BRIDGE_MODULE_VISION, /**< Media vision */
+ MEDIA_BRIDGE_MODULE_WEBRTC, /**< Media webrtc */
+ MEDIA_BRIDGE_MODULE_NUM
+} media_bridge_module_e;
+
+
+/**
+ * @internal
+ * @brief The function prototype to set media bridge for source module.
+ * @since_tizen 6.5
+ * @remarks The source module should have the implementation for this function.
+ * @param[in] module_handle The handle to the module
+ * @param[in] bridge The handle to the media bridge
+ * @see media_bridge_set_source()
+ */
+typedef int (*module_media_bridge_set_bridge_func)(void *module_handle, media_bridge_h bridge);
+
+/**
+ * @internal
+ * @brief The function prototype to unset media bridge for source module.
+ * @since_tizen 6.5
+ * @remarks The source module should have the implementation for this function.
+ * @param[in] module_handle The handle to the module
+ * @see media_bridge_unset_source()
+ */
+typedef int (*module_media_bridge_unset_bridge_func)(void *module_handle);
+
+/**
+ * @internal
+ * @brief The function prototype to push media packet to sink module.
+ * @since_tizen 6.5
+ * @remarks The sink module should have the implementation for this function.
+ * @param[in] module_handle The handle to the module
+ * @param[in] bridge The handle to the media bridge
+ * @param[in] sink_id The id of the added sink
+ * @param[in] packet The media packet from source module
+ * @see media_bridge_unset_source()
+ */
+typedef int (*module_media_bridge_push_packet_func)(void *module_handle, media_bridge_h bridge, int sink_id, media_packet_h packet);
+
+
+/**
+ * @internal
+ * @brief Creates a new media bridge handle.
+ * @since_tizen 6.5
+ * @param[out] bridge A newly returned handle to the media bridge
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_BRIDGE_ERROR_NONE Successful
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_PARAMETER Invalid parameter
+ * @post If it succeeds, the state will be #MEDIA_BRIDGE_STATE_CREATED.
+ * @see media_bridge_destroy()
+ */
+int media_bridge_create(media_bridge_h *bridge);
+
+/**
+ * @internal
+ * @brief Destroys the media bridge handle and releases all its resources.
+ * @since_tizen 6.5
+ * @param[in] bridge The handle to the media bridge
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_BRIDGE_ERROR_NONE Successful
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_STATE Invalid state
+ * @pre The state must be set to #MEDIA_BRIDGE_STATE_CREATED.
+ * @see media_bridge_create()
+ */
+int media_bridge_destroy(media_bridge_h bridge);
+
+/**
+ * @internal
+ * @brief Sets the source module for media bridge.
+ * @since_tizen 6.5
+ * @remarks This function should be called before streaming(see media_bridge_start()).
+ * @param[in] bridge The handle to the media bridge
+ * @param[in] module The module that provides buffers
+ * @param[in] module_handle The handle to the module
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_BRIDGE_ERROR_NONE Successful
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_STATE Invalid state
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_OPERATION Invalid operation
+ * @retval #MEDIA_BRIDGE_ERROR_NOT_SUPPORTED The feature is not supported
+ * @pre The state must be set to #MEDIA_BRIDGE_STATE_CREATED.
+ * @see media_bridge_create()
+ * @see media_bridge_unset_source()
+ */
+int media_bridge_set_source(media_bridge_h bridge, media_bridge_module_e module, void *module_handle);
+
+/**
+ * @internal
+ * @brief Unsets the source module for media bridge.
+ * @since_tizen 6.5
+ * @param[in] bridge The handle to the media bridge
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_BRIDGE_ERROR_NONE Successful
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_STATE Invalid state
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_OPERATION Invalid operation
+ * @pre The state must be set to #MEDIA_BRIDGE_STATE_CREATED.
+ * @see media_bridge_set_source()
+ */
+int media_bridge_unset_source(media_bridge_h bridge);
+
+/**
+ * @internal
+ * @brief Adds the sink module for media bridge.
+ * @since_tizen 6.5
+ * @param[in] bridge The handle to the media bridge
+ * @param[in] module The module that consumes buffers
+ * @param[in] module_handle The handle to the module
+ * @param[out] sink_id The id of the added sink
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_BRIDGE_ERROR_NONE Successful
+ * @retval #MEDIA_BRIDGE_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_STATE Invalid state
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_OPERATION Invalid operation
+ * @retval #MEDIA_BRIDGE_ERROR_NOT_SUPPORTED The feature is not supported
+ * @pre The state must be set to #MEDIA_BRIDGE_STATE_CREATED.
+ * @see media_bridge_create()
+ * @see media_bridge_remove_sink()
+ */
+int media_bridge_add_sink(media_bridge_h bridge, media_bridge_module_e module, void *module_handle, int *sink_id);
+
+/**
+ * @internal
+ * @brief Removes the sink module for media bridge.
+ * @since_tizen 6.5
+ * @param[in] bridge The handle to the media bridge
+ * @param[in] sink_id The id of the added sink
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_BRIDGE_ERROR_NONE Successful
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_STATE Invalid state
+ * @pre The state must be set to #MEDIA_BRIDGE_STATE_CREATED.
+ * @see media_bridge_create()
+ * @see media_bridge_add_sink()
+ */
+int media_bridge_remove_sink(media_bridge_h bridge, int sink_id);
+
+/**
+ * @internal
+ * @brief Starts the streaming of media bridge.
+ * @since_tizen 6.5
+ * @param[in] bridge The handle to the media bridge
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_BRIDGE_ERROR_NONE Successful
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_STATE Invalid state
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_OPERATION Invalid operation
+ * @pre The state must be set to #MEDIA_BRIDGE_STATE_CREATED.
+ * @pre The source module should be set through media_bridge_set_source() \n
+ and the sink module should be added through media_bridge_add_sink().
+ * @post If it succeeds, the state will be #MEDIA_BRIDGE_STATE_STREAMING and \n
+ * buffers will be delivered from source module to sink modules automatically.
+ * @see media_bridge_stop()
+ */
+int media_bridge_start(media_bridge_h bridge);
+
+/**
+ * @internal
+ * @brief Stops the streaming of media bridge.
+ * @since_tizen 6.5
+ * @param[in] bridge The handle to the media bridge
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_BRIDGE_ERROR_NONE Successful
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_STATE Invalid state
+ * @pre The state must be set to #MEDIA_BRIDGE_STATE_STREAMING.
+ * @post If it succeeds, the state will be #MEDIA_BRIDGE_STATE_CREATED and \n
+ * it's stopped to deliver buffers from source module to sink modules.
+ * @see media_bridge_start()
+ */
+int media_bridge_stop(media_bridge_h bridge);
+
+/**
+ * @internal
+ * @brief Gets the state of media bridge.
+ * @since_tizen 6.5
+ * @param[in] bridge The handle to the media bridge
+ * @param[out] state The current state of the media bridge
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_BRIDGE_ERROR_NONE Successful
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int media_bridge_get_state(media_bridge_h bridge, media_bridge_state_e *state);
+
+/**
+ * @internal
+ * @brief Pushes media packet to media bridge.
+ * @since_tizen 6.5
+ * @param[in] bridge The handle to the media bridge
+ * @param[in] packet The handle to the media packet
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_BRIDGE_ERROR_NONE Successful
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_STATE Invalid state
+ * @retval #MEDIA_BRIDGE_ERROR_INVALID_OPERATION Invalid operation
+ * @pre The state must be set to #MEDIA_BRIDGE_STATE_STREAMING.
+ * @see media_bridge_start()
+ */
+int media_bridge_push_packet(media_bridge_h bridge, media_packet_h packet);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TIZEN_MEDIA_BRIDGE_INTERNAL_H__ */
--- /dev/null
+/*
+* Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+
+#include <dlog.h>
+#include <media_bridge_private.h>
+
+
+static media_bridge_module_name_table g_media_bridge_module_name_table[MEDIA_BRIDGE_MODULE_NUM] = {
+ /* MEDIA_BRIDGE_MODULE_CAMERA */
+ {PATH_LIBDIR"/libcapi-media-camera.so.0",
+ "camera_media_bridge_set_bridge",
+ "camera_media_bridge_unset_bridge",
+ NULL},
+ /* MEDIA_BRIDGE_MODULE_PLAYER */
+ {PATH_LIBDIR"/libcapi-media-player.so.0",
+ NULL,
+ NULL,
+ NULL},
+ /* MEDIA_BRIDGE_MODULE_VISION */
+ {PATH_LIBDIR"/libmv_common.so",
+ NULL,
+ NULL,
+ NULL},
+ /* MEDIA_BRIDGE_MODULE_CODEC */
+ {PATH_LIBDIR"/libcapi-media-codec.so.0",
+ NULL,
+ NULL,
+ NULL},
+ /* MEDIA_BRIDGE_MODULE_WEBRTC */
+ {PATH_LIBDIR"/libcapi-media-webrtc.so.0",
+ NULL,
+ NULL,
+ "webrtc_media_bridge_push_packet"}
+};
+
+
+static void __media_bridge_packet_queue_release(gpointer data)
+{
+ media_packet_h packet = (media_packet_h)data;
+
+ if (!packet) {
+ LOGE("NULL packet");
+ return;
+ }
+
+ LOGI("release remained packet[%p]", packet);
+
+ media_packet_unref(packet);
+}
+
+
+static int __media_bridge_unset_source_no_lock(media_bridge_s *handle)
+{
+ int ret = MEDIA_BRIDGE_ERROR_NONE;
+
+ MEDIA_BRIDGE_NULL_CHECK(handle);
+
+ if (!handle->src.dl_handle || !handle->src.module_handle ||
+ !handle->src.unset_bridge_func) {
+ LOGE("invalid source[%d:%p,%p,%p]",
+ handle->src.module, handle->src.module_handle,
+ handle->src.dl_handle, handle->src.unset_bridge_func);
+ return MEDIA_BRIDGE_ERROR_INVALID_OPERATION;
+ }
+
+ ret = handle->src.unset_bridge_func(handle->src.module_handle);
+ if (ret != MEDIA_BRIDGE_ERROR_NONE) {
+ LOGE("unset media bridge failed[0x%x]", ret);
+ return ret;
+ }
+
+ dlclose(handle->src.dl_handle);
+ memset(&handle->src, 0x0, sizeof(media_bridge_source_s));
+
+ return MEDIA_BRIDGE_ERROR_NONE;
+}
+
+
+static int __media_bridge_remove_all_sink_no_lock(media_bridge_s *handle)
+{
+ int id = 0;
+ media_bridge_sink_s *sink = NULL;
+
+ MEDIA_BRIDGE_NULL_CHECK(handle);
+
+ for (id = 0 ; id < MEDIA_BRIDGE_SINK_MAX ; id++) {
+ sink = &handle->sink[id];
+ if (sink->dl_handle) {
+ LOGI("remove sink[id:%d,t:%d,%p,%p]",
+ id, sink->module, sink->module_handle, sink->dl_handle);
+ dlclose(sink->dl_handle);
+ memset(sink, 0x0, sizeof(media_bridge_sink_s));
+ }
+ }
+
+ handle->sink_count = 0;
+
+ return MEDIA_BRIDGE_ERROR_NONE;
+}
+
+
+static gpointer __media_bridge_push_packet_func(gpointer data)
+{
+ int id = 0;
+ int push_count = 0;
+ int ret = 0;
+ media_bridge_s *handle = (media_bridge_s *)data;
+ media_packet_h packet = NULL;
+ media_bridge_sink_s *sink = NULL;
+
+ if (!handle) {
+ LOGE("NULL handle");
+ return NULL;
+ }
+
+ LOGI("push packet thread[%p,%p]", handle, handle->push_packet_thread);
+
+ g_mutex_lock(&handle->lock);
+
+ while (handle->state != MEDIA_BRIDGE_STATE_NONE) {
+ if (g_queue_is_empty(handle->packet_queue))
+ g_cond_wait(&handle->cond, &handle->lock);
+
+ packet = g_queue_pop_head(handle->packet_queue);
+ if (!packet) {
+ LOGW("NULL packet, bridge state[%d]", handle->state);
+ continue;
+ }
+
+ g_mutex_unlock(&handle->lock);
+
+ LOGD("[%p] push packet[%p] to sink[count:%d]", handle, packet, handle->sink_count);
+
+ push_count = 0;
+
+ for (id = 0 ; id < MEDIA_BRIDGE_SINK_MAX ; id++) {
+ sink = &handle->sink[id];
+
+ if (!sink->push_packet_func)
+ continue;
+
+ ret = media_packet_ref(packet);
+ if (ret != MEDIA_PACKET_ERROR_NONE) {
+ LOGE("failed[0x%x] to ref packet[%p] for sink[%d,t:%d,h:%p]",
+ ret, packet, id, sink->module, sink->module_handle);
+ continue;
+ }
+
+ ret = sink->push_packet_func(sink->module_handle, (media_bridge_h)handle, id, packet);
+ if (ret != MEDIA_BRIDGE_ERROR_NONE) {
+ LOGE("failed[0x%x] to push media packet[module:%d,%p, bridge:%p, id:%d]",
+ ret, sink->module, sink->module_handle, handle, id);
+ media_packet_unref(packet);
+ continue;
+ }
+
+ push_count++;
+ }
+
+ media_packet_unref(packet);
+ packet = NULL;
+
+ if (handle->sink_count != push_count)
+ LOGW("something wrong[sink count:%d vs push count:%d]", handle->sink_count, push_count);
+
+ g_mutex_lock(&handle->lock);
+ }
+
+ g_mutex_unlock(&handle->lock);
+
+ LOGI("leave: push packet thread[%p,%p]", handle, handle->push_packet_thread);
+
+ return NULL;
+}
+
+
+int media_bridge_create(media_bridge_h *bridge)
+{
+ media_bridge_s *new_handle = NULL;
+
+ MEDIA_BRIDGE_NULL_CHECK(bridge);
+
+ new_handle = g_new0(media_bridge_s, 1);
+
+ new_handle->state = MEDIA_BRIDGE_STATE_CREATED;
+ new_handle->packet_queue = g_queue_new();
+
+ g_mutex_init(&new_handle->lock);
+ g_cond_init(&new_handle->cond);
+
+ new_handle->push_packet_thread = g_thread_try_new("media_bridge_push_packet_thread",
+ __media_bridge_push_packet_func, (gpointer)new_handle, NULL);
+ if (!new_handle->push_packet_thread) {
+ LOGE("push_packet_thread failed");
+ goto _CREATE_FAILED;
+ }
+
+ LOGI("The new bridge handle[%p]", new_handle);
+
+ *bridge = (media_bridge_h)new_handle;
+
+ return MEDIA_BRIDGE_ERROR_NONE;
+
+_CREATE_FAILED:
+ g_cond_clear(&new_handle->cond);
+ g_mutex_clear(&new_handle->lock);
+ g_queue_free_full(new_handle->packet_queue, __media_bridge_packet_queue_release);
+ g_free(new_handle);
+
+ return MEDIA_BRIDGE_ERROR_INVALID_OPERATION;
+}
+
+
+int media_bridge_destroy(media_bridge_h bridge)
+{
+ int ret = MEDIA_BRIDGE_ERROR_NONE;
+ media_bridge_s *handle = (media_bridge_s *)bridge;
+
+ MEDIA_BRIDGE_NULL_CHECK(handle);
+
+ g_mutex_lock(&handle->lock);
+
+ if (handle->state != MEDIA_BRIDGE_STATE_CREATED) {
+ LOGE("state[%d] is not CREATED", handle->state);
+ g_mutex_unlock(&handle->lock);
+ return MEDIA_BRIDGE_ERROR_INVALID_STATE;
+ }
+
+ LOGI("Release bridge handle[%p]", handle);
+
+ handle->state = MEDIA_BRIDGE_STATE_NONE;
+
+ g_cond_signal(&handle->cond);
+ g_mutex_unlock(&handle->lock);
+
+ LOGI("join push_packet_thread[%p]", handle->push_packet_thread);
+
+ g_thread_join(handle->push_packet_thread);
+ handle->push_packet_thread = NULL;
+
+ LOGI("join done");
+
+ g_cond_clear(&handle->cond);
+ g_mutex_clear(&handle->lock);
+ g_queue_free_full(handle->packet_queue, __media_bridge_packet_queue_release);
+
+ if (handle->src.dl_handle) {
+ ret = __media_bridge_unset_source_no_lock(handle);
+ LOGW("__media_bridge_unset_source_no_lock ret[0x%x]", ret);
+ }
+
+ __media_bridge_remove_all_sink_no_lock(handle);
+
+ memset(handle, 0x0, sizeof(media_bridge_s));
+
+ g_free(handle);
+
+ return MEDIA_BRIDGE_ERROR_NONE;
+}
+
+
+int media_bridge_set_source(media_bridge_h bridge, media_bridge_module_e module, void *module_handle)
+{
+ int ret = MEDIA_BRIDGE_ERROR_NONE;
+ media_bridge_s *handle = (media_bridge_s *)bridge;
+ void *dl_handle = NULL;
+ module_media_bridge_set_bridge_func set_bridge_func = NULL;
+ module_media_bridge_unset_bridge_func unset_bridge_func = NULL;
+ const char *library_path = NULL;
+ const char *set_bridge = NULL;
+ const char *unset_bridge = NULL;
+
+ MEDIA_BRIDGE_NULL_CHECK(handle);
+ MEDIA_BRIDGE_NULL_CHECK(module_handle);
+
+ if (module < MEDIA_BRIDGE_MODULE_CAMERA || module >= MEDIA_BRIDGE_MODULE_NUM) {
+ LOGE("invalid module[%d]", module);
+ return MEDIA_BRIDGE_ERROR_INVALID_PARAMETER;
+ }
+
+ g_mutex_lock(&handle->lock);
+
+ if (handle->state != MEDIA_BRIDGE_STATE_CREATED) {
+ LOGE("state[%d] is not CREATED", handle->state);
+ ret = MEDIA_BRIDGE_ERROR_INVALID_STATE;
+ goto _SET_SOURCE_OUT;
+ }
+
+ if (handle->src.module_handle) {
+ LOGE("source[%p] is already set", handle->src.module_handle);
+ ret = MEDIA_BRIDGE_ERROR_INVALID_OPERATION;
+ goto _SET_SOURCE_OUT;
+ }
+
+ library_path = g_media_bridge_module_name_table[module].library_path;
+ set_bridge = g_media_bridge_module_name_table[module].set_bridge;
+ unset_bridge = g_media_bridge_module_name_table[module].unset_bridge;
+
+ if (!library_path || !set_bridge || !unset_bridge) {
+ LOGE("module[%d] is not supported[%s,%s,%s] for source",
+ module, library_path, set_bridge, unset_bridge);
+ ret = MEDIA_BRIDGE_ERROR_NOT_SUPPORTED;
+ goto _SET_SOURCE_OUT;
+ }
+
+ LOGI("open[%s]", library_path);
+
+ dl_handle = dlopen(library_path, RTLD_NOW);
+ if (!dl_handle) {
+ LOGE("open[%s] failed[errno:%d]", library_path, errno);
+ ret = MEDIA_BRIDGE_ERROR_INVALID_OPERATION;
+ goto _SET_SOURCE_OUT;
+ }
+
+ set_bridge_func = dlsym(dl_handle, set_bridge);
+ unset_bridge_func = dlsym(dl_handle, unset_bridge);
+ if (!set_bridge_func || !unset_bridge_func) {
+ LOGE("module[%d] symbol[%s,%s] failed[%s]",
+ module, set_bridge, unset_bridge, dlerror());
+ ret = MEDIA_BRIDGE_ERROR_INVALID_OPERATION;
+ goto _SET_SOURCE_OUT;
+ }
+
+ ret = set_bridge_func(module_handle, bridge);
+ if (ret != MEDIA_BRIDGE_ERROR_NONE) {
+ LOGE("set media bridge failed[0x%x]", ret);
+ goto _SET_SOURCE_OUT;
+ }
+
+ handle->src.module = module;
+ handle->src.dl_handle = dl_handle;
+ handle->src.module_handle = module_handle;
+ handle->src.set_bridge_func = set_bridge_func;
+ handle->src.unset_bridge_func = unset_bridge_func;
+
+ LOGI("bridge[%p] set source[module:%d,%p] done", bridge, module, module_handle);
+
+_SET_SOURCE_OUT:
+ if (ret != MEDIA_BRIDGE_ERROR_NONE && dl_handle)
+ dlclose(dl_handle);
+
+ g_mutex_unlock(&handle->lock);
+
+ return ret;
+}
+
+
+int media_bridge_unset_source(media_bridge_h bridge)
+{
+ int ret = MEDIA_BRIDGE_ERROR_NONE;
+ media_bridge_s *handle = (media_bridge_s *)bridge;
+
+ MEDIA_BRIDGE_NULL_CHECK(handle);
+
+ g_mutex_lock(&handle->lock);
+
+ if (handle->state != MEDIA_BRIDGE_STATE_CREATED) {
+ LOGE("state[%d] is not CREATED", handle->state);
+ ret = MEDIA_BRIDGE_ERROR_INVALID_STATE;
+ goto _UNSET_SOURCE_OUT;
+ }
+
+ LOGI("[%p] unset source[%d:%p]",
+ bridge, handle->src.module, handle->src.module_handle);
+
+ ret = __media_bridge_unset_source_no_lock(handle);
+
+ if (ret == MEDIA_BRIDGE_ERROR_NONE)
+ LOGI("[%p] unset source done", handle);
+
+_UNSET_SOURCE_OUT:
+ g_mutex_unlock(&handle->lock);
+
+ return ret;
+}
+
+
+int media_bridge_add_sink(media_bridge_h bridge, media_bridge_module_e module, void *module_handle, int *sink_id)
+{
+ int ret = MEDIA_BRIDGE_ERROR_NONE;
+ int id = 0;
+ void *dl_handle = NULL;
+ media_bridge_s *handle = (media_bridge_s *)bridge;
+ media_bridge_sink_s *sink = NULL;
+ module_media_bridge_push_packet_func push_packet_func = NULL;
+ const char *library_path = NULL;
+ const char *push_packet = NULL;
+
+ MEDIA_BRIDGE_NULL_CHECK(handle);
+ MEDIA_BRIDGE_NULL_CHECK(module_handle);
+ MEDIA_BRIDGE_NULL_CHECK(sink_id);
+
+ if (module < MEDIA_BRIDGE_MODULE_CAMERA || module >= MEDIA_BRIDGE_MODULE_NUM) {
+ LOGE("invalid module[%d]", module);
+ return MEDIA_BRIDGE_ERROR_INVALID_PARAMETER;
+ }
+
+ g_mutex_lock(&handle->lock);
+
+ if (handle->state != MEDIA_BRIDGE_STATE_CREATED) {
+ LOGE("state[%d] is not CREATED", handle->state);
+ ret = MEDIA_BRIDGE_ERROR_INVALID_STATE;
+ goto _ADD_SINK_OUT;
+ }
+
+ for (id = 0 ; id < MEDIA_BRIDGE_SINK_MAX ; id++) {
+ if (handle->sink[id].push_packet_func == NULL) {
+ LOGI("found empty slot[%d] for sink", id);
+ sink = &handle->sink[id];
+ break;
+ }
+ }
+
+ if (!sink) {
+ LOGE("no empty slot for sink");
+ ret = MEDIA_BRIDGE_ERROR_OUT_OF_MEMORY;
+ goto _ADD_SINK_OUT;
+ }
+
+ library_path = g_media_bridge_module_name_table[module].library_path;
+ push_packet = g_media_bridge_module_name_table[module].push_packet;
+
+ if (!library_path || !push_packet) {
+ LOGE("module[%d] is not supported[%s,%s] for sink", module, library_path, push_packet);
+ ret = MEDIA_BRIDGE_ERROR_NOT_SUPPORTED;
+ goto _ADD_SINK_OUT;
+ }
+
+ LOGI("open[%s]", library_path);
+
+ dl_handle = dlopen(library_path, RTLD_NOW);
+ if (!dl_handle) {
+ LOGE("open[%s] failed[errno:%d]", library_path, errno);
+ ret = MEDIA_BRIDGE_ERROR_INVALID_OPERATION;
+ goto _ADD_SINK_OUT;
+ }
+
+ push_packet_func = dlsym(dl_handle, push_packet);
+ if (!push_packet_func) {
+ LOGE("module[%d] symbol[%s] failed[%s]", module, push_packet, dlerror());
+ ret = MEDIA_BRIDGE_ERROR_INVALID_OPERATION;
+ goto _ADD_SINK_OUT;
+ }
+
+ sink->dl_handle = dl_handle;
+ sink->module = module;
+ sink->module_handle = module_handle;
+ sink->push_packet_func = push_packet_func;
+
+ handle->sink_count++;
+
+ *sink_id = id;
+
+ LOGI("[%p] sink added[module:%d,%p, id:%d] count[%d]",
+ handle, module, module_handle, id, handle->sink_count);
+
+_ADD_SINK_OUT:
+ if (ret != MEDIA_BRIDGE_ERROR_NONE && dl_handle)
+ dlclose(dl_handle);
+
+ g_mutex_unlock(&handle->lock);
+
+ return ret;
+}
+
+
+int media_bridge_remove_sink(media_bridge_h bridge, int sink_id)
+{
+ int ret = MEDIA_BRIDGE_ERROR_NONE;
+ int id = 0;
+ media_bridge_s *handle = (media_bridge_s *)bridge;
+
+ MEDIA_BRIDGE_NULL_CHECK(handle);
+
+ if (sink_id < 0 || sink_id >= MEDIA_BRIDGE_SINK_MAX) {
+ LOGE("invalid sink id[%d]", sink_id);
+ return MEDIA_BRIDGE_ERROR_INVALID_PARAMETER;
+ }
+
+ g_mutex_lock(&handle->lock);
+
+ if (handle->state != MEDIA_BRIDGE_STATE_CREATED) {
+ LOGE("state[%d] is not CREATED", handle->state);
+ ret = MEDIA_BRIDGE_ERROR_INVALID_STATE;
+ goto _REMOVE_SINK_OUT;
+ }
+
+ if (handle->sink[sink_id].dl_handle == NULL) {
+ LOGE("sink_id[%d] is empty", sink_id);
+ ret = MEDIA_BRIDGE_ERROR_INVALID_PARAMETER;
+ goto _REMOVE_SINK_OUT;
+ }
+
+ dlclose(handle->sink[sink_id].dl_handle);
+
+ memset(&handle->sink[sink_id], 0x0, sizeof(media_bridge_sink_s));
+
+ handle->sink_count--;
+
+ LOGI("[%p] sink removed[id:%d,count:%d]", sink_id, handle->sink_count);
+
+_REMOVE_SINK_OUT:
+ g_mutex_unlock(&handle->lock);
+
+ return ret;
+}
+
+
+int media_bridge_start(media_bridge_h bridge)
+{
+ media_bridge_s *handle = (media_bridge_s *)bridge;
+
+ MEDIA_BRIDGE_NULL_CHECK(handle);
+
+ g_mutex_lock(&handle->lock);
+
+ if (handle->state != MEDIA_BRIDGE_STATE_CREATED) {
+ LOGE("state[%d] is not CREATED", handle->state);
+ g_mutex_unlock(&handle->lock);
+ return MEDIA_BRIDGE_ERROR_INVALID_STATE;
+ }
+
+ if (handle->sink_count < 1) {
+ LOGE("no sink is added");
+ g_mutex_unlock(&handle->lock);
+ return MEDIA_BRIDGE_ERROR_INVALID_OPERATION;
+ }
+
+ handle->state = MEDIA_BRIDGE_STATE_STREAMING;
+
+ LOGI("[%p] set state to [STREAMING]", handle);
+
+ g_mutex_unlock(&handle->lock);
+
+ return MEDIA_BRIDGE_ERROR_NONE;
+}
+
+
+int media_bridge_stop(media_bridge_h bridge)
+{
+ media_bridge_s *handle = (media_bridge_s *)bridge;
+
+ MEDIA_BRIDGE_NULL_CHECK(handle);
+
+ g_mutex_lock(&handle->lock);
+
+ if (handle->state != MEDIA_BRIDGE_STATE_STREAMING) {
+ LOGE("state[%d] is not STREAMING", handle->state);
+ g_mutex_unlock(&handle->lock);
+ return MEDIA_BRIDGE_ERROR_INVALID_STATE;
+ }
+
+ handle->state = MEDIA_BRIDGE_STATE_CREATED;
+
+ LOGI("[%p] set state to [CREATED]", handle);
+
+ g_mutex_unlock(&handle->lock);
+
+ return MEDIA_BRIDGE_ERROR_NONE;
+}
+
+
+int media_bridge_get_state(media_bridge_h bridge, media_bridge_state_e *state)
+{
+ media_bridge_s *handle = (media_bridge_s *)bridge;
+
+ MEDIA_BRIDGE_NULL_CHECK(handle);
+ MEDIA_BRIDGE_NULL_CHECK(state);
+
+ *state = handle->state;
+
+ return MEDIA_BRIDGE_ERROR_NONE;
+}
+
+
+int media_bridge_push_packet(media_bridge_h bridge, media_packet_h packet)
+{
+ int ret = MEDIA_BRIDGE_ERROR_NONE;
+ int packet_ret = MEDIA_PACKET_ERROR_NONE;
+ int id = 0;
+ int push_count = 0;
+ media_bridge_s *handle = (media_bridge_s *)bridge;
+
+ MEDIA_BRIDGE_NULL_CHECK(handle);
+
+ g_mutex_lock(&handle->lock);
+
+ if (handle->state != MEDIA_BRIDGE_STATE_STREAMING) {
+ LOGE("state[%d] is not STREAMING", handle->state);
+ ret = MEDIA_BRIDGE_ERROR_INVALID_STATE;
+ goto _PUSH_PACKET_OUT;
+ }
+
+ if (handle->sink_count < 1) {
+ LOGW("no sink is added");
+ goto _PUSH_PACKET_OUT;
+ }
+
+ LOGD("[%p] push packet[%p] to queue", handle, packet);
+
+ g_queue_push_tail(handle->packet_queue, (gpointer)packet);
+ g_cond_signal(&handle->cond);
+
+_PUSH_PACKET_OUT:
+ g_mutex_unlock(&handle->lock);
+
+ if (ret == MEDIA_BRIDGE_ERROR_NONE) {
+ media_packet_unref(packet);
+ LOGI("[%p] push packet[%p] done", handle, packet);
+ } else {
+ LOGE("[%p] push packet[%p] failed[0x%x]", handle, packet, ret);
+ }
+
+ return ret;
+}