Add API to set/get display visibleness 18/261718/12
authorSangchul Lee <sc11.lee@samsung.com>
Fri, 23 Jul 2021 07:01:43 +0000 (16:01 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Tue, 10 Aug 2021 07:38:28 +0000 (16:38 +0900)
Functions are added as below.
 - webrtc_set_display_visible()
 - webrtc_get_display_visible()

[Version] 0.2.70
[Issue Type] API

Change-Id: Ia50a7c3f12b14a329e52b94ba182ee90f86a9a25
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
include/webrtc.h
include/webrtc_private.h
packaging/capi-media-webrtc.spec
src/webrtc.c
src/webrtc_display.c
src/webrtc_sink.c
src/webrtc_source.c
test/webrtc_test.c

index ec6b3f819232f2aa1595aee889292a04e1fb4220..6745be8fd2d3468e2d30e35af27cb86de5071802 100644 (file)
@@ -1097,6 +1097,8 @@ int webrtc_set_sound_stream_info(webrtc_h webrtc, unsigned int track_id, sound_s
  * @see webrtc_unset_track_added_cb()
  * @see webrtc_set_display_mode()
  * @see webrtc_get_display_mode()
+ * @see webrtc_set_display_visible()
+ * @see webrtc_get_display_visible()
  */
 int webrtc_set_display(webrtc_h webrtc, unsigned int track_id, webrtc_display_type_e type, webrtc_display_h display);
 
@@ -1135,6 +1137,41 @@ int webrtc_set_display_mode(webrtc_h webrtc, unsigned int track_id, webrtc_displ
  */
 int webrtc_get_display_mode(webrtc_h webrtc, unsigned int track_id, webrtc_display_mode_e *mode);
 
+/**
+ * @brief Sets the display visibleness of the video track.
+ * @since_tizen 6.5
+ * @param[in] webrtc      WebRTC handle
+ * @param[in] track_id    The track id
+ * @param[in] visible     The display visibleness
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #WEBRTC_ERROR_NONE    Successful
+ * @retval #WEBRTC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #WEBRTC_ERROR_INVALID_OPERATION Invalid operation
+ * @pre For remote video track, webrtc_set_display() must be called with @a track_id from webrtc_track_added_cb().\n
+ *      For loopback video track, webrtc_media_source_set_video_loopback() must be called to get @a track_id.
+ * @see webrtc_get_display_visible()
+ */
+int webrtc_set_display_visible(webrtc_h webrtc, unsigned int track_id, bool visible);
+
+/**
+ * @brief Gets the display visibleness of the video track.
+ * @since_tizen 6.5
+ * @remarks The default value is @c true.
+ * @param[in] webrtc      WebRTC handle
+ * @param[in] track_id    The track id
+ * @param[out] visible    The display visibleness
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #WEBRTC_ERROR_NONE    Successful
+ * @retval #WEBRTC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #WEBRTC_ERROR_INVALID_OPERATION Invalid operation
+ * @pre For remote video track, webrtc_set_display() must be called with @a track_id from webrtc_track_added_cb().\n
+ *      For loopback video track, webrtc_media_source_set_video_loopback() must be called to get @a track_id.
+ * @see webrtc_set_display_visible()
+ */
+int webrtc_get_display_visible(webrtc_h webrtc, unsigned int track_id, bool *visible);
+
 /**
  * @brief Sets an encoded audio frame callback function to be invoked when each audio frame is ready to be rendered.
  * @since_tizen 6.5
@@ -1253,6 +1290,8 @@ int webrtc_media_source_set_audio_loopback(webrtc_h webrtc, unsigned int source_
  * @see webrtc_media_source_set_audio_loopback()
  * @see webrtc_set_display_mode()
  * @see webrtc_get_display_mode()
+ * @see webrtc_set_display_visible()
+ * @see webrtc_get_display_visible()
  */
 int webrtc_media_source_set_video_loopback(webrtc_h webrtc, unsigned int source_id, webrtc_display_type_e type, webrtc_display_h display, unsigned int *track_id);
 
@@ -1800,7 +1839,7 @@ int webrtc_unset_data_channel_cb(webrtc_h webrtc);
  * @remarks The @a channel should be released using webrtc_destroy().\n
  *          The @a options dictionary is similar format as the RTCDataChannelInit members outlined https://www.w3.org/TR/webrtc/#dom-rtcdatachannelinit.\n
  *          The following attributes can be set to @a options by using #bundle API:\n
- *          'ordered' of type bool            : Whether the channel will send data with guaranteed ordering. The default value is true.\n
+ *          'ordered' of type bool            : Whether the channel will send data with guaranteed ordering. The default value is @c true.\n
  *          'max-packet-lifetime' of type int : The time in milliseconds to attempt transmitting unacknowledged data. -1 for unset. The default value is -1.\n
  *          'max-retransmits' of type int     : The number of times data will be attempted to be transmitted without acknowledgement before dropping. The default value is -1.\n
  *          'protocol' of type string         : The subprotocol used by this channel. The default value is NULL.\n
index 87d5705f1aeb245bcf839f5d573761d596fe9b15..ba3be081ed856d570909c8057df93c7f773c987e 100644 (file)
@@ -369,6 +369,7 @@ typedef struct _webrtc_display {
        GMutex mutex;
        mm_display_interface_h mm_display;
        webrtc_display_mode_e mode;
+       bool visible;
        webrtc_tbm_s *tbm;
        GstElement *sink_element;
 } webrtc_display_s;
@@ -588,6 +589,10 @@ int _set_display_mode_to_sink(webrtc_s *webrtc, unsigned int track_id, webrtc_di
 int _get_display_mode_from_sink(webrtc_s *webrtc, unsigned int track_id, webrtc_display_mode_e *mode);
 int _set_display_mode_to_loopback(webrtc_s *webrtc, unsigned int track_id, webrtc_display_mode_e mode);
 int _get_display_mode_from_loopback(webrtc_s *webrtc, unsigned int track_id, webrtc_display_mode_e *mode);
+int _set_display_visible_to_sink(webrtc_s *webrtc, unsigned int track_id, bool visible);
+int _get_display_visible_from_sink(webrtc_s *webrtc, unsigned int track_id, bool *visible);
+int _set_display_visible_to_loopback(webrtc_s *webrtc, unsigned int track_id, bool visible);
+int _get_display_visible_from_loopback(webrtc_s *webrtc, unsigned int track_id, bool *visible);
 int _set_audio_loopback(webrtc_s *webrtc, unsigned int source_id, sound_stream_info_h stream_info, unsigned int *track_id);
 int _set_video_loopback(webrtc_s *webrtc, unsigned int source_id, unsigned int type, void *display, unsigned int *track_id);
 int _decodebin_autoplug_select_cb(GstElement *decodebin, GstPad *pad, GstCaps *caps, GstElementFactory *factory, gpointer user_data);
@@ -605,6 +610,8 @@ int _apply_display(webrtc_display_s *display);
 void _set_display_type_and_surface(webrtc_display_s *display, webrtc_display_type_e type, void *surface);
 int _set_display_mode(webrtc_display_s *display, webrtc_display_mode_e mode);
 int _get_display_mode(webrtc_display_s *display, webrtc_display_mode_e *mode);
+int _set_display_visible(webrtc_display_s *display, bool visible);
+int _get_display_visible(webrtc_display_s *display, bool *visible);
 void _video_stream_decoded_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
 
 #ifndef TIZEN_TV
index 66d1d8d0760b9b5aa61997a0729761380e72b50e..90c5d41e6ac4ad9ca2ebfdb71b982545cb65c66d 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-webrtc
 Summary:    A WebRTC library in Tizen Native API
-Version:    0.2.69
+Version:    0.2.70
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index 5da5a7847839190d5fe319de1094dff9c32f9540..d85bbc4b49589907f4f9b5661b3441589cab7811 100644 (file)
@@ -706,6 +706,47 @@ int webrtc_get_display_mode(webrtc_h webrtc, unsigned int track_id, webrtc_displ
        return ret;
 }
 
+int webrtc_set_display_visible(webrtc_h webrtc, unsigned int track_id, bool visible)
+{
+       int ret = WEBRTC_ERROR_NONE;
+       webrtc_s *_webrtc = (webrtc_s*)webrtc;
+
+       RET_VAL_IF(_webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+       RET_VAL_IF(track_id == 0, WEBRTC_ERROR_INVALID_PARAMETER, "track id is 0");
+
+       g_mutex_lock(&_webrtc->mutex);
+
+       if (track_id < TRACK_ID_THRESHOLD_OF_LOOPBACK)
+               ret = _set_display_visible_to_sink(webrtc, track_id, visible);
+       else
+               ret = _set_display_visible_to_loopback(webrtc, track_id, visible);
+
+       g_mutex_unlock(&_webrtc->mutex);
+
+       return ret;
+}
+
+int webrtc_get_display_visible(webrtc_h webrtc, unsigned int track_id, bool *visible)
+{
+       int ret = WEBRTC_ERROR_NONE;
+       webrtc_s *_webrtc = (webrtc_s*)webrtc;
+
+       RET_VAL_IF(_webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+       RET_VAL_IF(track_id == 0, WEBRTC_ERROR_INVALID_PARAMETER, "track id is 0");
+       RET_VAL_IF(visible == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "visible is NULL");
+
+       g_mutex_lock(&_webrtc->mutex);
+
+       if (track_id < TRACK_ID_THRESHOLD_OF_LOOPBACK)
+               ret = _get_display_visible_from_sink(webrtc, track_id, visible);
+       else
+               ret = _get_display_visible_from_loopback(webrtc, track_id, visible);
+
+       g_mutex_unlock(&_webrtc->mutex);
+
+       return ret;
+}
+
 int webrtc_set_encoded_audio_frame_cb(webrtc_h webrtc, webrtc_encoded_frame_cb callback, void *user_data)
 {
        webrtc_s *_webrtc = (webrtc_s*)webrtc;
index e4d3b1a5f37a4090e7d27277e22e13fedfba04ec..1de585d1ce34743cc812f961171b4ddc55c03d7a 100644 (file)
@@ -649,7 +649,7 @@ static int __set_overlay_display(webrtc_display_s *display)
        ret = mm_display_interface_set_display_mainloop_sync(display->mm_display, type, display->surface, &display->overlay_surface_id);
        RET_VAL_IF(ret != MM_ERROR_NONE, WEBRTC_ERROR_INVALID_OPERATION, "failed to mm_display_interface_set_display_mainloop_sync()");
 
-       LOG_INFO("overlay_surface_id[%d]", display->overlay_surface_id);
+       LOG_INFO("surface[%p], overlay_surface_id[%d]", display->surface, display->overlay_surface_id);
 
        return WEBRTC_ERROR_NONE;
 }
@@ -674,6 +674,11 @@ static int __set_evas_display(webrtc_display_s *display)
        ret = mm_display_interface_evas_set_visible(display->mm_display, true);
        RET_VAL_IF(ret != MM_ERROR_NONE, WEBRTC_ERROR_INVALID_OPERATION, "failed to mm_display_interface_evas_set_visible()");
 
+       display->mode = WEBRTC_DISPLAY_MODE_LETTER_BOX;
+       display->visible = true;
+
+       LOG_INFO("surface[%p], mode[%u], visible[%u]", display->surface, display->mode, display->visible);
+
        return WEBRTC_ERROR_NONE;
 }
 
@@ -830,5 +835,64 @@ int _get_display_mode(webrtc_display_s *display, webrtc_display_mode_e *mode)
 
        g_mutex_unlock(&display->mutex);
 
+       return WEBRTC_ERROR_NONE;
+}
+
+int _set_display_visible(webrtc_display_s *display, bool visible)
+{
+       RET_VAL_IF(display == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "display is NULL");
+
+       g_mutex_lock(&display->mutex);
+
+       RET_VAL_WITH_UNLOCK_IF(display->mm_display == NULL, WEBRTC_ERROR_INVALID_OPERATION, &display->mutex, "mm_display is NULL");
+       RET_VAL_WITH_UNLOCK_IF(display->surface == NULL, WEBRTC_ERROR_INVALID_OPERATION, &display->mutex, "surface is NULL");
+
+       switch (display->type) {
+       case WEBRTC_DISPLAY_TYPE_OVERLAY:
+       case WEBRTC_DISPLAY_TYPE_ECORE_WL:
+               LOG_INFO("it's %s type, visible[%u]", display->type == WEBRTC_DISPLAY_TYPE_OVERLAY ? "OVERLAY" : "ECORE_WL", visible);
+               RET_VAL_WITH_UNLOCK_IF(display->sink_element == NULL, WEBRTC_ERROR_INVALID_OPERATION, &display->mutex, "sink_element is NULL");
+               RET_VAL_WITH_UNLOCK_IF(!g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(display->sink_element)), "visible"),
+                       WEBRTC_ERROR_INVALID_OPERATION, &display->mutex, "could not find 'visible'");
+
+               g_object_set(G_OBJECT(display->sink_element), "visible", (gboolean)visible, NULL);
+               display->visible = visible;
+               break;
+
+       case WEBRTC_DISPLAY_TYPE_EVAS:
+               LOG_INFO("it's EVAS type, visible[%u]", visible);
+               RET_VAL_WITH_UNLOCK_IF(mm_display_interface_evas_set_visible(display->mm_display, visible) != 0,
+                       WEBRTC_ERROR_INVALID_OPERATION, &display->mutex, "failed to mm_display_interface_evas_set_visible()");
+
+               display->visible = visible;
+               break;
+
+       default:
+               LOG_ERROR_IF_REACHED("type(%d)", display->type);
+               g_mutex_unlock(&display->mutex);
+               return WEBRTC_ERROR_INVALID_OPERATION;
+       }
+
+       g_mutex_unlock(&display->mutex);
+
+       return WEBRTC_ERROR_NONE;
+}
+
+int _get_display_visible(webrtc_display_s *display, bool *visible)
+{
+       RET_VAL_IF(display == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "display is NULL");
+       RET_VAL_IF(visible == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "visible is NULL");
+
+       g_mutex_lock(&display->mutex);
+
+       RET_VAL_WITH_UNLOCK_IF(display->mm_display == NULL, WEBRTC_ERROR_INVALID_OPERATION, &display->mutex, "mm_display is NULL");
+       RET_VAL_WITH_UNLOCK_IF(display->surface == NULL, WEBRTC_ERROR_INVALID_OPERATION, &display->mutex, "surface is NULL");
+
+       *visible = display->visible;
+
+       LOG_INFO("visible[%d]", *visible);
+
+       g_mutex_unlock(&display->mutex);
+
        return WEBRTC_ERROR_NONE;
 }
\ No newline at end of file
index 3c17a8c4b404c131eb093e43f502f9dcfee1504a..9c145846ce375c0ffa4a408d74be2ad6c41ab71f 100644 (file)
@@ -163,8 +163,12 @@ static int __build_videosink(webrtc_s *webrtc, GstElement *decodebin, GstPad *sr
                if (sink->display->type == WEBRTC_DISPLAY_TYPE_OVERLAY ||
                        sink->display->type == WEBRTC_DISPLAY_TYPE_ECORE_WL) {
                        gst_video_overlay_set_wl_window_wl_surface_id(GST_VIDEO_OVERLAY(videosink), sink->display->overlay_surface_id);
-                       g_object_set(G_OBJECT(videosink), "display-geometry-method", (gint)0, NULL); /* 0: letter box, 1: origin size, 2: full screen */
+                       g_object_set(G_OBJECT(videosink),
+                               "display-geometry-method", (gint)0, /* 0: letter box, 1: origin size, 2: full screen */
+                               "visible", TRUE,
+                               NULL);
                        sink->display->mode = WEBRTC_DISPLAY_MODE_LETTER_BOX;
+                       sink->display->visible = true;
 
                } else if (sink->display->type == WEBRTC_DISPLAY_TYPE_EVAS) {
                        g_object_set(G_OBJECT(videosink),
@@ -994,3 +998,38 @@ int _get_display_mode_from_sink(webrtc_s *webrtc, unsigned int track_id, webrtc_
 
        return WEBRTC_ERROR_NONE;
 }
+
+int _set_display_visible_to_sink(webrtc_s *webrtc, unsigned int track_id, bool visible)
+{
+       webrtc_gst_slot_s *sink;
+
+       RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+       RET_VAL_IF(track_id == 0, WEBRTC_ERROR_INVALID_PARAMETER, "track id is 0");
+
+       sink = __find_sink_slot_by_id(webrtc, track_id);
+       RET_VAL_IF(sink == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "sink is NULL");
+
+       RET_VAL_IF(sink->bin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "bin is NULL");
+       RET_VAL_IF((sink->media_types & MEDIA_TYPE_VIDEO) == 0x0, WEBRTC_ERROR_INVALID_OPERATION, "it's not a video track");
+       RET_VAL_IF(_set_display_visible(sink->display, visible) != WEBRTC_ERROR_NONE, WEBRTC_ERROR_INVALID_OPERATION, "failed to _set_display_visible()");
+
+       return WEBRTC_ERROR_NONE;
+}
+
+int _get_display_visible_from_sink(webrtc_s *webrtc, unsigned int track_id, bool *visible)
+{
+       webrtc_gst_slot_s *sink;
+
+       RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+       RET_VAL_IF(track_id == 0, WEBRTC_ERROR_INVALID_PARAMETER, "track id is 0");
+       RET_VAL_IF(visible == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "visible is NULL");
+
+       sink = __find_sink_slot_by_id(webrtc, track_id);
+       RET_VAL_IF(sink == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "sink is NULL");
+
+       RET_VAL_IF(sink->bin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "bin is NULL");
+       RET_VAL_IF((sink->media_types & MEDIA_TYPE_VIDEO) == 0x0, WEBRTC_ERROR_INVALID_OPERATION, "it's not a video track");
+       RET_VAL_IF(_get_display_visible(sink->display, visible) != WEBRTC_ERROR_NONE, WEBRTC_ERROR_INVALID_OPERATION, "failed to _get_display_visible()");
+
+       return WEBRTC_ERROR_NONE;
+}
index e82a7b06d111db9518376eae837f989c6a3bed8f..7fdd88a1943ea3777fe538a22d85b14d08ee8fc7 100644 (file)
@@ -3430,6 +3430,12 @@ static int __build_loopback_videosink(webrtc_gst_slot_s *source, GstElement *lin
        if (source->display->type == WEBRTC_DISPLAY_TYPE_OVERLAY ||
                source->display->type == WEBRTC_DISPLAY_TYPE_ECORE_WL) {
                gst_video_overlay_set_wl_window_wl_surface_id(GST_VIDEO_OVERLAY(videosink), source->display->overlay_surface_id);
+               g_object_set(G_OBJECT(videosink),
+                       "display-geometry-method", (gint)0, /* 0: letter box, 1: origin size, 2: full screen */
+                       "visible", TRUE,
+                       NULL);
+               source->display->mode = WEBRTC_DISPLAY_MODE_LETTER_BOX;
+               source->display->visible = true;
 
        } else if (source->display->type == WEBRTC_DISPLAY_TYPE_EVAS) {
                g_object_set(videosink, "signal-handoffs", TRUE, NULL);
@@ -3690,5 +3696,42 @@ int _get_display_mode_from_loopback(webrtc_s *webrtc, unsigned int track_id, web
        RET_VAL_IF((source->media_types & MEDIA_TYPE_VIDEO) == 0x0, WEBRTC_ERROR_INVALID_OPERATION, "it's not a video track");
        RET_VAL_IF(_get_display_mode(source->display, mode) != WEBRTC_ERROR_NONE, WEBRTC_ERROR_INVALID_OPERATION, "failed to _get_display_mode()");
 
+       return WEBRTC_ERROR_NONE;
+}
+
+int _set_display_visible_to_loopback(webrtc_s *webrtc, unsigned int track_id, bool visible)
+{
+       webrtc_gst_slot_s *source;
+
+       RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+       RET_VAL_IF(track_id < TRACK_ID_THRESHOLD_OF_LOOPBACK, WEBRTC_ERROR_INVALID_PARAMETER, "invalid track_id(%d)", track_id);
+
+       source = _get_slot_by_id(webrtc->gst.source_slots, track_id / 100);
+       RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
+       RET_VAL_IF(source->av[AV_IDX_VIDEO].render.track_id != track_id, WEBRTC_ERROR_INVALID_PARAMETER, "invalid track_id(%d)", track_id);
+
+       RET_VAL_IF(source->bin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "bin is NULL");
+       RET_VAL_IF((source->media_types & MEDIA_TYPE_VIDEO) == 0x0, WEBRTC_ERROR_INVALID_OPERATION, "it's not a video track");
+       RET_VAL_IF(_set_display_visible(source->display, visible) != WEBRTC_ERROR_NONE, WEBRTC_ERROR_INVALID_OPERATION, "failed to _set_display_visible()");
+
+       return WEBRTC_ERROR_NONE;
+}
+
+int _get_display_visible_from_loopback(webrtc_s *webrtc, unsigned int track_id, bool *visible)
+{
+       webrtc_gst_slot_s *source;
+
+       RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+       RET_VAL_IF(track_id < TRACK_ID_THRESHOLD_OF_LOOPBACK, WEBRTC_ERROR_INVALID_PARAMETER, "invalid track_id(%d)", track_id);
+       RET_VAL_IF(visible == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "visible is NULL");
+
+       source = _get_slot_by_id(webrtc->gst.source_slots, track_id / 100);
+       RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
+       RET_VAL_IF(source->av[AV_IDX_VIDEO].render.track_id != track_id, WEBRTC_ERROR_INVALID_PARAMETER, "invalid track_id(%d)", track_id);
+
+       RET_VAL_IF(source->bin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "bin is NULL");
+       RET_VAL_IF((source->media_types & MEDIA_TYPE_VIDEO) == 0x0, WEBRTC_ERROR_INVALID_OPERATION, "it's not a video track");
+       RET_VAL_IF(_get_display_visible(source->display, visible) != WEBRTC_ERROR_NONE, WEBRTC_ERROR_INVALID_OPERATION, "failed to _get_display_visible()");
+
        return WEBRTC_ERROR_NONE;
 }
\ No newline at end of file
index 7525f9e803d10f370915be868972dff6cf984dbf..2c767d34c163f44546eff799781f164134c930db 100644 (file)
@@ -74,6 +74,8 @@ enum {
        CURRENT_STATUS_SET_DISPLAY_TYPE,
        CURRENT_STATUS_SET_DISPLAY_MODE,
        CURRENT_STATUS_GET_DISPLAY_MODE,
+       CURRENT_STATUS_SET_DISPLAY_VISIBLE,
+       CURRENT_STATUS_GET_DISPLAY_VISIBLE,
        CURRENT_STATUS_MEDIA_SOURCE_SET_AUDIO_LOOPBACK,
        CURRENT_STATUS_MEDIA_SOURCE_SET_VIDEO_LOOPBACK,
        CURRENT_STATUS_DATA_CHANNEL_SEND_STRING,
@@ -877,6 +879,27 @@ static void _webrtc_get_display_mode(int index, unsigned int track_id)
        g_print("webrtc_get_display_mode() success, track_id[%u], mode[%u]\n", track_id, mode);
 }
 
+static void _webrtc_set_display_visible(int index, unsigned int track_id, int visible)
+{
+       int ret = WEBRTC_ERROR_NONE;
+
+       ret = webrtc_set_display_visible(g_conns[index].webrtc, track_id, (bool)visible);
+       RET_IF(ret != WEBRTC_ERROR_NONE, "ret[0x%x]", ret);
+
+       g_print("webrtc_set_display_visible() success, track_id[%u], visible[%u]\n", track_id, visible);
+}
+
+static void _webrtc_get_display_visible(int index, unsigned int track_id)
+{
+       int ret = WEBRTC_ERROR_NONE;
+       bool visible;
+
+       ret = webrtc_get_display_visible(g_conns[index].webrtc, track_id, &visible);
+       RET_IF(ret != WEBRTC_ERROR_NONE, "ret[0x%x]", ret);
+
+       g_print("webrtc_get_display_visible() success, track_id[%u], visible[%u]\n", track_id, visible);
+}
+
 static void _webrtc_media_source_set_audio_loopback(int index, unsigned int source_id)
 {
        int ret = WEBRTC_ERROR_NONE;
@@ -3469,6 +3492,12 @@ void _interpret_main_menu(char *cmd)
                } else if (strncmp(cmd, "gm", 2) == 0) {
                        g_conns[g_conn_index].menu_state = CURRENT_STATUS_GET_DISPLAY_MODE;
 
+               } else if (strncmp(cmd, "dv", 2) == 0) {
+                       g_conns[g_conn_index].menu_state = CURRENT_STATUS_SET_DISPLAY_VISIBLE;
+
+               } else if (strncmp(cmd, "gv", 2) == 0) {
+                       g_conns[g_conn_index].menu_state = CURRENT_STATUS_GET_DISPLAY_VISIBLE;
+
                } else if (strncmp(cmd, "al", 2) == 0) {
                        g_conns[g_conn_index].menu_state = CURRENT_STATUS_MEDIA_SOURCE_SET_AUDIO_LOOPBACK;
 
@@ -3742,7 +3771,9 @@ void display_sub_basic()
        g_print("sf. Set media format to media packet source\n");
        g_print("dt. Set display type\t");
        g_print("dm. Set display mode\t");
-       g_print("gm. Get display mode\n");
+       g_print("gm. Get display mode\t");
+       g_print("dv. Set display visible\t");
+       g_print("gv. Get display visible\n");
        g_print("al. Set audio loopback\t");
        g_print("vl. Set video loopback\n");
        g_print("cd. Create data channel\t");
@@ -3883,6 +3914,15 @@ static void displaymenu()
        } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_GET_DISPLAY_MODE) {
                g_print("*** input track id.\n");
 
+       } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_SET_DISPLAY_VISIBLE) {
+               if (g_conns[g_conn_index].cnt == 0)
+                       g_print("*** input track id.\n");
+               else if (g_conns[g_conn_index].cnt == 1)
+                       g_print("*** input display visible.(1:true 0:false)\n");
+
+       } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_GET_DISPLAY_VISIBLE) {
+               g_print("*** input track id.\n");
+
        } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_MEDIA_SOURCE_SET_AUDIO_LOOPBACK) {
                g_print("*** input source id.\n");
 
@@ -4184,6 +4224,30 @@ static void interpret(char *cmd)
                reset_menu_state();
                break;
        }
+       case CURRENT_STATUS_SET_DISPLAY_VISIBLE: {
+               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_set_display_visible(g_conn_index, id, value);
+                       id = 0;
+                       g_conns[g_conn_index].cnt = 0;
+                       reset_menu_state();
+                       break;
+               }
+               break;
+       }
+       case CURRENT_STATUS_GET_DISPLAY_VISIBLE: {
+               value = atoi(cmd);
+               _webrtc_get_display_visible(g_conn_index, value);
+               reset_menu_state();
+               break;
+       }
        case CURRENT_STATUS_MEDIA_SOURCE_SET_AUDIO_LOOPBACK: {
                value = atoi(cmd);
                _webrtc_media_source_set_audio_loopback(g_conn_index, value);