Screen Mirroring: Mirroring Screen and Sound
This tutorial demonstrates how you can mirror the device screen and sound to another device wirelessly as a sink.
This feature is supported in mobile applications only.
Warm-up
Become familiar with Screen Mirroring API basics by learning about:
-
Initializing the Screen Mirroring Sink
Initialize the screen mirroring sink for use.
-
Preparing the Screen Mirroring Sink
Set a callback and display object, and prepare the screen mirroring sink.
-
Connecting and Starting the Screen Mirroring Sink
Connect and start the screen mirroring sink.
-
Releasing Resources
Disconnect and unprepare the screen mirroring sink, and release all resources allocated to the sink.
-
Handling Screen Mirroring Sink Exceptions
Handle exceptions in the screen mirroring sink processes.
Initializing the Screen Mirroring Sink
To initialize the screen mirroring sink for use:
-
To use the functions and data types of the Screen Mirroring API, include the <scmirroring_type.h> and <scmirroring_sink.h> header files in your application:
#include <scmirroring_type.h> #include <scmirroring_sink.h>
-
Create a handle for the screen mirroring sink using the scmirroring_sink_create() function.
The function sets the screen mirroring state to SCMIRRORING_STATE_NULL.
static scmirroring_sink_h g_scmirroring; static int init_scmirroring_sink() { int ret = SCMIRRORING_ERROR_NONE; ret = scmirroring_sink_create(&g_scmirroring); if (ret != SCMIRRORING_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "scmirroring_sink_create fail [%d]", ret); return FALSE; } return TRUE; }
Preparing the Screen Mirroring Sink
To prepare the screen mirroring sink:
-
Register and define a callback for checking the screen mirroring sink state using the scmirroring_sink_set_state_changed_cb() function:
static void scmirroring_state_callback(scmirroring_error_e error_code, scmirroring_state_e state, void *user_data) { dlog_print(DLOG_ERROR, LOG_TAG, "Received Callback error code[%d], state[%d]", error_code, state); switch (state) { case SCMIRRORING_STATE_NULL: break; case SCMIRRORING_STATE_PREPARED: break; case SCMIRRORING_STATE_CONNECTED: break; case SCMIRRORING_STATE_PLAYING: break; case SCMIRRORING_STATE_PAUSED: break; case SCMIRRORING_STATE_DISCONNECTED: break; case SCMIRRORING_STATE_NONE: break; default: dlog_print(DLOG_ERROR, LOG_TAG, "state[%d] Invalid State", state); break; } return; } static int prepare_scmirroring_sink(scmirroring_display_type_e display_type) { ret = scmirroring_sink_set_state_changed_cb(g_scmirroring, scmirroring_state_callback, NULL); if (ret != SCMIRRORING_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "scmirroring_sink_set_state_changed_cb fail [%d]", ret); return FALSE; }
-
Set a display object using the scmirroring_sink_set_display() function:
switch (display_type) { case SCMIRRORING_DISPLAY_TYPE_EVAS: if (g_eo == NULL) { dlog_print(DLOG_ERROR, LOG_TAG, "g_eo is NULL"); return FALSE; } ret = scmirroring_sink_set_display(g_scmirroring, SCMIRRORING_DISPLAY_TYPE_EVAS, (void*)g_eo); if (ret != SCMIRRORING_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "scmirroring_sink_set_display fail [%d], display type [%d]", ret, display_type); return FALSE; } break; case SCMIRRORING_DISPLAY_TYPE_OVERLAY: if (g_win == NULL) { dlog_print(DLOG_ERROR, LOG_TAG, "g_win is NULL"); return FALSE; } ret = scmirroring_sink_set_display(g_scmirroring, SCMIRRORING_DISPLAY_TYPE_OVERLAY, (void*)g_win); if (ret != SCMIRRORING_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "scmirroring_sink_set_display fail [%d], display type [%d]", ret, display_type); return FALSE; } break; default: dlog_print(DLOG_ERROR, LOG_TAG, "Invalid display type [%d].", display_type); return FALSE; } }
-
Create the display object based on the applicable scmirroring_display_type_e enumerator value:
#define PACKAGE_NAME "SCREEN_MIRRORING_SINK_APP" #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 1200 static Evas_Object *g_win = NULL; static Evas_Object *g_evas = NULL; static Evas_Object *g_eo = NULL; static Evas_Object *g_rect = NULL; static void create_base_gui(scmirroring_display_type_e display_type) { g_win = elm_win_add(NULL, PACKAGE_NAME, ELM_WIN_BASIC); evas_object_resize(g_win, WINDOW_WIDTH, WINDOW_HEIGHT); evas_object_move(g_win, 0, 0); elm_win_autodel_set(g_win, EINA_TRUE); switch (display_type) { case SCMIRRORING_DISPLAY_TYPE_EVAS: g_evas = evas_object_evas_get(g_win); // Set an Evas image object for drawing g_eo = evas_object_image_add(g_evas); evas_object_image_size_set(g_eo, WINDOW_WIDTH, WINDOW_HEIGHT); evas_object_image_fill_set(g_eo, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); evas_object_resize(g_eo, WINDOW_WIDTH, WINDOW_HEIGHT); // Show the window after the base GUI is set up evas_object_show(g_eo); evas_object_show(g_win); break; case SCMIRRORING_DISPLAY_TYPE_OVERLAY: g_rect = evas_object_rectangle_add(g_evas); evas_object_resize(g_rect, WINDOW_WIDTH, WINDOW_HEIGHT); evas_object_move(g_rect, 0, 0); evas_object_color_set(g_rect, 0, 0, 0, 0); evas_object_render_op_set(g_rect, EVAS_RENDER_COPY); evas_object_size_hint_weight_set(g_rect, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); // Show the window after the base GUI is set up evas_object_show(g_win); break; default: break; } }
-
Prepare the screen mirroring sink using the scmirroring_sink_prepare() function.
The function sets the screen mirroring state to SCMIRRORING_STATE_PREPARED.
ret = scmirroring_sink_prepare(g_scmirroring); if (ret != SCMIRRORING_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "scmirroring_sink_prepare fail [%d]", ret); return FALSE; } return TRUE;
Connecting and Starting the Screen Mirroring Sink
To connect and start the screen mirroring sink:
-
Set the IP address and port number using the scmirroring_sink_set_ip_and_port() function:
static int start_scmirroring_sink(const char* peer_ip, const char* peer_port) { int ret; ret = scmirroring_sink_set_ip_and_port(g_scmirroring, peer_ip, peer_port); if (ret != SCMIRRORING_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "scmirroring_sink_set_ip_and_port fail [%d]", ret); return FALSE; }
-
Connect the screen mirroring sink to the screen mirroring source using the scmirroring_sink_connect() function.
The function sets the screen mirroring state to SCMIRRORING_STATE_CONNECTED asynchronously. Monitor the state changes using the state callback.
ret = scmirroring_sink_connect(g_scmirroring); if (ret != SCMIRRORING_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "scmirroring_sink_connect fail [%d]", ret); return FALSE; } return TRUE; }
-
When the screen mirroring state is SCMIRRORING_STATE_CONNECTED, start the screen mirroring sink using the scmirroring_sink_start() function.
The function sets the screen mirroring state to SCMIRRORING_STATE_PLAYING asynchronously.
static void scmirroring_state_callback(scmirroring_error_e error_code, scmirroring_state_e state, void *user_data) { int ret; dlog_print(DLOG_ERROR, LOG_TAG, "Received Callback error code[%d], state[%d]", error_code, state); switch (state) { // Other cases case SCMIRRORING_STATE_CONNECTED: ret = scmirroring_sink_start(g_scmirroring); if (ret != SCMIRRORING_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "scmirroring_sink_start fail [%d]", ret); return; } break; // Other cases } return; }
Releasing Resources
After you have finished working with the screen mirroring sink, disconnect it and release all its resources:
-
Disconnect the screen mirroring sink using scmirroring_sink_disconnect() function.
The function sets the screen mirroring state to SCMIRRORING_STATE_DISCONNECTED.
static int destroy_scmirroring_sink() { ret = scmirroring_sink_disconnect(g_scmirroring); if (ret != SCMIRRORING_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "scmirroring_sink_disconnect fail [%d]", ret); return FALSE; }
-
Unprepare the screen mirroring sink using the scmirroring_sink_unprepare() function.
The function sets the screen mirroring state to SCMIRRORING_STATE_NULL.
ret = scmirroring_sink_unprepare(g_scmirroring); if (ret != SCMIRRORING_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "scmirroring_sink_unprepare fail [%d]", ret); return FALSE; }
-
Release the screen mirroring sink resources using the scmirroring_sink_destroy() function.
The function sets the screen mirroring state to SCMIRRORING_STATE_NONE.
ret = scmirroring_sink_destroy(g_scmirroring); if (ret != SCMIRRORING_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "scmirroring_sink_destroy fail [%d]", ret); return FALSE; } return TRUE; }
Handling Screen Mirroring Sink Exceptions
If the state callback returns an error or the SCMIRRORING_STATE_DISCONNECTED state, release the screen mirroring sink and its allocated resources. This exception is caused by an internal error in the screen mirroring sink, or by the source device disconnecting the session.
static void scmirroring_state_callback(scmirroring_error_e error_code, scmirroring_state_e state, void *user_data) { int ret; dlog_print(DLOG_ERROR, LOG_TAG, "Received Callback error code[%d], state[%d]", error_code, state); if (error_code != SCMIRRORING_ERROR_NONE) { ret = destroy_scmirroring_sink(); if (ret != TRUE) { dlog_print(DLOG_ERROR, LOG_TAG, "destroy_scmirroring_sink fail"); return; } } switch (state) { // Other cases case SCMIRRORING_STATE_DISCONNECTED: ret = scmirroring_sink_unprepare(g_scmirroring); if (ret != SCMIRRORING_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "scmirroring_sink_unprepare fail [%d]", ret); return; } // Do something break; // Other cases } return; }