[0.6.193] Apply client PID to pulsesink properties
[platform/core/multimedia/libmm-player.git] / src / mm_player_tracks.c
1 /*
2  * libmm-player
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, naveen cherukuri <naveen.ch@samsung.com>,
7  * YeJin Cho <cho.yejin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22 #include <dlog.h>
23 #include <mm_error.h>
24 #include "mm_player_utils.h"
25 #include "mm_player_tracks.h"
26
27 #define INVALID_TRACK_INDEX -1
28 #define LANGUAGE_CODE_SIZE (3 + 1) /* Size of ISO-639-1, and considering the nul-terminator */
29
30 /*---------------------------------------------------------------------------------------
31 |    LOCAL FUNCTION PROTOTYPES:                                                                               |
32 ---------------------------------------------------------------------------------------*/
33 static int __mmplayer_track_get_language(mmplayer_t *player, mmplayer_track_type_e type, gint stream_index, gchar **code);
34
35
36 /*=======================================================================================
37 |  FUNCTION DEFINITIONS                                                                                      |
38 =======================================================================================*/
39 int
40 _mmplayer_get_track_count(MMHandleType hplayer,  mmplayer_track_type_e type, int *count)
41 {
42         int ret = MM_ERROR_NONE;
43         mmplayer_t *player = (mmplayer_t *)hplayer;
44         MMHandleType attrs = 0;
45
46         MMPLAYER_FENTER();
47
48         /* check player handle */
49         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
50         MMPLAYER_RETURN_VAL_IF_FAIL(count, MM_ERROR_INVALID_ARGUMENT);
51         MMPLAYER_RETURN_VAL_IF_FAIL((MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)
52                  || (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING),
53                 MM_ERROR_PLAYER_INVALID_STATE);
54
55         attrs = MMPLAYER_GET_ATTRS(player);
56         if (!attrs) {
57                 LOGE("cannot get content attribute");
58                 return MM_ERROR_PLAYER_INTERNAL;
59         }
60
61         *count = 0;
62
63         switch (type) {
64         case MM_PLAYER_TRACK_TYPE_AUDIO:
65                 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num > 0)
66                         *count = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num;
67                 break;
68         case MM_PLAYER_TRACK_TYPE_TEXT: /* internal or external */
69                 ret = mm_attrs_get_int_by_name(attrs, "content_text_track_num", count);
70                 break;
71         default:
72                 ret = MM_ERROR_INVALID_ARGUMENT;
73                 break;
74         }
75
76         LOGD("type: %d, the num of track: %d", type, *count);
77
78         MMPLAYER_FLEAVE();
79
80         return ret;
81 }
82
83 int
84 _mmplayer_select_track(MMHandleType hplayer, mmplayer_track_type_e type, int index)
85 {
86         int ret = MM_ERROR_NONE;
87         mmplayer_t *player = (mmplayer_t *)hplayer;
88
89         MMPLAYER_FENTER();
90         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
91
92         LOGD("track type: %d, index: %d", type, index);
93
94         MMPLAYER_SUBTITLE_INFO_LOCK(player);
95
96         if (type == MM_PLAYER_TRACK_TYPE_TEXT && player->subtitle_language_list) { /* external subtitle */
97                 GstElement *subparse = NULL;
98                 mmplayer_lang_info_t *temp = NULL;
99                 guint num_of_list = 0;
100
101                 if (!player->pipeline || !player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst) {
102                         ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
103                         goto EXIT;
104                 }
105
106                 num_of_list = g_list_length(player->subtitle_language_list);
107                 if (index < 0 || index >= num_of_list) {
108                         LOGE("req track index is wrong");
109                         ret = MM_ERROR_INVALID_ARGUMENT;
110                         goto EXIT;
111                 }
112
113                 temp = g_list_nth_data(player->subtitle_language_list, index);
114                 if (!temp) {
115                         LOGE("fail to get lang from list");
116                         ret = MM_ERROR_PLAYER_INTERNAL;
117                         goto EXIT;
118                 }
119                 subparse = player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst;
120                 LOGD("setting to language %s", temp->language_code);
121                 g_object_set(G_OBJECT(subparse), "current-language", temp->language_key, NULL);
122
123                 _mmplayer_sync_subtitle_pipeline(player);
124
125         } else { /* audio or internal subtitle */
126                 ret = _mmplayer_change_track_language(hplayer, type, index);
127                 if (ret != MM_ERROR_NONE) {
128                         LOGE("failed to change track");
129                         goto EXIT;
130                 }
131         }
132
133         if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
134                 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
135                 if (!attrs) {
136                         LOGE("cannot get content attribute");
137                         ret = MM_ERROR_PLAYER_INTERNAL;
138                         goto EXIT;
139                 }
140
141                 mm_attrs_set_int_by_name(attrs, "current_text_track_index", index);
142
143                 if (mm_attrs_commit_all(attrs)) {
144                         LOGE("failed to commit");
145                         ret = MM_ERROR_PLAYER_INTERNAL;
146                         goto EXIT;
147                 }
148         }
149
150         LOGD("current index is updated");
151
152 EXIT:
153         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
154         MMPLAYER_FLEAVE();
155         return ret;
156 }
157
158 int
159 _mmplayer_get_current_track(MMHandleType hplayer, mmplayer_track_type_e type, int *index)
160 {
161         int ret = MM_ERROR_NONE;
162         mmplayer_t *player = (mmplayer_t *)hplayer;
163         MMHandleType attrs = 0;
164         gint count = 0;
165
166         MMPLAYER_FENTER();
167         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
168         MMPLAYER_RETURN_VAL_IF_FAIL(index, MM_ERROR_INVALID_ARGUMENT);
169
170         attrs = MMPLAYER_GET_ATTRS(player);
171         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
172
173         MMPLAYER_SUBTITLE_INFO_LOCK(player);
174
175         LOGD("track type: %d", type);
176
177         *index = INVALID_TRACK_INDEX;
178
179         switch (type) {
180         case MM_PLAYER_TRACK_TYPE_AUDIO:
181                 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) {
182                         LOGW("there is no audio track");
183                         ret = MM_ERROR_PLAYER_NO_OP;
184                         goto EXIT;
185                 }
186
187                 *index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
188                 break;
189         case MM_PLAYER_TRACK_TYPE_TEXT: /* internal or external */
190                 mm_attrs_get_int_by_name(attrs, "content_text_track_num", &count);
191                 if (count <= 0) {
192                         LOGD("there is no text track");
193                         ret = MM_ERROR_PLAYER_NO_OP;
194                         goto EXIT;
195                 }
196
197                 mm_attrs_get_int_by_name(attrs, "current_text_track_index", index);
198                 break;
199         default:
200                 LOGD("invalid input type");
201                 ret = MM_ERROR_INVALID_ARGUMENT;
202                 goto EXIT;
203         }
204
205         if (*index < 0) {
206                 LOGE("invalid track index");
207                 ret = MM_ERROR_PLAYER_INTERNAL;
208                 goto EXIT;
209         }
210
211         LOGD("current track index: %d", *index);
212
213 EXIT:
214         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
215         MMPLAYER_FLEAVE();
216         return ret;
217 }
218
219 int
220 _mmplayer_get_track_language_code(MMHandleType hplayer, mmplayer_track_type_e type, int index, char **code)
221 {
222         int ret = MM_ERROR_NONE;
223         mmplayer_t *player = (mmplayer_t *)hplayer;
224         gchar *lang_code = NULL;
225
226         MMPLAYER_FENTER();
227         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
228         MMPLAYER_RETURN_VAL_IF_FAIL(code, MM_ERROR_INVALID_ARGUMENT);
229
230         MMPLAYER_SUBTITLE_INFO_LOCK(player);
231
232         if (type == MM_PLAYER_TRACK_TYPE_TEXT && player->subtitle_language_list) { /* external subtitle */
233                 mmplayer_lang_info_t *language_list = NULL;
234
235                 lang_code = (gchar *)g_malloc0(LANGUAGE_CODE_SIZE * sizeof(char));
236
237                 language_list = g_list_nth_data(player->subtitle_language_list, index);
238                 if (language_list == NULL) {
239                         LOGE("invalid index %d", index);
240                         ret = MM_ERROR_INVALID_ARGUMENT;
241                         goto EXIT;
242                 }
243                 g_strlcpy(lang_code, language_list->language_code, LANGUAGE_CODE_SIZE);
244         } else { /* audio or internal subtitle */
245                 if (player->selector[type].total_track_num <= 0) {
246                         LOGW("language list is not available. [type:%d]", type);
247                         ret = MM_ERROR_PLAYER_NO_OP;
248                         goto EXIT;
249                 }
250
251                 ret = __mmplayer_track_get_language(player, type, index, &lang_code);
252         }
253
254 EXIT:
255         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
256
257         *code = NULL;
258         if (ret == MM_ERROR_NONE) {
259                 if (g_strcmp0(lang_code, "und"))
260                         *code = strndup(lang_code, 2);
261                 else
262                         *code = strndup("und", 3);
263         }
264         MMPLAYER_FREEIF(lang_code);
265
266         MMPLAYER_FLEAVE();
267         return ret;
268 }
269
270 void
271 _mmplayer_track_initialize(mmplayer_t *player)
272 {
273         mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_AUDIO;
274
275         MMPLAYER_FENTER();
276
277         for (; type < MM_PLAYER_TRACK_TYPE_MAX ; type++) {
278                 /* active_pad_index is initialized when player is created or destroyed.
279                    and the value can be set by calling _mmplayer_change_track_language()
280                    before pipeline is created.*/
281                 player->selector[type].total_track_num = 0;
282                 player->selector[type].channels = g_ptr_array_new();
283         }
284 }
285
286 void
287 _mmplayer_track_destroy(mmplayer_t *player)
288 {
289         mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_AUDIO;
290         MMHandleType attrs = 0;
291         MMPLAYER_FENTER();
292
293         attrs = MMPLAYER_GET_ATTRS(player);
294         if (attrs) {
295                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 0);
296                 mm_attrs_set_int_by_name(attrs, "current_text_track_index", INVALID_TRACK_INDEX);
297
298                 if (mm_attrs_commit_all(attrs))
299                         LOGE("failed to commit");
300         }
301
302         for (; type < MM_PLAYER_TRACK_TYPE_MAX ; type++) {
303                 player->selector[type].active_pad_index = 0;
304                 player->selector[type].total_track_num = 0;
305
306                 if (player->selector[type].channels)
307                         g_ptr_array_free(player->selector[type].channels, TRUE);
308                 player->selector[type].channels = NULL;
309         }
310 }
311
312 void
313 _mmplayer_track_update_selector_info(mmplayer_t *player, mmplayer_track_type_e type, GstPad *sinkpad)
314 {
315         MMPLAYER_FENTER();
316
317         player->selector[type].total_track_num++;
318         g_ptr_array_add(player->selector[type].channels, sinkpad);
319
320         LOGD("type: %d, track cnt: %d", type, player->selector[type].total_track_num);
321 }
322
323 void
324 _mmplayer_track_update_text_attr_info(mmplayer_t *player, GstMessage *msg)
325 {
326          MMHandleType attrs = 0;
327          const GValue *lang_list = NULL;
328          mmplayer_lang_info_t *temp = NULL;
329          gchar *current_lang = NULL;
330          gint  track_index = INVALID_TRACK_INDEX;
331          guint track_count = 0, index = 0;
332
333          MMPLAYER_FENTER();
334          MMPLAYER_RETURN_IF_FAIL(player && msg);
335
336         attrs = MMPLAYER_GET_ATTRS(player);
337         if (!attrs) {
338                 LOGE("failed to get content attribute");
339                 return;
340         }
341
342         if (!gst_message_get_structure(msg)) {
343                 LOGE("failed to get msg structure");
344                 return;
345         }
346
347         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
348         if (!lang_list) {
349                 LOGW("language list is null");
350                 return;
351         }
352
353         track_count = g_list_length((GList *)g_value_get_pointer(lang_list));
354         if (track_count == 0) {
355                 LOGW("track count is zero");
356                 return;
357         }
358
359         MMPLAYER_SUBTITLE_INFO_LOCK(player);
360         player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
361         mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)track_count);
362         g_object_get(G_OBJECT(msg->src), "current-language", &current_lang, NULL);
363
364         LOGI("track count: %d, current track lang: %s", track_count, current_lang);
365         if (!current_lang)
366                 goto EXIT;
367
368         for (index = 0 ; index < track_count ; index++) {
369                 temp = g_list_nth_data(player->subtitle_language_list, index);
370                 if (temp) {
371                         LOGI("[%d] lang_key: %s, lang_code: %s",
372                                 index, temp->language_key, temp->language_code);
373
374                         if (!g_strcmp0(temp->language_key, current_lang)) {
375                                 LOGD("current track index : %d", index);
376                                 track_index = index;
377                                 break;
378                         }
379                 }
380         }
381
382         if (track_index > INVALID_TRACK_INDEX)
383                 mm_attrs_set_int_by_name(attrs, "current_text_track_index", track_index);
384         else
385                 LOGE("failed to find current track index");
386
387         if (mm_attrs_commit_all(attrs))
388                 LOGE("failed to commit");
389
390 EXIT:
391         MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
392         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
393
394         MMPLAYER_FLEAVE();
395 }
396
397 static int
398 __mmplayer_track_get_language(mmplayer_t *player, mmplayer_track_type_e type, gint stream_index, gchar **code)
399 {
400         GstTagList *tag_list = NULL;
401         gchar *tag = NULL;
402         GstPad *sinkpad = NULL;
403
404         MMPLAYER_FENTER();
405         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
406         MMPLAYER_RETURN_VAL_IF_FAIL((code && (stream_index >= 0) &&
407                 (stream_index < player->selector[type].total_track_num)), MM_ERROR_INVALID_ARGUMENT);
408
409         LOGD("type: %d, track count: %d, intput idx: %d", type, player->selector[type].total_track_num, stream_index);
410
411         *code = (gchar *)g_malloc0(LANGUAGE_CODE_SIZE * sizeof(char));
412
413         sinkpad = g_ptr_array_index(player->selector[type].channels, stream_index);
414
415         g_object_get(sinkpad, "tags", &tag_list, NULL);
416         if (tag_list)
417                 gst_tag_list_get_string(tag_list, GST_TAG_LANGUAGE_CODE, &tag);
418
419         if (tag) {
420                 LOGD("language code: %s, len: %zu", tag, strlen(tag));
421                 g_strlcpy(*code, tag, LANGUAGE_CODE_SIZE);
422                 MMPLAYER_FREEIF(tag);
423         } else {
424                 LOGD("no language code info - und");
425                 g_strlcpy(*code, "und", LANGUAGE_CODE_SIZE);
426         }
427
428         if (tag_list)
429                 gst_tag_list_unref(tag_list);
430
431         MMPLAYER_FLEAVE();
432         return MM_ERROR_NONE;
433 }