Page Example

Mediastreamer Sample Overview

Mobile native

The Media Streamer sample application demonstrates how to add fully functional media streaming features to an application. This sample introduces multimedia streaming scenarios and how to include them in applications. This sample contains local playback, broadcast server, broadcast client, and VoIP (Voice over IP) scenarios.

The following figure illustrates the main view of the Media Streamer.

Figure: Media Streamer main view

Media Streamer main view

Click an item on the list to use the related functionality. For backward navigation, use the back button.

Source Files

You can create and view the sample application project, including the source files, in the IDE.

Table: Source files
File name Description
inc/media_streamer.h This file contains the type definitions used in the application.
inc/media_streamer_view.h This file contains the functions and type definitions used in the application.
res/content This directory stores the multimedia content used in the application.
res/images This directory contains the images used in the application.
src/media_streamer.c This file contains the functions related to the application life cycle and the event callbacks.
src/media_streamer_broadcast_client.c This file contains the functions related to the broadcast client scenario.
src/media_streamer_broadcast_server.c This file contains the functions related to the broadcast server scenario.
src/media_streamer_player.c This file contains the functions related to the local playback scenario.
src/media_streamer_view.c This file contains the functions related to the application UI.
src/media_streamer_voip.c This file contains the functions related to the broadcast VoIP scenario.

Implementation

Application Main View

