Merge "Fixed SVACE critical issues" into tizen_3.0
[platform/core/multimedia/libmm-player.git] / src / mm_player_pd.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_pd.h"
25 #include "mm_player_utils.h"
26 #include "mm_player_priv.h"
27
28 /*---------------------------------------------------------------------------------------
29 |    LOCAL FUNCTION PROTOTYPES:                                                                                                                 |
30 ---------------------------------------------------------------------------------------*/
31
32 /* It's callback to process whenever there is some changes in PD downloader. */
33 static gboolean __pd_downloader_callback(GstBus *bus, GstMessage *msg, gpointer data);
34
35 /* This function posts messages to application. */
36 /* Currently, MM_MESSAGE_PD_DOWNLOADER_START and MM_MESSAGE_PD_DOWNLOADER_END are used. */
37 static gboolean __pd_downloader_post_message(mm_player_t * player, enum MMMessageType msgtype, MMMessageParamType* param);
38
39 /*=======================================================================================
40 |  FUNCTION DEFINITIONS                                                                                                                                 |
41 =======================================================================================*/
42 static gboolean
43 __pd_downloader_callback(GstBus *bus, GstMessage *msg, gpointer data)
44 {
45         mm_player_t * player = NULL;
46         mm_player_pd_t *pd = NULL;
47         gboolean bret = TRUE;
48
49         MMPLAYER_FENTER();
50
51         /* chech player handle */
52         MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_INVALID_ARGUMENT);
53
54         player = MM_PLAYER_CAST((MMHandleType)data);
55
56         /* get PD downloader handle */
57         pd = MM_PLAYER_GET_PD((MMHandleType)data);
58
59         MMPLAYER_RETURN_VAL_IF_FAIL(pd, MM_ERROR_INVALID_ARGUMENT);
60
61 //      g_print("%s\n", GST_MESSAGE_TYPE_NAME(msg));
62
63         switch (GST_MESSAGE_TYPE(msg)) {
64         case GST_MESSAGE_EOS:
65                 {
66                         LOGD("PD Downloader EOS received....\n");
67
68                         g_object_set(G_OBJECT(pd->playback_pipeline_src), "eos", TRUE, NULL);
69
70                         /* notify application that download is completed */
71                         __pd_downloader_post_message(player, MM_MESSAGE_PD_DOWNLOADER_END, NULL);
72
73                         #ifdef PD_SELF_DOWNLOAD
74                         _mmplayer_unrealize_pd_downloader((MMHandleType)data);
75                         #endif
76                 }
77                 break;
78
79         case GST_MESSAGE_ERROR:
80                 {
81                         GError *error = NULL;
82                         gchar* debug = NULL;
83                         GstMessage *new_msg = NULL;
84
85                         /* get error code */
86                         gst_message_parse_error(msg, &error, &debug);
87                         LOGE("GST_MESSAGE_ERROR = %s\n", debug);
88
89                         new_msg = gst_message_new_error(GST_OBJECT_CAST(pd->playback_pipeline_src), error, debug);
90
91                         /* notify application that pd has any error */
92                         gst_element_post_message(pd->playback_pipeline_src, new_msg);
93
94                         _mmplayer_unrealize_pd_downloader((MMHandleType)data);
95                         MMPLAYER_FREEIF(debug);
96                         g_error_free(error);
97                 }
98                 break;
99
100         case GST_MESSAGE_WARNING:
101                 {
102                         char* debug = NULL;
103                         GError* error = NULL;
104
105                         gst_message_parse_warning(msg, &error, &debug);
106                         LOGW("warning : %s\n", error->message);
107                         LOGW("debug : %s\n", debug);
108
109                         MMPLAYER_FREEIF(debug);
110                         g_error_free(error);
111                 }
112                 break;
113
114         case GST_MESSAGE_STATE_CHANGED:
115         {
116                 GstState old_state, new_state;
117                 gchar *src_name;
118
119                 /* get old and new state */
120                 gst_message_parse_state_changed(msg, &old_state, &new_state, NULL);
121
122                 if (old_state == new_state)
123                         break;
124
125                 /* we only care about pipeline state changes */
126                 if (GST_MESSAGE_SRC(msg) != GST_OBJECT(pd->downloader_pipeline))
127                         break;
128
129                 src_name = gst_object_get_name(msg->src);
130                 LOGD("%s changed state from %s to %s", src_name,
131                         gst_element_state_get_name(old_state),
132                         gst_element_state_get_name(new_state));
133                 g_free(src_name);
134
135                 switch (new_state) {
136                 case GST_STATE_VOID_PENDING:
137                 case GST_STATE_NULL:
138                 case GST_STATE_READY:
139                 case GST_STATE_PAUSED:
140                         break;
141
142                 case GST_STATE_PLAYING:
143                                 /* notify application that download is stated */
144                         __pd_downloader_post_message(player, MM_MESSAGE_PD_DOWNLOADER_START, NULL);
145                         break;
146
147                 default:
148                         break;
149                 }
150         }
151         break;
152
153         case GST_MESSAGE_DURATION:
154         {
155                 gint64 size = 0LL;
156
157                 /* get total size  of download file, (bytes) */
158                 if (!gst_element_query_duration(pd->downloader_pipeline, GST_FORMAT_BYTES, &size)) {
159                         GError *err = NULL;
160                         GstMessage *new_msg = NULL;
161
162                         err = g_error_new(GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED, "can't get total size");
163                         new_msg = gst_message_new_error(GST_OBJECT_CAST(pd->playback_pipeline_src), err, NULL);
164                         gst_element_post_message(pd->playback_pipeline_src, new_msg);
165
166                         g_error_free(err);
167
168                         // TODO: check if playback pipeline is closed well or not
169                         g_object_set(G_OBJECT(pd->playback_pipeline_src), "eos", TRUE, NULL);
170
171                         _mmplayer_unrealize_pd_downloader((MMHandleType)data);
172
173                         LOGE("failed to query total size for download\n");
174                         break;
175                 }
176
177                 pd->total_size = size;
178
179                 LOGD("PD total size : %lld bytes\n", size);
180         }
181         break;
182
183         default:
184                 LOGW("unhandled message\n");
185                 break;
186         }
187
188         MMPLAYER_FLEAVE();
189
190         return bret;
191 }
192
193
194 gboolean __pd_downloader_post_message(mm_player_t * player, enum MMMessageType msgtype, MMMessageParamType* param)
195 {
196         MMPLAYER_FENTER();
197
198         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
199
200         if (!player->pd_msg_cb) {
201                 LOGW("no msg callback. can't post\n");
202                 return FALSE;
203         }
204
205         player->pd_msg_cb(msgtype, param, player->pd_msg_cb_param);
206
207         MMPLAYER_FLEAVE();
208
209         return TRUE;
210 }
211
212
213 int _mmplayer_get_pd_downloader_status(MMHandleType handle, guint64 *current_pos, guint64 *total_size)
214 {
215         MMPLAYER_FENTER();
216
217         mm_player_pd_t * pd = NULL;
218         guint64 bytes = 0;
219
220         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_INVALID_ARGUMENT);
221
222         pd = MM_PLAYER_GET_PD(handle);
223
224         MMPLAYER_RETURN_VAL_IF_FAIL(pd, MM_ERROR_INVALID_ARGUMENT);
225         MMPLAYER_RETURN_VAL_IF_FAIL(pd->downloader_pipeline, MM_ERROR_PLAYER_INVALID_STATE);
226
227         if (!pd->total_size) {
228                 LOGW("not ready to get total size\n");
229                 return MM_ERROR_PLAYER_INTERNAL;
230         }
231
232         g_object_get(pd->downloader_sink, "current-bytes", &bytes, NULL);
233
234         LOGD("PD status : %lld / %lld\n", bytes, pd->total_size);
235
236         *current_pos = bytes;
237         *total_size = pd->total_size;
238
239         MMPLAYER_FLEAVE();
240
241         return MM_ERROR_NONE;
242 }
243
244
245 mm_player_pd_t * _mmplayer_create_pd_downloader()
246 {
247         MMPLAYER_FENTER();
248
249         mm_player_pd_t * pd = NULL;
250
251         /* create PD handle */
252         pd = (mm_player_pd_t *) malloc(sizeof(mm_player_pd_t));
253         if (!pd) {
254                 LOGE("Failed to create pd downloader handle...\n");
255                 return FALSE;
256         }
257         memset(pd, 0, sizeof(mm_player_pd_t));
258
259         MMPLAYER_FLEAVE();
260
261         return pd;
262 }
263
264
265 gboolean _mmplayer_destroy_pd_downloader(MMHandleType handle)
266 {
267         MMPLAYER_FENTER();
268
269         mm_player_pd_t * pd = NULL;
270
271         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_INVALID_ARGUMENT);
272
273         pd = MM_PLAYER_GET_PD(handle);
274
275         if (pd && pd->downloader_pipeline)
276                 _mmplayer_unrealize_pd_downloader(handle);
277
278         /* release PD handle */
279         MMPLAYER_FREEIF(pd);
280
281         MMPLAYER_FLEAVE();
282
283         return TRUE;
284 }
285
286
287 gboolean _mmplayer_realize_pd_downloader(MMHandleType handle, gchar *src_uri, gchar *dst_uri, GstElement *pushsrc)
288 {
289         MMPLAYER_FENTER();
290
291         mm_player_pd_t * pd = NULL;
292
293         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_INVALID_ARGUMENT);
294         MMPLAYER_RETURN_VAL_IF_FAIL(src_uri, MM_ERROR_INVALID_ARGUMENT);
295         MMPLAYER_RETURN_VAL_IF_FAIL(dst_uri, MM_ERROR_INVALID_ARGUMENT);
296         MMPLAYER_RETURN_VAL_IF_FAIL(pushsrc, MM_ERROR_INVALID_ARGUMENT);
297
298         pd = MM_PLAYER_GET_PD(handle);
299
300         /* initialize */
301         pd->path_read_from = g_strdup(src_uri);
302         pd->location_to_save = g_strdup(dst_uri);
303         pd->playback_pipeline_src = pushsrc;
304         pd->total_size = 0LL;
305
306         MMPLAYER_FLEAVE();
307
308         return TRUE;
309 }
310
311
312 gboolean _mmplayer_start_pd_downloader(MMHandleType handle)
313 {
314         GstBus* bus = NULL;
315         gboolean bret = FALSE;
316         GstStateChangeReturn sret = GST_STATE_CHANGE_SUCCESS;
317         GstState cur_state;
318         GstState pending_state;
319
320         MMPLAYER_FENTER();
321
322         mm_player_pd_t * pd = NULL;
323
324         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_INVALID_ARGUMENT);
325
326         pd = MM_PLAYER_GET_PD(handle);
327
328         /* pipeline */
329         pd->downloader_pipeline = gst_pipeline_new("PD Downloader");
330         if (NULL == pd->downloader_pipeline) {
331                 LOGE("Can't create PD download pipeline...");
332                 return FALSE;
333         }
334
335         /* source */
336         pd->downloader_src = gst_element_factory_make("souphttpsrc", "PD HTTP download source");
337         if (NULL == pd->downloader_src) {
338                 LOGE("Can't create PD download src...");
339                 return FALSE;
340         }
341
342         /* queue */
343         pd->downloader_queue = gst_element_factory_make("queue", "PD download queue");
344         if (NULL == pd->downloader_queue) {
345                 LOGE("Can't create PD download queue...");
346                 return FALSE;
347         }
348
349         /* filesink */
350         pd->downloader_sink = gst_element_factory_make("filesink", "PD download sink");
351         if (NULL == pd->downloader_sink) {
352                 LOGE("Can't create PD download sink...");
353                 return FALSE;
354         }
355
356         g_object_set(pd->downloader_sink, "sync", FALSE, NULL);
357
358         /* Add to bin and link */
359         gst_bin_add_many(GST_BIN(pd->downloader_pipeline),
360                                         pd->downloader_src, pd->downloader_queue, pd->downloader_sink,
361                                         NULL);
362
363         bret = gst_element_link_many(pd->downloader_src, pd->downloader_queue, pd->downloader_sink, NULL);
364         if (FALSE == bret) {
365                 LOGE("Can't link elements src and sink...");
366                 return FALSE;
367         }
368
369         /* Get Bus and set callback to watch */
370         bus = gst_pipeline_get_bus(GST_PIPELINE(pd->downloader_pipeline));
371         gst_bus_add_watch(bus, __pd_downloader_callback, (gpointer)handle);
372         gst_object_unref(bus);
373
374         /* Set URI on HTTP source */
375         g_object_set(G_OBJECT(pd->downloader_src), "location", pd->path_read_from, NULL);
376
377         /* set file download location on filesink*/
378         g_object_set(G_OBJECT(pd->downloader_sink), "location", pd->location_to_save, NULL);
379
380         SECURE_LOGD("src location = %s, save location = %s\n", pd->path_read_from, pd->location_to_save);
381
382         /* Start to download */
383         sret = gst_element_set_state(pd->downloader_pipeline, GST_STATE_PLAYING);
384         if (GST_STATE_CHANGE_FAILURE == sret) {
385                 LOGE("PD download pipeline failed to go to PLAYING state...");
386                 return FALSE;
387         }
388
389         LOGD("set_state :: sret = %d\n", sret);
390
391         sret = gst_element_get_state(pd->downloader_pipeline, &cur_state, &pending_state, GST_CLOCK_TIME_NONE);
392         if (GST_STATE_CHANGE_FAILURE == sret) {
393                 LOGE("PD download pipeline failed to do get_state...");
394                 return FALSE;
395         }
396
397         LOGD("get-state :: sret = %d\n", sret);
398
399         MMPLAYER_FLEAVE();
400
401         return TRUE;
402 }
403
404
405 gboolean _mmplayer_unrealize_pd_downloader(MMHandleType handle)
406 {
407         MMPLAYER_FENTER();
408
409         mm_player_pd_t * pd = NULL;
410
411         MMPLAYER_RETURN_VAL_IF_FAIL(handle, FALSE);
412
413         pd = MM_PLAYER_GET_PD(handle);
414
415         MMPLAYER_RETURN_VAL_IF_FAIL(pd && pd->downloader_pipeline, FALSE);
416
417         gst_element_set_state(pd->downloader_pipeline, GST_STATE_NULL);
418         gst_element_get_state(pd->downloader_pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
419
420         gst_object_unref(G_OBJECT(pd->downloader_pipeline));
421         pd->downloader_pipeline = NULL;
422
423         /* free */
424         MMPLAYER_FREEIF(pd->path_read_from);
425         MMPLAYER_FREEIF(pd->location_to_save);
426
427         MMPLAYER_FLEAVE();
428
429         return TRUE;
430 }
431
432
433 gint _mm_player_set_pd_downloader_message_cb(MMHandleType handle, MMMessageCallback callback, gpointer user_param)
434 {
435         MMPLAYER_FENTER();
436
437         mm_player_t * player = NULL;
438
439         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_INVALID_ARGUMENT);
440
441         player = MM_PLAYER_CAST((MMHandleType)handle);
442
443         /* PD callback can be set as soon as player handle is created.
444           * So, player handle must have it.
445           */
446         player->pd_msg_cb = callback;
447         player->pd_msg_cb_param = user_param;
448
449         LOGD("msg_cb : %p     msg_cb_param : %p\n", callback, user_param);
450
451         MMPLAYER_FLEAVE();
452
453         return MM_ERROR_NONE;
454 }