*/
#include <webrtc.h>
+#include <media_format.h>
#include <appcore-efl.h>
#include <Elementary.h>
+#include <tbm_surface_internal.h>
#include <glib.h>
+#include <gst/gst.h>
#include <libsoup/soup.h>
#include <json-glib/json-glib.h>
#include <sys/stat.h>
#define MAX_STRING_LEN 512
#define MAX_CHANNEL_LEN 10
#define MAX_CONNECTION_LEN 4
+#define MAX_MEDIA_PACKET_SOURCE_LEN 4
enum {
CURRENT_STATUS_MAINMENU,
CURRENT_STATUS_ADD_MEDIA_SOURCE,
CURRENT_STATUS_REMOVE_MEDIA_SOURCE,
+ CURRENT_STATUS_MEDIA_PACKET_SOURCE_SET_BUFFER_STATE_CHANGED_CB,
+ CURRENT_STATUS_MEDIA_PACKET_SOURCE_UNSET_BUFFER_STATE_CHANGED_CB,
+ CURRENT_STATUS_MEDIA_PACKET_SOURCE_SET_FORMAT,
CURRENT_STATUS_GET_TRANSCEIVER_DIRECTION,
CURRENT_STATUS_SET_TRANSCEIVER_DIRECTION,
CURRENT_STATUS_SET_DISPLAY_TYPE,
CURRENT_STATUS_CHANGE_CONNECTION,
CURRENT_STATUS_REQUEST_SESSION,
CURRENT_STATUS_SEND_LOCAL_DESCRIPTION,
+ CURRENT_STATUS_START_PUSHING_PACKET_TO_MEDIA_PACKET_SOURCE,
+ CURRENT_STATUS_STOP_PUSHING_PACKET_TO_MEDIA_PACKET_SOURCE,
};
enum {
Evas_Object *layout_main;
} appdata_s;
+typedef struct {
+ unsigned int source_id;
+ media_format_h format;
+
+ webrtc_h webrtc;
+ GstElement *src_pipeline;
+ GstElement *src;
+ GstElement *sink;
+ gulong handoff_signal_id;
+ bool is_overflowed;
+ bool is_stop_requested;
+ GCond cond;
+ GMutex mutex;
+} media_packet_source_s;
+
typedef struct _connection_s {
SoupWebsocketConnection *ws_conn;
gint32 local_peer_id;
webrtc_display_type_e display_type;
Evas_Object *eo;
+
+ media_packet_source_s packet_sources[MAX_MEDIA_PACKET_SOURCE_LEN];
} connection_s;
static gchar g_signaling_server[MAX_STRING_LEN];
.terminate = app_terminate,
};
+static void __disconnect_signal(GObject *obj, gulong signal_id)
+{
+ if (!obj || signal_id == 0) {
+ g_printerr("invalid parameter, obj[%p], signal_id[%lu]\n", obj, signal_id);
+ return;
+ }
+
+ if (g_signal_handler_is_connected(obj, signal_id)) {
+ g_signal_handler_disconnect(obj, signal_id);
+ g_print("signal with id[%lu] is disconnected from object [%s]\n", signal_id, GST_OBJECT_NAME(obj));
+ }
+}
+
+static void __release_packet_source(int conn_idx, unsigned int source_idx)
+{
+ if (conn_idx < 0 || conn_idx >= MAX_CONNECTION_LEN)
+ return;
+ if (source_idx < 0 || source_idx >= MAX_MEDIA_PACKET_SOURCE_LEN)
+ return;
+
+ media_packet_source_s *packet_source = &g_conns[conn_idx].packet_sources[source_idx];
+
+ packet_source->source_id = 0;
+ if (packet_source->format) {
+ media_format_unref(packet_source->format);
+ packet_source->format = NULL;
+ }
+ if (packet_source->handoff_signal_id > 0) {
+ __disconnect_signal((GObject *)packet_source->sink, packet_source->handoff_signal_id);
+ packet_source->handoff_signal_id = 0;
+ }
+ g_clear_object(&packet_source->src_pipeline);
+ packet_source->src_pipeline = NULL;
+
+ g_mutex_clear(&packet_source->mutex);
+ g_cond_clear(&packet_source->cond);
+}
+
static void _webrtc_create(int index)
{
int ret = WEBRTC_ERROR_NONE;
g_conns[index].recv_channels[i] = NULL;
}
g_conns[index].channel_index = 0;
+
+ for (i = 0; i < MAX_MEDIA_PACKET_SOURCE_LEN; i++)
+ __release_packet_source(index, i);
}
}
g_print("state: [%s]\n", g_webrtc_state_str[state]);
}
+static int _get_empty_packet_sources_index(int index)
+{
+ int i;
+
+ for (i = 0; i < MAX_MEDIA_PACKET_SOURCE_LEN; i++) {
+ if (g_conns[index].packet_sources[i].source_id == 0)
+ return i;
+ }
+
+ /* array full */
+ return -1;
+}
+
+static int _find_packet_sources_index(int index, unsigned int source_id)
+{
+ int i;
+
+ if (source_id == 0)
+ return -1;
+
+ for (i = 0; i < MAX_MEDIA_PACKET_SOURCE_LEN; i++) {
+ if (g_conns[index].packet_sources[i].source_id == source_id)
+ return i;
+ }
+
+ /* not found */
+ return -1;
+}
+
static void _webrtc_add_media_source(int index, int type)
{
int ret = WEBRTC_ERROR_NONE;
unsigned int source_id = 0;
+ int i;
+
+ if (type == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET) {
+ i = _get_empty_packet_sources_index(index);
+ if (i == -1) {
+ g_print("media packet source can be added up to 4\n");
+ return;
+ }
+ }
ret = webrtc_add_media_source(g_conns[index].webrtc, (webrtc_media_source_type_e)type, &source_id);
- if (ret != WEBRTC_ERROR_NONE)
+ if (ret != WEBRTC_ERROR_NONE) {
g_print("failed to webrtc_add_media_source(), ret[0x%x]\n", ret);
- else
+ } else {
g_print("webrtc_add_media_source() success, source_id[%u]\n", source_id);
+ if (type == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET) {
+ g_conns[index].packet_sources[i].source_id = source_id;
+ g_mutex_init(&g_conns[index].packet_sources[i].mutex);
+ g_cond_init(&g_conns[index].packet_sources[i].cond);
+ }
+ }
}
static void _webrtc_remove_media_source(int index, unsigned int source_id)
{
int ret = WEBRTC_ERROR_NONE;
+ int i;
ret = webrtc_remove_media_source(g_conns[index].webrtc, source_id);
- if (ret != WEBRTC_ERROR_NONE)
+ if (ret != WEBRTC_ERROR_NONE) {
g_print("failed to webrtc_remove_media_source(), source_id[%u], ret[0x%x]\n", source_id, ret);
- else
+ } else {
g_print("webrtc_remove_media_source() success, source_id[%u]\n", source_id);
+ i = _find_packet_sources_index(index, source_id);
+ if (i != -1)
+ __release_packet_source(index, i);
+ }
+}
+
+#define VIDEO_WIDTH 352
+#define VIDEO_HIGHT 288
+#define VIDEO_FRAME_RATE 30
+#define AUDIO_CHANNEL 1
+#define AUDIO_SAMPLERATE 8000
+
+static int __create_formats(media_format_mimetype_e type, media_format_h *format)
+{
+ int ret = MEDIA_FORMAT_ERROR_NONE;
+
+ if (format == NULL) {
+ g_print("format is NULL\n");
+ return -1;
+ }
+
+ ret = media_format_create(format);
+ if (ret != MEDIA_FORMAT_ERROR_NONE) {
+ g_print("failed to media_format_create()\n");
+ return -1;
+ }
+
+ if (type & MEDIA_FORMAT_AUDIO) {
+ ret = media_format_set_audio_mime(*format, type);
+ ret |= media_format_set_audio_channel(*format, AUDIO_CHANNEL);
+ ret |= media_format_set_audio_samplerate(*format, AUDIO_SAMPLERATE);
+ ret |= media_format_set_audio_bit(*format, 16);
+ if (ret != MEDIA_FORMAT_ERROR_NONE) {
+ g_print("failed to set audio format\n");
+ goto error;
+ }
+
+ } else if (type & MEDIA_FORMAT_VIDEO) {
+ ret = media_format_set_video_mime(*format, type);
+ ret |= media_format_set_video_width(*format, VIDEO_WIDTH);
+ ret |= media_format_set_video_height(*format, VIDEO_HIGHT);
+ ret |= media_format_set_video_frame_rate(*format, VIDEO_FRAME_RATE);
+ if (ret != MEDIA_FORMAT_ERROR_NONE) {
+ g_print("failed to set video format\n");
+ goto error;
+ }
+
+ } else {
+ g_print("type is not AUDIO or VIDEO\n");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ media_format_unref(*format);
+ return -1;
+}
+
+static void _webrtc_media_packet_source_set_format(int index, unsigned int source_id, int value)
+{
+ int ret = WEBRTC_ERROR_NONE;
+ media_format_h format = NULL;
+ media_format_mimetype_e type;
+
+ switch (value) {
+ case 1:
+ type = MEDIA_FORMAT_I420;
+ break;
+ case 2:
+ type = MEDIA_FORMAT_NV12;
+ break;
+ case 3:
+ type = MEDIA_FORMAT_PCM_S16LE;
+ break;
+ default:
+ g_print("invalid value[%d]\n", value);
+ return;
+ }
+
+ if (__create_formats(type, &format) == -1)
+ return;
+
+ ret = webrtc_media_packet_source_set_format(g_conns[index].webrtc, source_id, format);
+ if (ret != WEBRTC_ERROR_NONE) {
+ g_print("failed to webrtc_set_media_format(), ret[0x%x]\n", ret);
+ } else {
+ int i = _find_packet_sources_index(index, source_id);
+
+ g_print("webrtc_set_media_format() success, source_id[%u], format[%p]\n", source_id, format);
+
+ if (i == -1) {
+ g_print("could not find media packet source id[%u]\n", source_id);
+ return;
+ }
+
+ if (g_conns[index].packet_sources[i].format)
+ media_format_unref(g_conns[index].packet_sources[i].format);
+ g_conns[index].packet_sources[i].format = format;
+ g_conns[index].packet_sources[i].webrtc = g_conns[index].webrtc;
+ }
}
static void _webrtc_get_transceiver_direction(int index, unsigned int source_id, webrtc_media_type_e media_type)
g_print("webrtc_unset_track_added_cb() success\n");
}
+static void __media_packet_source_buffer_state_changed_cb(unsigned int source_id, webrtc_media_packet_source_buffer_state_e state, void *user_data)
+{
+ connection_s *conn = (connection_s *)user_data;
+ int i;
+
+ if (conn == NULL) {
+ g_printerr("conn is NULL\n");
+ return;
+ }
+
+ g_print("__media_packet_source_buffer_state_changed_cb() is invoked, source_id[%u], state[%s], conn[%p]\n",
+ source_id, state == WEBRTC_MEDIA_PACKET_SOURCE_BUFFER_STATE_OVERFLOW ? "OVERFLOW" : "UNDERFLOW", conn);
+ for (i = 0; i < MAX_MEDIA_PACKET_SOURCE_LEN; i++)
+ if (conn->packet_sources[i].source_id == source_id)
+ break;
+ if (i == MAX_MEDIA_PACKET_SOURCE_LEN) {
+ g_printerr("could not find packet source of source_id[%u]", source_id);
+ return;
+ }
+ g_mutex_lock(&conn->packet_sources[i].mutex);
+ conn->packet_sources[i].is_overflowed = (state == WEBRTC_MEDIA_PACKET_SOURCE_BUFFER_STATE_OVERFLOW);
+ g_mutex_unlock(&conn->packet_sources[i].mutex);
+ if (!conn->packet_sources[i].is_overflowed)
+ g_cond_signal(&conn->packet_sources[i].cond);
+}
+
+static void _webrtc_media_packet_source_set_buffer_state_changed_cb(int index, unsigned int source_id)
+{
+ int ret = WEBRTC_ERROR_NONE;
+
+ ret = webrtc_media_packet_source_set_buffer_state_changed_cb(g_conns[index].webrtc, source_id, __media_packet_source_buffer_state_changed_cb, &g_conns[index]);
+ if (ret != WEBRTC_ERROR_NONE)
+ g_print("failed to webrtc_media_packet_source_set_buffer_state_changed_cb()\n");
+ else
+ g_print("webrtc_media_packet_source_set_buffer_state_changed_cb() success\n");
+}
+
+static void _webrtc_media_packet_source_unset_buffer_state_changed_cb(int index, unsigned int source_id)
+{
+ int ret = WEBRTC_ERROR_NONE;
+
+ ret = webrtc_media_packet_source_unset_buffer_state_changed_cb(g_conns[index].webrtc, source_id);
+ if (ret != WEBRTC_ERROR_NONE)
+ g_print("failed to webrtc_media_packet_source_unset_buffer_state_changed_cb()\n");
+ else
+ g_print("webrtc_media_packet_source_unset_buffer_state_changed_cb() success\n");
+}
+
static void _webrtc_create_offer(int index)
{
int ret = WEBRTC_ERROR_NONE;
soup_websocket_connection_send_text(g_conns[index].ws_conn, desc);
}
+gulong _connect_signal(GObject *obj, const char *signal_name, GCallback callback, gpointer user_data)
+{
+ gulong signal_id;
+
+ if (!obj || !signal_name || !callback) {
+ g_printerr("invalid parameter, obj[%p], signal_name[%s], callback[%p]\n", obj, signal_name, callback);
+ return 0;
+ }
+
+ signal_id = g_signal_connect(obj, signal_name, callback, user_data);
+ if (signal_id == 0) {
+ g_printerr("failed to g_signal_connect(), [%s] for object [%s]\n", signal_name, GST_OBJECT_NAME(obj));
+ return 0;
+ }
+
+ g_print("signal [%s] with id[%lu] is connected to object [%s]\n", signal_name, signal_id, GST_OBJECT_NAME(obj));
+
+ return signal_id;
+}
+
+static int __media_packet_finalize_cb(media_packet_h packet, int error_code, void *user_data)
+{
+ g_print("__media_packet_finalize_cb(), packet[%p], error_code[0x%x], user_data[%p]\n", packet, error_code, user_data);
+
+ return MEDIA_PACKET_FINALIZE;
+}
+
+static void __stream_handoff_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
+{
+ int ret;
+ media_packet_h packet;
+ media_packet_source_s *packet_source = (media_packet_source_s *)data;
+ guchar *data_ptr;
+ gsize size;
+ GstClockTime pts;
+ GstClockTime duration;
+ GstMapInfo buff_info = GST_MAP_INFO_INIT;
+ bool has_tbm_surface;
+ tbm_surface_info_s ts_info;
+
+ if (!object || !buffer || !pad || !packet_source) {
+ g_printerr("invalid parameters, object[%p], buffer[%p], pad[%p], packet_source[%p]\n", object, buffer, pad, packet_source);
+ return;
+ }
+
+ if (packet_source->is_stop_requested) {
+ g_print("stop requested, skip this buffer[%p]\n", buffer);
+ return;
+ }
+
+ g_mutex_lock(&packet_source->mutex);
+ if (packet_source->is_overflowed) {
+ g_print("wait...\n");
+ g_cond_wait(&packet_source->cond, &packet_source->mutex);
+ g_print("wake up...\n");
+ }
+ g_mutex_unlock(&packet_source->mutex);
+
+ size = gst_buffer_get_size(buffer);
+ pts = GST_BUFFER_PTS(buffer);
+ duration = GST_BUFFER_DURATION(buffer);
+
+ g_print("__stream_handoff_cb(), buffer[%p], size[%u], pts[%llu], duration[%llu]\n", buffer, size, pts, duration);
+
+ ret = media_packet_create_alloc(packet_source->format, __media_packet_finalize_cb, packet_source, &packet);
+ if (ret != MEDIA_PACKET_ERROR_NONE) {
+ g_printerr("failed to media_packet_create_alloc()\n");
+ return;
+ }
+
+ gst_buffer_ref(buffer);
+
+ ret = media_packet_set_pts(packet, pts);
+ if (ret != MEDIA_PACKET_ERROR_NONE) {
+ g_printerr("failed to media_packet_set_pts()\n");
+ goto exit;
+ }
+
+ ret = media_packet_set_duration(packet, duration);
+ if (ret != MEDIA_PACKET_ERROR_NONE) {
+ g_printerr("failed to media_packet_set_duration()\n");
+ goto exit;
+ }
+
+ ret = media_packet_set_buffer_size(packet, size);
+ if (ret != MEDIA_PACKET_ERROR_NONE) {
+ g_printerr("failed to media_packet_set_buffer_size()\n");
+ goto exit;
+ }
+
+ ret = media_packet_get_buffer_data_ptr(packet, (void **)&data_ptr);
+ if (ret != MEDIA_PACKET_ERROR_NONE) {
+ g_printerr("failed to media_packet_get_buffer_data_ptr()\n");
+ goto exit;
+ }
+
+ media_packet_has_tbm_surface_buffer(packet, &has_tbm_surface);
+ if (has_tbm_surface) {
+ int ret = TBM_SURFACE_ERROR_NONE;
+ tbm_surface_h ts;
+
+ media_packet_get_tbm_surface(packet, &ts);
+ ret = tbm_surface_get_info(ts, &ts_info);
+ if (ret != TBM_SURFACE_ERROR_NONE) {
+ g_printerr("failed to tbm_surface_get_info()\n");
+ goto exit;
+ }
+ g_print("tbm surface[%p, %ux%u, size:%u, format:%u, num_planes:%u] found\n",
+ ts, ts_info.width, ts_info.height, ts_info.size, ts_info.format, ts_info.num_planes);
+ }
+
+ if (gst_buffer_map(buffer, &buff_info, GST_MAP_READ)) {
+ if (has_tbm_surface) {
+ int i;
+ guint8 *ptr = buff_info.data;
+ for (i = 0; i < ts_info.num_planes; i++) {
+ g_print("plane[%d][ptr:%p size:%u]\n", i, ts_info.planes[i].ptr, ts_info.planes[i].size);
+ memcpy(ts_info.planes[i].ptr, ptr, ts_info.planes[i].size);
+ ptr += ts_info.planes[i].size;
+ }
+ } else {
+ memcpy(data_ptr, buff_info.data, size);
+ }
+ gst_buffer_unmap(buffer, &buff_info);
+ } else
+ g_printerr("failed to gst_buffer_map()\n");
+
+ ret = webrtc_media_packet_source_push_packet(packet_source->webrtc, packet_source->source_id, packet);
+ if (ret != WEBRTC_ERROR_NONE)
+ g_printerr("failed to webrtc_media_packet_source_push_packet()\n");
+
+exit:
+ media_packet_destroy(packet);
+ gst_buffer_unref(buffer);
+}
+
+
+static GstCaps *__make_raw_caps(media_format_h format)
+{
+ GstCaps *caps = NULL;
+ media_format_type_e format_type;
+ media_format_mimetype_e mime_type;
+ gchar *format_str;
+
+ if (media_format_get_type(format, &format_type) != MEDIA_FORMAT_ERROR_NONE) {
+ g_printerr("failed to media_format_get_type()\n");
+ return NULL;
+ }
+
+ if (format_type == MEDIA_FORMAT_AUDIO) {
+ int channels;
+ int samplerate;
+
+ if (media_format_get_audio_info(format, &mime_type, &channels, &samplerate, NULL, NULL) != MEDIA_FORMAT_ERROR_NONE) {
+ g_printerr("failed to media_format_get_audio_info()\n");
+ return NULL;
+ }
+
+ switch (mime_type) {
+ case MEDIA_FORMAT_PCM_S16LE:
+ format_str = "S16LE";
+ break;
+ case MEDIA_FORMAT_PCM_S24LE:
+ format_str = "S24LE";
+ break;
+ default:
+ g_printerr("invalid mime_type[0x%x]\n", mime_type);
+ return NULL;
+ }
+
+ caps = gst_caps_new_simple("audio/x-raw",
+ "format", G_TYPE_STRING, format_str,
+ "channels", G_TYPE_INT, channels,
+ "rate", G_TYPE_INT, samplerate,
+ NULL);
+
+ } else if (format_type == MEDIA_FORMAT_VIDEO) {
+ int width;
+ int height;
+ int framerate;
+
+ if (media_format_get_video_info(format, &mime_type, &width, &height, NULL, NULL) != MEDIA_FORMAT_ERROR_NONE) {
+ g_printerr("failed to media_format_get_video_info()\n");
+ return NULL;
+ }
+
+ if (media_format_get_video_frame_rate(format, &framerate) != MEDIA_FORMAT_ERROR_NONE) {
+ g_printerr("failed to media_format_get_video_frame_rate()\n");
+ return NULL;
+ }
+
+ switch (mime_type) {
+ case MEDIA_FORMAT_I420:
+ format_str = "I420";
+ break;
+ case MEDIA_FORMAT_NV12:
+ format_str = "NV12";
+ break;
+ default:
+ g_printerr("invalid mime_type[0x%x]\n", mime_type);
+ return NULL;
+ }
+
+ caps = gst_caps_new_simple("video/x-raw",
+ "format", G_TYPE_STRING, format_str,
+ "framerate", GST_TYPE_FRACTION, framerate, 1,
+ "width", G_TYPE_INT, width,
+ "height", G_TYPE_INT, height,
+ NULL);
+
+ } else {
+ g_printerr("invalid format_type[0x%x]\n", format_type);
+ return NULL;
+ }
+
+ return caps;
+}
+
+static GstElement* __make_src_pipeline(media_packet_source_s *packet_source)
+{
+ media_format_type_e format_type;
+ GstElement *src;
+ GstElement *capsfilter;
+ const char *factory_name_src = "videotestsrc";
+ const char *factory_name_sink;
+ GstCaps *caps;
+ gchar *caps_str;
+
+ if (!packet_source) {
+ g_printerr("packet_source is NULL\n");
+ return NULL;
+ }
+
+ if (!packet_source->format) {
+ g_printerr("format is not set yet\n");
+ return NULL;
+ }
+
+ packet_source->src_pipeline = gst_pipeline_new("src-pipeline");
+ if (!packet_source) {
+ g_printerr("failed to gst_pipeline_new()\n");
+ return NULL;
+ }
+
+ if (media_format_get_type(packet_source->format, &format_type) != MEDIA_FORMAT_ERROR_NONE) {
+ g_printerr("failed to media_format_get_type()\n");
+ return NULL;
+ }
+
+ if (format_type == MEDIA_FORMAT_AUDIO)
+ factory_name_src = "audiotestsrc";
+ else if (format_type == MEDIA_FORMAT_VIDEO)
+ factory_name_src = "videotestsrc";
+
+ src = gst_element_factory_make(factory_name_src, NULL);
+ if (!src) {
+ g_printerr("failed to gst_element_factory_make(), %s\n", factory_name_src);
+ goto error;
+ }
+
+ g_object_set(G_OBJECT(src), "is-live", TRUE, NULL);
+ if (format_type == MEDIA_FORMAT_VIDEO)
+ g_object_set(G_OBJECT(src), "pattern", 18, NULL); /* 18: ball */
+
+ capsfilter = gst_element_factory_make("capsfilter", NULL);
+ if (!capsfilter) {
+ g_printerr("failed to gst_element_factory_make(), capsfilter\n");
+ goto error;
+ }
+ caps = __make_raw_caps(packet_source->format);
+ if (!caps) {
+ g_printerr("failed to __make_raw_caps()\n");
+ goto error;
+ }
+ caps_str = gst_caps_to_string(caps);
+ g_print("capsfilter caps[%s]\n", caps_str);
+ g_free(caps_str);
+
+ g_object_set(G_OBJECT(capsfilter), "caps", caps, NULL);
+ gst_caps_unref(caps);
+
+ factory_name_sink = "fakesink";
+ packet_source->sink = gst_element_factory_make(factory_name_sink, NULL);
+ if (!packet_source->sink) {
+ g_printerr("failed to gst_element_factory_make(), %s\n", factory_name_sink);
+ goto error;
+ }
+
+ gst_bin_add_many(GST_BIN(packet_source->src_pipeline), src, capsfilter, packet_source->sink, NULL);
+ if (!gst_element_link_many(src, capsfilter, packet_source->sink, NULL)) {
+ g_printerr("failed to gst_element_link_many()\n");
+ goto error;
+ }
+
+ g_object_set(packet_source->sink, "signal-handoffs", TRUE, NULL);
+ packet_source->handoff_signal_id = _connect_signal((GObject *)packet_source->sink, "handoff", G_CALLBACK(__stream_handoff_cb), packet_source);
+ if (packet_source->handoff_signal_id == 0)
+ goto error;
+
+ return packet_source->src_pipeline;
+
+error:
+ gst_object_unref(packet_source->src_pipeline);
+ packet_source->src_pipeline = NULL;
+
+ return NULL;
+}
+
+static void _start_pushing_packet(int index, int source_id)
+{
+ GstStateChangeReturn state_change_ret;
+
+ int i = _find_packet_sources_index(index, source_id);
+ if (i == -1) {
+ g_print("could not find media packet source id[%u]\n", source_id);
+ return;
+ }
+
+ if (g_conns[index].packet_sources[i].format == NULL) {
+ g_print("Please call webrtc_media_packet_source_set_format() first, press 'f'\n");
+ return;
+ }
+
+ if (!g_conns[index].packet_sources[i].src_pipeline) {
+ g_conns[index].packet_sources[i].src_pipeline = __make_src_pipeline(&g_conns[index].packet_sources[i]);
+ if (!g_conns[index].packet_sources[i].src_pipeline)
+ return;
+ }
+
+ state_change_ret = gst_element_set_state(g_conns[index].packet_sources[i].src_pipeline, GST_STATE_PLAYING);
+ if (state_change_ret == GST_STATE_CHANGE_FAILURE) {
+ g_printerr("failed to set state to PLAYING\n");
+ return;
+ }
+
+ g_conns[index].packet_sources[i].is_stop_requested = false;
+
+ g_print("_start_pushing_packet()\n");
+}
+
+static void _stop_pushing_packet(int index, int source_id)
+{
+ int i = _find_packet_sources_index(index, source_id);
+ if (i == -1) {
+ g_print("could not find media packet source id[%u]\n", source_id);
+ return;
+ }
+
+ if (!g_conns[index].packet_sources[i].src_pipeline) {
+ g_print("already stopped for pushing packet\n");
+ return;
+ }
+
+ if (g_conns[index].packet_sources[i].is_overflowed)
+ g_cond_signal(&g_conns[index].packet_sources[i].cond);
+
+ g_conns[index].packet_sources[i].is_stop_requested = true;
+
+ gst_element_set_state(g_conns[index].packet_sources[i].src_pipeline, GST_STATE_PAUSED);
+
+ g_print("_stop_pushing_packet()\n");
+}
+
static void __close_websocket(connection_s *conn)
{
if (!conn) {
}
} else if (len == 2) {
- if (strncmp(cmd, "gd", 2) == 0) {
+ if (strncmp(cmd, "sf", 2) == 0) {
+ g_conns[g_conn_index].menu_state = CURRENT_STATUS_MEDIA_PACKET_SOURCE_SET_FORMAT;
+
+ } else if (strncmp(cmd, "gd", 2) == 0) {
g_conns[g_conn_index].menu_state = CURRENT_STATUS_GET_TRANSCEIVER_DIRECTION;
} else if (strncmp(cmd, "td", 2) == 0) {
} else if (strncmp(cmd, "uk", 2) == 0) {
_webrtc_unset_track_added_cb(g_conn_index);
+ } else if (strncmp(cmd, "sm", 2) == 0) {
+ g_conns[g_conn_index].menu_state = CURRENT_STATUS_MEDIA_PACKET_SOURCE_SET_BUFFER_STATE_CHANGED_CB;
+
+ } else if (strncmp(cmd, "um", 2) == 0) {
+ g_conns[g_conn_index].menu_state = CURRENT_STATUS_MEDIA_PACKET_SOURCE_UNSET_BUFFER_STATE_CHANGED_CB;
+
} else if (strncmp(cmd, "co", 2) == 0) {
_webrtc_create_offer(g_conn_index);
} else if (strncmp(cmd, "sd", 2) == 0) {
g_conns[g_conn_index].menu_state = CURRENT_STATUS_SEND_LOCAL_DESCRIPTION;
+ } else if (strncmp(cmd, "sp", 2) == 0) {
+ g_conns[g_conn_index].menu_state = CURRENT_STATUS_START_PUSHING_PACKET_TO_MEDIA_PACKET_SOURCE;
+
+ } else if (strncmp(cmd, "tp", 2) == 0) {
+ g_conns[g_conn_index].menu_state = CURRENT_STATUS_STOP_PUSHING_PACKET_TO_MEDIA_PACKET_SOURCE;
+
} else if (strncmp(cmd, "ac", 2) == 0) {
_webrtc_add_ice_candidate(g_conn_index);
} else if (len == 3) {
if (strncmp(cmd, "sac", 3) == 0) {
+ int i;
+
_webrtc_set_error_cb(g_conn_index);
_webrtc_set_state_changed_cb(g_conn_index);
_webrtc_set_negotiation_needed_cb(g_conn_index);
_webrtc_set_track_added_cb(g_conn_index);
_webrtc_set_data_channel_cb(g_conn_index);
+ for (i = 0; i < MAX_MEDIA_PACKET_SOURCE_LEN; i++) {
+ if (g_conns[g_conn_index].packet_sources[i].source_id > 0)
+ _webrtc_media_packet_source_set_buffer_state_changed_cb(g_conn_index, g_conns[g_conn_index].packet_sources[i].source_id);
+ }
+
} else {
g_print("unknown menu \n");
}
g_print("g. Get state\n");
g_print("a. Add media source\t");
g_print("r. Remove media source\n");
+ g_print("sf. Set media format to media packet source\n");
g_print("gd. Get transceiver direction\t");
g_print("td. Set transceiver direction\n");
g_print("dt. Set display type\n");
g_print("uk. Unset track added callback\n");
g_print("sz. Set data channel callback\t");
g_print("uz. Unset data channel callback\n");
+ g_print("sm. Set media packet source buffer state changed callback\n");
+ g_print("um. Unset media packet source buffer state changed callback\n");
g_print("------------------------------------- Negotiation ---------------------------------------\n");
g_print("st. Set STUN server\t");
g_print("gt. Get STUN server\n");
g_print("cs. Connect to the signaling server\n");
g_print("rs. Request session of remote peer id\n");
g_print("sd. Send local description\n");
+ g_print("sp. Start pushing packet to media packet source\t");
+ g_print("tp. Stop pushing packet to media packet source\n");
g_print("-----------------------------------------------------------------------------------------\n");
g_print("=========================================================================================\n");
}
display_sub_basic();
} else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_ADD_MEDIA_SOURCE) {
- g_print("*** input media source type.(1:camera, 2:mic, 3:audiotest, 4:videotest)\n");
+ g_print("*** input media source type.(1:camera, 2:mic, 3:audiotest, 4:videotest, 5:media packet)\n");
} else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_REMOVE_MEDIA_SOURCE) {
g_print("*** input media source id to remove.\n");
+ } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_MEDIA_PACKET_SOURCE_SET_BUFFER_STATE_CHANGED_CB) {
+ g_print("*** input media packet source id to set buffer state changed callback.\n");
+
+ } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_MEDIA_PACKET_SOURCE_UNSET_BUFFER_STATE_CHANGED_CB) {
+ g_print("*** input media packet source id to unset buffer state changed callback.\n");
+
+ } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_MEDIA_PACKET_SOURCE_SET_FORMAT) {
+ if (g_conns[g_conn_index].cnt == 0)
+ g_print("*** input source id.\n");
+ else if (g_conns[g_conn_index].cnt == 1)
+ g_print("*** input media format.(1:I420 2:NV12 3:PCM_S16LE)\n");
+
} else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_GET_TRANSCEIVER_DIRECTION) {
if (g_conns[g_conn_index].cnt == 0)
g_print("*** input source id.\n");
} else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_SEND_LOCAL_DESCRIPTION) {
g_print("*** input type of local description to send to the server.(1:offer, 2:answer)\n");
+ } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_START_PUSHING_PACKET_TO_MEDIA_PACKET_SOURCE) {
+ g_print("*** input media packet source id to start pushing packet.\n");
+
+ } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_STOP_PUSHING_PACKET_TO_MEDIA_PACKET_SOURCE) {
+ g_print("*** input media packet source id to stop pushing packet.\n");
+
} else {
g_print("*** unknown status.\n");
quit_program();
reset_menu_state();
break;
}
+ case CURRENT_STATUS_MEDIA_PACKET_SOURCE_SET_BUFFER_STATE_CHANGED_CB: {
+ value = atoi(cmd);
+ _webrtc_media_packet_source_set_buffer_state_changed_cb(g_conn_index, value);
+ reset_menu_state();
+ break;
+ }
+ case CURRENT_STATUS_MEDIA_PACKET_SOURCE_UNSET_BUFFER_STATE_CHANGED_CB: {
+ value = atoi(cmd);
+ _webrtc_media_packet_source_unset_buffer_state_changed_cb(g_conn_index, value);
+ reset_menu_state();
+ break;
+ }
+ case CURRENT_STATUS_MEDIA_PACKET_SOURCE_SET_FORMAT: {
+ static unsigned int id;
+ value = atoi(cmd);
+
+ switch (g_conns[g_conn_index].cnt) {
+ case 0:
+ id = value;
+ g_conns[g_conn_index].cnt++;
+ break;
+ case 1:
+ _webrtc_media_packet_source_set_format(g_conn_index, id, value);
+ id = 0;
+ g_conns[g_conn_index].cnt = 0;
+ reset_menu_state();
+ break;
+ }
+ break;
+ }
case CURRENT_STATUS_GET_TRANSCEIVER_DIRECTION: {
static unsigned int id;
static unsigned int media_type;
reset_menu_state();
break;
}
+ case CURRENT_STATUS_START_PUSHING_PACKET_TO_MEDIA_PACKET_SOURCE: {
+ value = atoi(cmd);
+ _start_pushing_packet(g_conn_index, value);
+ reset_menu_state();
+ break;
+ }
+ case CURRENT_STATUS_STOP_PUSHING_PACKET_TO_MEDIA_PACKET_SOURCE: {
+ value = atoi(cmd);
+ _stop_pushing_packet(g_conn_index, value);
+ reset_menu_state();
+ break;
+ }
}
g_timeout_add(100, timeout_menu_display, 0);