To create the application main view:

  1. The create_base_gui() function is called right after the application starts. It creates the main view, consisting of the window, conformant, and naviframe. For each sample scenario, a separate list item is created and added to list by calling the append_XXX_menu() functions.
    /* @brief Functions for creating the list with links to the available scenarios */
    void
    create_base_gui(appdata_s *ad)
    {
        /* Window */
        ad->win = elm_win_util_standard_add(PACKAGE, PACKAGE);
        elm_win_conformant_set(ad->win, EINA_TRUE);
        elm_win_autodel_set(ad->win, EINA_TRUE);
    
        /* Conformant */
        ad->conform = elm_conformant_add(ad->win);
        elm_win_indicator_mode_set(ad->win, ELM_WIN_INDICATOR_SHOW);
        elm_win_indicator_opacity_set(ad->win, ELM_WIN_INDICATOR_OPAQUE);
        evas_object_size_hint_weight_set(ad->conform, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
        elm_win_resize_object_add(ad->win, ad->conform);
        evas_object_show(ad->conform);
    
        ad->naviframe = elm_naviframe_add(ad->conform);
        eext_object_event_callback_add(ad->naviframe, EEXT_CALLBACK_BACK, _naviframe_back_cb, ad);
        elm_object_content_set(ad->conform, ad->naviframe);
        evas_object_show(ad->naviframe);
    
        /* Creating each separate view for each scenario */
        ad->menu_list = elm_list_add(ad->naviframe);
        append_playback_menu(ad);
        append_broadcast_server_menu(ad);
        append_broadcast_client_menu(ad);
        append_voip_menu(ad);
    
        /* Show the window after the base GUI is set up */
        evas_object_show(ad->win);
    }
    
  2. Each append_XXX_menu() function calls the elm_list_item_append() function and sets the click event callback, _menu_click_cb(). This callback is called each time an element on the list is clicked.

    The following example is from the media_streamer_player.c file, related to the local playback scenario. After the local playback item is clicked on the list, the _create_streamers() smart callback is set on a naviframe instance. The local playback view is created by calling the _create_player_view() function.

    /* @brief This callback is called after click action is performed on the VoIP list element */
    static void
    _menu_click_cb(void *data, Evas_Object *obj, void *event_info)
    {
        appdata_s *ad = data;
    
        /* Add smart callback to create media streamer instances for the transition finished event */
        evas_object_smart_callback_add(ad->naviframe, "transition,finished", _create_streamer, ad);
        _create_player_view(ad->naviframe);
        ad->frame_item = elm_naviframe_item_push(ad->naviframe, PAGE_NAME, NULL, NULL, p_data.layout, NULL);
        elm_naviframe_item_pop_cb_set(ad->frame_item, _delete_streamer, NULL);
        dlog_print(DLOG_INFO, LOG_TAG, "Selected %s page", PAGE_NAME);
    
        Elm_List_Item *selected_item = (Elm_List_Item *)event_info;
        elm_list_item_selected_set(selected_item, EINA_FALSE);
    }
    
    /* @brief Function used for adding a scenario list item to the main view list */
    Elm_Object_Item*
    append_voip_menu(appdata_s *ad)
    {
        return elm_list_item_append(ad->menu_list, PAGE_NAME, NULL, NULL, _menu_click_cb, (void*)ad);
    }
    

Local Playback

The following figure illustrates the local playback view. On the left, the playback has not started. On the right, playback is in progress.

Figure: Media Streamer local playback view

Media Streamer local playback view

To implement the local playback feature:

  1. Create the player view.

    The following example shows parts of the _create_player_view() function. This code is related to the creation of the Evas_Object image object using the evas_object_image_filled_add() function. It is used further to render video content from the media streamer sink node. This object can be used in all scenarios that assume that video stream is present.

    /* @brief Function used for creating the local playback view */
    static void
    _create_player_view(Evas_Object *parent)
    {
        /* Video_rect is used to display video stream */
        p_data.video_rect = create_video_rect(p_data.layout);
        elm_table_pack(p_data.layout, p_data.video_rect, 0, 0, 4, 7);
    }
    
    /* @brief Function for creating the rectangular area (Evas object) used to display video content */
    Evas_Object*
    create_video_rect(Evas_Object *parent)
    {
        Evas *evas = evas_object_evas_get(parent);
        Evas_Object *rect = evas_object_image_filled_add(evas);
        evas_object_image_fill_spread_set(rect, EVAS_TEXTURE_REPEAT);
        evas_object_size_hint_weight_set(rect, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
        evas_object_size_hint_align_set(rect, EVAS_HINT_FILL, EVAS_HINT_FILL);
        evas_object_show(rect);
    
        return rect;
    }
    
  2. Create the media streamer instance.

    The _create_streamer() callback is called after the transition from the main view to the local playback view is finished. The media streamer instance is created using the media_streamer_create() function. In case of no errors (MEDIA_STREAMER_ERROR_NONE), create the nodes and add them to the media streamer instance. Use the media_streamer_set_error_cb() function to set the _streamer_error_cb() callback to be called each time when an error occurs.

    /* @brief Function used for encapsulating the media streamer instance creation */
    static void
    _create_streamer(void *data, Evas_Object *obj, void *event_info)
    {
        appdata_s *ad = (appdata_s *)data;
        if (!ad) {
            dlog_print(DLOG_ERROR, LOG_TAG, "Empty data in transition,finished callback.");
    
            return;
        }
    
        /* 
           Create the media streamer instance and set the error callback
           to be called if an error occurs during media streamer operation
        */
        if (media_streamer_create(&p_data.streamer) != MEDIA_STREAMER_ERROR_NONE) {
            dlog_print(DLOG_ERROR, LOG_TAG, "Fail to create media streamer");
    
            return;
        }
        media_streamer_set_error_cb(p_data.streamer, _streamer_error_cb, NULL);
    
  3. Create the source node.

    The local playback scenario uses local audio or video content. The type of the created source is the file source (MEDIA_STREAMER_NODE_SRC_TYPE_FILE). To create the source node, call the media_streamer_node_create_src() function. The parameters are the node type and pointer to the media_streamer_node_h handle. This handle is used in further manipulations. For that purpose, store it separately in a container, such as an array, list, or a hash table. To utilize the file source, set the URI of the content by calling the media_streamer_set_param() function. The URI is a path to the content available for the application. After the source node is created and the URI is set, add it to the media streamer instance by calling the media_streamer_add() function with media_streamer_h and media_streamer_node_h handles as parameters.

        /* Get the path to video content */
        char res_path[PATH_MAX] = {0,};
        app_get_resource(VIDEO_PATH, res_path, PATH_MAX);
    
        /* Create the source node of the MEDIA_STREAMER_NODE_SRC_TYPE_FILE type for reading content from a file */
        media_streamer_node_h file_src = NULL;
        media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_FILE, &file_src);
        dlog_print(DLOG_ERROR, LOG_TAG, "Res path %s", res_path);
    
        /* Add the created node to the media streamer instance */
        media_streamer_node_set_param(file_src, MEDIA_STREAMER_PARAM_URI, res_path);
        media_streamer_node_add(p_data.streamer, file_src);
        p_data.nodes[p_data.node_counter++] = file_src;
    
  4. Create a sink node.

    This sample has predefined content to test local playback: a video file. For this, create 2 sink nodes to render video and play audio from file.

    All sink nodes are created with the media_streamer_node_create_sink() function which is much the same as the media_streamer_node_create_src() function. Earlier, an Evas image object was added to the layout. Now, create a video sink of the MEDIA_STREAMER_NODE_SINK_TYPE_EVAS type to render video stream. Set the MEDIA_STREAMER_PARAM_EVAS_OBJECT parameter for the node to point to render the target as an image object created earlier.

        /* Create the sink node of the MEDIA_STREAMER_NODE_SINK_TYPE_EVAS type for displaying video content on an Evas object */
        media_streamer_node_h video_sink = NULL;
        media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_EVAS, &video_sink);
    
        /* Set MEDIA_STREAMER_PARAM_EVAS_OBJECT parameter to arbitrary evas object */
        media_streamer_node_set_param(video_sink, MEDIA_STREAMER_PARAM_EVAS_OBJECT, (const char*)p_data.video_rect);
    
        /* Add the created video_sink node to the media streamer instance */
        media_streamer_node_add(p_data.streamer, video_sink);
        p_data.nodes[p_data.node_counter++] = video_sink;
    

    Creation and addition of the audio sink is similar. No parameters are needed.

        /* Create sink node of the MEDIA_STREAMER_NODE_SINK_TYPE_AUDIO type for playing audio content */
        media_streamer_node_h audio_sink = NULL;
        media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_AUDIO, &audio_sink);
    
        /* Add the created audio_sink node to the media streamer instance */
        media_streamer_node_add(p_data.streamer, audio_sink);
        p_data.nodes[p_data.node_counter++] = audio_sink;
    

    After all required nodes have been added to the media streamer instance, change its state from MEDIA_STREAMER_STATE_IDLE to MEDIA_STREAMER_STATE_READY by calling the media_streamer_prepare() function.

        /* Prepare the media streamer instance after adding all required nodes */
        media_streamer_prepare(p_data.streamer);
    }
    
  5. In the _create_player_view() function, create a simple button and set a callback to be called after the click event occurs.
    /* @brief Function used for creating the local playback view */
    static void
    _create_player_view(Evas_Object *parent)
    {
        /* Play and pause button */
        p_data.pp_btn = elm_button_add(p_data.layout);
        elm_object_style_set(p_data.pp_btn, "circle");
        evas_object_smart_callback_add(p_data.pp_btn, "clicked", _play_clicked_cb, NULL);
        evas_object_size_hint_align_set(p_data.pp_btn, 0.5, 0.5);
        evas_object_show(p_data.pp_btn);
    }
    
  6. Manage the media streamer instance state transitions within the _play_clicked_cb() callback. When the user clicks the play or pause button, the media streamer instance state is checked by calling the media_streamer_get_state() function which has 2 parameters, the media_streamer_h handle and a pointer to the media_streamer_state_e variable. After calling the media_streamer_prepare() function, the state must be MEDIA_STREAMER_STATE_READY if no error occurred. To start playback, call the media_streamer_play() function. The state changes to MEDIA_STREAMER_STATE_PLAYING, the video starts to render, and audio can be heard.
    /* @brief This callback is called after clicking the play or pause button */
    static void
    _play_clicked_cb(void *data, Evas_Object *obj, void *event_info)
    {
        /* Handle play button click event in accordance to the current media streamer state */
        media_streamer_state_e state = MEDIA_STREAMER_STATE_NONE;
        media_streamer_get_state(p_data.streamer, &state);
        switch (state) {
        case MEDIA_STREAMER_STATE_PLAYING:
            /* 
               If the current media streamer state is MEDIA_STREAMER_STATE_PLAYING,
               pause it, freeze the ecore timer, and change the play button icon to "play.png"
            */
            media_streamer_pause(p_data.streamer);
            break;
        case MEDIA_STREAMER_STATE_PAUSED:
        case MEDIA_STREAMER_STATE_READY:
            /*
               If the current media streamer state is MEDIA_STREAMER_STATE_PAUSE or MEDIA_STREAMER_STATE_READY start playback, 
               reset and thaw the timer, the play button icon is changed
            */
            media_streamer_play(p_data.streamer);
            break;
        default:
            /* Default action for unknown state is error */
            dlog_print(DLOG_ERROR, LOG_TAG, "Media Streamer can't play from state [%d]", state);
            break;
        }
    }
    

    If the play or pause button is clicked again, the media_streamer_pause() function is called to pause the media streamer and set its state to MEDIA_STREAMER_STATE_PAUSED.