[0.6.177] check audio out for offload setup 57/202357/11 accepted/tizen/unified/20190401.225014 submit/tizen/20190329.054531
authorEunhye Choi <eunhae1.choi@samsung.com>
Wed, 27 Mar 2019 11:51:15 +0000 (20:51 +0900)
committerEunhye Choi <eunhae1.choi@samsung.com>
Thu, 28 Mar 2019 10:33:47 +0000 (19:33 +0900)
- get current audio device type and check whether
  it can support offload or not based on the ini
- add device connected cb to monitor the changes
  of audio device

Change-Id: I83349d6310dbe327250c58c7331b88343f3731be

packaging/libmm-player.spec
src/include/mm_player_ini.h
src/include/mm_player_priv.h
src/mm_player_ini.c
src/mm_player_priv.c

index 159c16e..ab63c49 100644 (file)
@@ -1,6 +1,6 @@
 Name:       libmm-player
 Summary:    Multimedia Framework Player Library
-Version:    0.6.176
+Version:    0.6.177
 Release:    0
 Group:      Multimedia/Libraries
 License:    Apache-2.0
index 1c682a7..193a480 100644 (file)
  * of each string item.
  */
 enum keyword_type {
-       KEYWORD_EXCLUDE,    // for element exclude keyworld
-       KEYWORD_DUMP,       // for dump element keyworld
+       KEYWORD_EXCLUDE,    // for element exclude keyword
+       KEYWORD_DUMP,       // for dump element keyword
        KEYWORD_UNSUPPORTED_CODEC, // for un-supported codec
        KEYWORD_A_SW_CODEC, // for audio sw codec
-       KEYWORD_V_SW_CODEC // for video sw codec
+       KEYWORD_V_SW_CODEC, // for video sw codec
+       KEYWORD_A_OFFLOAD,  // for audio device type which can support offload
 };
 
 typedef struct __mm_player_ini {
@@ -71,6 +72,7 @@ typedef struct __mm_player_ini {
        gchar audioresampler_element[PLAYER_INI_MAX_STRLEN];
        gchar audiosink_element[PLAYER_INI_MAX_STRLEN];
        gchar audio_offload_sink_element[PLAYER_INI_MAX_STRLEN];
+       gchar audio_offload_device_type[PLAYER_INI_MAX_ELEMENT][PLAYER_INI_MAX_STRLEN];
        gboolean skip_rescan;
        gboolean generate_dot;
        gboolean use_system_clock;
@@ -148,6 +150,7 @@ typedef struct __mm_player_ini {
 #define DEFAULT_AUDIOSINK                                 "pulsesink"
 #define DEFAULT_CODEC_HW                                  ""
 #define DEFAULT_CODEC_SW                                  ""
+#define DEFAULT_A_OFFLOAD_DEVICE_TYPE                     ""
 #define DEFAULT_GST_PARAM                                 ""
 #define DEFAULT_EXCLUDE_KEYWORD                           ""
 #define DEFAULT_UNSUPPORTED_CODEC_KEYWORD                 ""
index 216357a..726f776 100644 (file)
@@ -742,9 +742,6 @@ typedef struct {
        GCond subtitle_info_cond;
        GMutex subtitle_info_mutex;
 
-       /* To store the current multiwindow status */
-       gboolean last_multiwin_status;
-
        /* To store the current running audio pad index of demuxer */
        gint demux_pad_index;
 
@@ -798,6 +795,7 @@ typedef struct {
 
        /* build audio offload */
        gboolean build_audio_offload;
+       guint audio_device_cb_id;
 } mm_player_t;
 
 typedef struct {
index d8f022a..dca9e1e 100644 (file)
@@ -173,6 +173,9 @@ mm_player_ini_load(mm_player_ini_t *ini)
                        iniparser_getstring(dict, "general:element exclude keyword", DEFAULT_EXCLUDE_KEYWORD), KEYWORD_EXCLUDE);
 
                __get_element_list(ini,
+                       iniparser_getstring(dict, "general:audio offload device type", DEFAULT_A_OFFLOAD_DEVICE_TYPE), KEYWORD_A_OFFLOAD);
+
+               __get_element_list(ini,
                        iniparser_getstring(dict, "general:unsupported codec keyword", DEFAULT_UNSUPPORTED_CODEC_KEYWORD), KEYWORD_UNSUPPORTED_CODEC);
 
                MMPLAYER_INI_GET_STRING(dict, ini->gst_param[0], "general:gstparam1", DEFAULT_GST_PARAM);
@@ -221,6 +224,7 @@ mm_player_ini_load(mm_player_ini_t *ini)
 
                __get_element_list(ini, DEFAULT_CODEC_SW, KEYWORD_A_SW_CODEC);
                __get_element_list(ini, DEFAULT_CODEC_SW, KEYWORD_V_SW_CODEC);
+               __get_element_list(ini, DEFAULT_A_OFFLOAD_DEVICE_TYPE, KEYWORD_A_OFFLOAD);
                __get_element_list(ini, DEFAULT_EXCLUDE_KEYWORD, KEYWORD_EXCLUDE);
                __get_element_list(ini, DEFAULT_UNSUPPORTED_CODEC_KEYWORD, KEYWORD_UNSUPPORTED_CODEC);
 
@@ -261,6 +265,8 @@ mm_player_ini_load(mm_player_ini_t *ini)
        LOGD("audio resampler element : %s", ini->audioresampler_element);
        LOGD("audiosink element : %s", ini->audiosink_element);
        LOGD("audio offload sink element : %s", ini->audio_offload_sink_element);
+       for (idx = 0; ini->audio_offload_device_type[idx][0] != '\0'; idx++)
+               LOGD("audio_offload_device_type [%d] : %s", idx, ini->audio_offload_device_type[idx]);
        LOGD("generate dot : %d", ini->generate_dot);
        LOGD("use system clock(video only) : %d", ini->use_system_clock);
        LOGD("live state change timeout(sec) : %d", ini->live_state_change_timeout);
@@ -446,6 +452,7 @@ __get_element_list(mm_player_ini_t *ini, gchar *str, int keyword_type)
        gchar **walk = NULL;
        gint i = 0;
        gchar *strtmp = NULL;
+       gchar (*ini_keyword)[PLAYER_INI_MAX_STRLEN] = {NULL, };
 
        if (!str)
                return;
@@ -458,7 +465,6 @@ __get_element_list(mm_player_ini_t *ini, gchar *str, int keyword_type)
        /* trimming. it works inplace */
        g_strstrip(strtmp);
 
-
        /* split */
        list = g_strsplit(strtmp, ",", 10);
 
@@ -470,72 +476,45 @@ __get_element_list(mm_player_ini_t *ini, gchar *str, int keyword_type)
        /* copy list */
        switch (keyword_type) {
        case KEYWORD_EXCLUDE:
-       {
-               for (walk = list; *walk; walk++) {
-                       strncpy(ini->exclude_element_keyword[i], *walk, (PLAYER_INI_MAX_STRLEN - 1));
-                       g_strstrip(ini->exclude_element_keyword[i]);
-                       ini->exclude_element_keyword[i][PLAYER_INI_MAX_STRLEN -1] = '\0';
-                       i++;
-               }
-               /* mark last item to NULL */
-               ini->exclude_element_keyword[i][0] = '\0';
-
+               ini_keyword = ini->exclude_element_keyword;
                break;
-       }
        case KEYWORD_DUMP:
-       {
-               for (walk = list; *walk; walk++) {
-                       strncpy(ini->dump_element_keyword[i], *walk, (PLAYER_INI_MAX_STRLEN - 1));
-                       g_strstrip(ini->dump_element_keyword[i]);
-                       ini->dump_element_keyword[i][PLAYER_INI_MAX_STRLEN -1] = '\0';
-                       i++;
-               }
-               /* mark last item to NULL */
-               ini->dump_element_keyword[i][0] = '\0';
-
+               ini_keyword = ini->dump_element_keyword;
                break;
-       }
        case KEYWORD_UNSUPPORTED_CODEC:
-       {
-               for (walk = list; *walk; walk++) {
-                       strncpy(ini->unsupported_codec_keyword[i], *walk, (PLAYER_INI_MAX_STRLEN - 1));
-                       g_strstrip(ini->unsupported_codec_keyword[i]);
-                       ini->unsupported_codec_keyword[i][PLAYER_INI_MAX_STRLEN -1] = '\0';
-                       i++;
-               }
-               /* mark last item to NULL */
-               ini->unsupported_codec_keyword[i][0] = '\0';
+               ini_keyword = ini->unsupported_codec_keyword;
                break;
-       }
        case KEYWORD_V_SW_CODEC:
-       {
-               for (walk = list; *walk; walk++) {
-                       strncpy(ini->videocodec_element_sw[i], *walk, (PLAYER_INI_MAX_STRLEN - 1));
-                       g_strstrip(ini->videocodec_element_sw[i]);
-                       ini->videocodec_element_sw[i][PLAYER_INI_MAX_STRLEN -1] = '\0';
-                       i++;
-               }
-               /* mark last item to NULL */
-               ini->videocodec_element_sw[i][0] = '\0';
+               ini_keyword = ini->videocodec_element_sw;
                break;
-       }
        case KEYWORD_A_SW_CODEC:
-       {
-               for (walk = list; *walk; walk++) {
-                       strncpy(ini->audiocodec_element_sw[i], *walk, (PLAYER_INI_MAX_STRLEN - 1));
-                       g_strstrip(ini->audiocodec_element_sw[i]);
-                       ini->audiocodec_element_sw[i][PLAYER_INI_MAX_STRLEN -1] = '\0';
-                       i++;
-               }
-               /* mark last item to NULL */
-               ini->audiocodec_element_sw[i][0] = '\0';
+               ini_keyword = ini->audiocodec_element_sw;
+               break;
+       case KEYWORD_A_OFFLOAD:
+               ini_keyword = ini->audio_offload_device_type;
                break;
-       }
-
        default:
+               goto EXIT;
                break;
        }
 
+       for (walk = list; *walk && ini_keyword[i]; walk++) {
+               strncpy(ini_keyword[i], *walk, (PLAYER_INI_MAX_STRLEN - 1));
+               g_strstrip(ini_keyword[i]);
+               ini_keyword[i][PLAYER_INI_MAX_STRLEN -1] = '\0';
+               i++;
+       }
+
+       /* mark last item to NULL */
+       if (ini_keyword[i]) {
+               ini_keyword[i][0] = '\0';
+       } else {
+               LOGE("too many keyword exist in list (%d)", i);
+               if (i > 0)
+                       ini_keyword[i-1][0] = '\0';
+       }
+
+EXIT:
        g_strfreev(list);
        MMPLAYER_FREEIF(strtmp);
 }
index c241425..75b3e1a 100644 (file)
 #include <sys/time.h>
 #include <stdlib.h>
 #include <dlog.h>
+#include <gio/gio.h>
 
 #include <mm_error.h>
 #include <mm_attrs.h>
+#include <mm_sound.h>
 
 #include "mm_player_priv.h"
 #include "mm_player_ini.h"
@@ -4858,7 +4860,6 @@ _mmplayer_realize(MMHandleType hplayer)
        player->demux_pad_index = 0;
        player->subtitle_language_list = NULL;
        player->is_subtitle_force_drop = FALSE;
-       player->last_multiwin_status = FALSE;
 
        __mmplayer_track_initialize(player);
        __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
@@ -6826,7 +6827,124 @@ __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad *pad,
 }
 
 static gboolean
-__mmplayer_check_offload_path(mm_player_t *player)
+__mmplayer_is_offload_supportable(mm_player_t *player)
+{
+       gboolean ret = TRUE;
+       GDBusConnection *conn = NULL;
+       GError *err = NULL;
+       GVariant *result = NULL;
+       const gchar *dbus_device_type = NULL;
+       const gchar *dbus_ret = NULL;
+       gint idx = 0;
+
+       conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+       if (!conn || err) {
+               LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
+               g_error_free(err);
+               ret = FALSE;
+               goto DONE;
+       }
+
+       result = g_dbus_connection_call_sync(conn,
+                                       "org.pulseaudio.Server",
+                                       "/org/pulseaudio/StreamManager",
+                                       "org.pulseaudio.StreamManager",
+                                       "GetCurrentMediaRoutingPath",
+                                       g_variant_new("(s)", "out"),
+                                       G_VARIANT_TYPE("(ss)"),
+                                       G_DBUS_CALL_FLAGS_NONE,
+                                       2000,
+                                       NULL,
+                                       &err);
+       if (!result || err) {
+               LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
+               g_error_free(err);
+               ret = FALSE;
+               goto DONE;
+       }
+
+       /* device type is listed in stream-map.json at mmfw-sysconf */
+       g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
+
+       LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
+       if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
+               ret = FALSE;
+               goto DONE;
+       }
+
+       /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
+       for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
+               if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
+                       LOGD("audio offload is supportable");
+                       ret = TRUE;
+                       goto DONE;
+               }
+       }
+
+       LOGD("audio offload is not supportable");
+       ret = FALSE;
+
+DONE:
+       g_variant_unref(result);
+       g_object_unref(conn);
+
+       return ret;
+}
+
+void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
+{
+       mm_player_t *player = (mm_player_t *)user_data;
+       mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
+       gboolean is_supportable = FALSE;
+
+       if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
+               LOGW("failed to get device type");
+       else
+               LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
+
+       if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
+               (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
+               (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
+               LOGD("ignore this dev connected info");
+               return;
+       }
+
+       is_supportable = __mmplayer_is_offload_supportable(player);
+       if (player->build_audio_offload == is_supportable) {
+               LOGD("keep current pipeline without re-building");
+               return;
+       }
+
+       /* FIXME: rebuild pipeline */
+       LOGD("FIXME: re-build pipeline");
+
+       return;
+}
+
+static gboolean
+__mmplayer_add_audio_device_connected_cb(mm_player_t *player)
+{
+       unsigned int id = 0;
+
+       if (player->audio_device_cb_id != 0) {
+               LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
+               return TRUE;
+       }
+
+       if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
+                               __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
+               LOGD("added device connected cb (%u)", id);
+               player->audio_device_cb_id = id;
+       } else {
+               LOGW("failed to add device connected cb");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static gboolean
+__mmplayer_can_build_audio_offload_path(mm_player_t *player)
 {
        gboolean ret = FALSE;
        GstElementFactory *factory = NULL;
@@ -6834,22 +6952,35 @@ __mmplayer_check_offload_path(mm_player_t *player)
        MMPLAYER_FENTER();
        MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
 
-       if (strcmp(player->ini.audio_offload_sink_element, "")) {
-               /* FIXME : 1. need to consider the current audio output path and
-                       player have to know whether it support offload or not.
-                       2. could be added new condition about content length */
-               LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
-               if (!__mmplayer_is_only_mp3_type(player->type))
-                       goto DONE;
+       LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
+       if (!__mmplayer_is_only_mp3_type(player->type))
+               goto DONE;
 
-               factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
-               if (!factory)
-                       goto DONE;
+       if (!strcmp(player->ini.audio_offload_sink_element, "")) {
+               LOGD("there is no audio offload sink");
+               goto DONE;
+       }
 
-               LOGD("can setup the audio offload path");
-               gst_object_unref(factory);
-               ret = TRUE;
+       if (player->ini.audio_offload_device_type[0][0] == '\0') {
+               LOGW("there is no audio device type to support offload");
+               goto DONE;
+       }
+
+       factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
+       if (!factory) {
+               LOGW("there is no installed audio offload sink element");
+               goto DONE;
        }
+       gst_object_unref(factory);
+
+       if (!__mmplayer_add_audio_device_connected_cb(player))
+               goto DONE;
+
+       if (!__mmplayer_is_offload_supportable(player))
+               goto DONE;
+
+       LOGD("audio offload can be built");
+       ret = TRUE;
 
 DONE:
        MMPLAYER_FLEAVE();
@@ -6865,10 +6996,10 @@ __mmplayer_check_codec_info(mm_player_t *player, const char *klass, GstCaps *cap
        int audio_offload = 0;
 
        if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
-               mm_attrs_get_int_by_name(player->attrs, "audio_offload", &audio_offload); /* user setting */
+               mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
 
-               if (audio_offload && __mmplayer_check_offload_path(player)) {
-                       LOGD("expose audio path to build offload path");
+               if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
+                       LOGD("expose audio path to build offload output path");
                        player->build_audio_offload = TRUE;
                        /* update codec info */
                        player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
@@ -7337,7 +7468,6 @@ __mmplayer_release_misc(mm_player_t *player)
        player->is_subtitle_force_drop = FALSE;
        player->play_subtitle = FALSE;
        player->adjust_subtitle_pos = 0;
-       player->last_multiwin_status = FALSE;
        player->has_closed_caption = FALSE;
        player->set_mode.media_packet_video_stream = false;
        player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
@@ -7345,6 +7475,10 @@ __mmplayer_release_misc(mm_player_t *player)
        /* recover mode */
        player->set_mode.rich_audio = cur_mode;
 
+       if (mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
+               LOGW("failed to remove audio device_connected_callback");
+       player->audio_device_cb_id = 0;
+
        for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
                player->bitrate[i] = 0;
                player->maximum_bitrate[i] = 0;