Turn out remaining gst-1.0 code
[platform/core/multimedia/libmm-player.git] / src / mm_player_streaming.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>, YeJin Cho <cho.yejin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <sys/vfs.h>
23 #include "mm_player_utils.h"
24
25 #include "mm_player_streaming.h"
26
27 static void streaming_set_buffer_size(mm_player_streaming_t* streamer, guint buffer_size);
28 static void streaming_set_buffer_percent(mm_player_streaming_t* streamer, gdouble low_percent, gdouble high_percent);
29 static void streaming_set_buffer_type (mm_player_streaming_t* streamer, gboolean use_file, gchar * file_path, guint64 content_size);
30 static void streaming_set_buffering_time(mm_player_streaming_t* streamer, gdouble buffering_time);
31
32
33 mm_player_streaming_t *
34 __mm_player_streaming_create ()
35 {
36         mm_player_streaming_t *streamer = NULL;
37
38         debug_fenter();
39
40         streamer = (mm_player_streaming_t *) malloc (sizeof (mm_player_streaming_t));
41         if (!streamer)
42         {
43                 debug_error ("fail to create streaming player handle..\n");
44                 return NULL;
45         }
46
47         debug_fleave();
48
49         return streamer;
50 }
51
52 void __mm_player_streaming_initialize (mm_player_streaming_t* streamer)
53 {
54         debug_fenter();
55
56         streamer->buffer = NULL;
57         streamer->buffer_size = DEFAULT_BUFFER_SIZE;
58         streamer->buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT;
59         streamer->buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT;
60         streamer->buffer_avg_bitrate = 0;
61         streamer->buffer_max_bitrate = 0;
62         streamer->need_update = FALSE;
63
64         streamer->is_buffering = FALSE;
65         streamer->buffering_percent = -1;
66         streamer->buffering_time = DEFAULT_BUFFERING_TIME;
67
68         debug_fleave();
69
70         return;
71 }
72
73 void __mm_player_streaming_deinitialize (mm_player_streaming_t* streamer)
74 {
75         debug_fenter();
76
77         return_if_fail(streamer);
78
79         streamer->buffer_size = DEFAULT_BUFFER_SIZE;
80         streamer->buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT;
81         streamer->buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT;
82         streamer->buffer_avg_bitrate = 0;
83         streamer->buffer_max_bitrate = 0;
84         streamer->need_update = FALSE;
85
86         streamer->is_buffering = FALSE;
87         streamer->buffering_percent = -1;
88         streamer->buffering_time = DEFAULT_BUFFERING_TIME;
89
90         debug_fleave();
91
92         return;
93 }
94
95 void __mm_player_streaming_destroy (mm_player_streaming_t* streamer)
96 {
97         debug_fenter();
98
99         if(streamer)
100         {
101                 g_free (streamer);
102                 streamer = NULL;
103         }
104
105         debug_fleave();
106
107         return;
108 }
109
110 void __mm_player_streaming_set_buffer(mm_player_streaming_t* streamer, GstElement * buffer,
111         gboolean use_buffering, guint buffer_size, gdouble low_percent, gdouble high_percent, gdouble buffering_time,
112         gboolean use_file, gchar * file_path, guint64 content_size)
113 {
114         debug_fenter();
115
116         return_if_fail(streamer);
117
118         if (buffer)
119         {
120                 streamer->buffer = buffer;
121
122                 debug_log("buffer element is %s.", GST_ELEMENT_NAME(buffer));
123
124                 g_object_set ( G_OBJECT (streamer->buffer), "use-buffering", use_buffering, NULL );
125         }
126
127         streaming_set_buffer_size(streamer, buffer_size);
128         streaming_set_buffer_percent(streamer, low_percent, high_percent);
129         streaming_set_buffer_type (streamer, use_file, file_path, content_size);
130         streaming_set_buffering_time(streamer, buffering_time);
131
132         debug_fleave();
133
134         return;
135 }
136
137 void __mm_player_streaming_set_content_bitrate(mm_player_streaming_t* streamer, guint max_bitrate, guint avg_bitrate)
138 {
139         debug_fenter();
140
141         return_if_fail(streamer);
142
143        /* Note : Update buffering criterion bytes
144          *      1. maximum bitrate is considered first.
145          *      2. average bitrage * 3 is next.
146          *      3. if there are no updated bitrate, use default buffering limit.
147          */
148         if (max_bitrate > 0 && streamer->buffer_max_bitrate != max_bitrate)
149         {
150               debug_log("set maximum bitrate(%dbps).\n", max_bitrate);
151               streamer->buffer_max_bitrate = max_bitrate;
152
153                 streamer->need_update = TRUE;
154         }
155
156         if (avg_bitrate > 0 && streamer->buffer_avg_bitrate != avg_bitrate)
157         {
158               debug_log("set averate bitrate(%dbps).\n", avg_bitrate);
159               streamer->buffer_avg_bitrate = avg_bitrate;
160
161                 streamer->need_update = TRUE;
162         }
163
164         debug_fleave();
165
166         return;
167 }
168
169 static void
170 streaming_set_buffer_size(mm_player_streaming_t* streamer, guint buffer_size)
171 {
172         debug_fenter();
173
174         return_if_fail(streamer);
175         return_if_fail(buffer_size>0);
176
177         debug_log("set buffer size to %d.", buffer_size);
178
179         streamer->buffer_size = buffer_size;
180
181         if (streamer->buffer)
182                 g_object_set (G_OBJECT(streamer->buffer), "max-size-bytes", buffer_size, NULL);
183
184         debug_fleave();
185
186         return;
187 }
188
189 static void
190 streaming_set_buffer_percent(mm_player_streaming_t* streamer, gdouble low_percent, gdouble high_percent)
191 {
192         gdouble buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT;
193         gdouble buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT;
194
195         debug_fenter();
196
197         return_if_fail(streamer);
198
199         if (low_percent <= MIN_BUFFER_PERCENT || low_percent >= MAX_BUFFER_PERCENT)
200         {
201                 debug_warning("buffer low percent is out of range. use defaut value.");
202                 buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT;
203         }
204         else
205         {
206                 buffer_low_percent = low_percent;
207         }
208
209         if (high_percent  <=  MIN_BUFFER_PERCENT || high_percent  >=  MAX_BUFFER_PERCENT)
210         {
211                 debug_warning("buffer high percent is out of range. use defaut value.");
212                 buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT;
213         }
214         else
215         {
216                 buffer_high_percent = high_percent;
217         }
218
219         if (buffer_high_percent <= buffer_low_percent)
220                 buffer_high_percent =  buffer_low_percent + 1.0;
221
222         debug_log("set buffer percent to %2.3f ~ %2.3f.",  streamer->buffer_low_percent, streamer->buffer_high_percent);
223
224         if (streamer->buffer)
225         {
226                 if ( streamer->buffer_low_percent != buffer_low_percent )
227                         g_object_set (G_OBJECT(streamer->buffer), "low-percent", streamer->buffer_low_percent, NULL);
228
229                 if ( streamer->buffer_high_percent != buffer_high_percent )
230                         g_object_set (G_OBJECT(streamer->buffer), "high-percent", streamer->buffer_high_percent, NULL);
231         }
232
233         streamer->buffer_low_percent = buffer_low_percent;
234         streamer->buffer_high_percent = buffer_high_percent;
235
236         debug_fleave();
237
238         return;
239 }
240
241 static void
242 streaming_set_buffering_time(mm_player_streaming_t* streamer, gdouble buffering_time)
243 {
244         gdouble buffer_buffering_time = DEFAULT_BUFFERING_TIME;
245
246         debug_fenter();
247
248         return_if_fail(streamer);
249
250         if (buffering_time < MIN_BUFFERING_TIME)
251                 buffer_buffering_time = MIN_BUFFERING_TIME;
252         else if (buffering_time > MAX_BUFFERING_TIME)
253                 buffer_buffering_time = MAX_BUFFERING_TIME;
254         else
255                 buffer_buffering_time = buffering_time;
256
257         if (streamer->buffering_time != buffer_buffering_time)
258         {
259                 debug_log("set buffer buffering time from %2.1f to %2.1f.", streamer->buffering_time, buffer_buffering_time);
260
261                 streamer->buffering_time = buffer_buffering_time;
262         }
263
264         debug_fleave();
265
266         return;
267 }
268
269 static void
270 streaming_set_buffer_type (mm_player_streaming_t* streamer, gboolean use_file, gchar * file_path, guint64 content_size)
271 {
272         guint64 storage_available_size = 0L; //bytes
273         guint64 file_buffer_size = 0L;  //bytes
274         gchar file_buffer_name[MAX_FILE_BUFFER_NAME_LEN] = {0};
275         struct statfs buf = {0};
276
277         debug_fenter();
278
279         return_if_fail(streamer && streamer->buffer);
280
281         if (!use_file)
282         {
283                 debug_log("use memory for buffering. streaming is played on push-based. \n"
284                                 "buffering position would not be updated.\n"
285                                 "buffered data would be flushed after played.\n"
286                                 "seeking and getting duration could be failed due to file format.");
287                 return;
288         }
289
290         debug_log("use file for buffering. streaming is played on pull-based. \n");
291
292         if (!file_path || strlen(file_path) <= 0)
293                 file_path = g_strdup(DEFAULT_FILE_BUFFER_PATH);
294
295         g_snprintf(file_buffer_name, MM_MAX_URL_LEN, "%s/XXXXXX", file_path);
296         debug_log("the buffering file name is %s.\n", file_buffer_name);
297
298         if (statfs((const char *)file_path, &buf) < 0)
299         {
300                 debug_warning ("fail to get availabe storage capacity. just use file buffer.\n");
301                 file_buffer_size = 0L;
302         }
303         else
304         {
305                 storage_available_size = (guint64)buf.f_bavail * (guint64)buf.f_bsize; //bytes
306
307                 debug_log ("the number of available blocks : %"G_GUINT64_FORMAT", the block size is %"G_GUINT64_FORMAT".\n",
308                         (guint64)buf.f_bavail, (guint64)buf.f_bsize);
309                 debug_log ("calculated availabe storage size is %"G_GUINT64_FORMAT" Bytes.\n", storage_available_size);
310
311                 if (content_size <= 0 || content_size >= storage_available_size)
312                         file_buffer_size = storage_available_size;
313                 else
314                         file_buffer_size = 0L;
315         }
316
317         if (file_buffer_size>0)
318                 debug_log("use file ring buffer for buffering.");
319
320         g_object_set (G_OBJECT(streamer->buffer), "temp-template", file_buffer_name, NULL);
321         g_object_set (G_OBJECT(streamer->buffer), "file-buffer-max-size", file_buffer_size, NULL);
322
323         debug_fleave();
324
325         return;
326 }
327
328 #define GET_BYTE_FROM_BIT(bit) (bit/8)
329 void __mm_player_streaming_buffering(mm_player_streaming_t* streamer, GstMessage *buffering_msg)
330 {
331         GstBufferingMode mode = GST_BUFFERING_STREAM;
332         gint byte_in_rate = 0;
333         gint byte_out_rate = 0;
334         gint64 buffering_left = -1;
335         gdouble buffering_time = DEFAULT_BUFFERING_TIME;
336         gdouble low_percent = 0.0;
337         gdouble high_percent = 0.0;
338         guint high_percent_byte = 0;
339         gint buffer_percent = 0;
340         guint buffer_criteria = 0;
341
342         return_if_fail ( streamer );
343         return_if_fail ( buffering_msg );
344         return_if_fail ( GST_IS_MESSAGE ( buffering_msg ) );
345         return_if_fail ( GST_MESSAGE_TYPE ( buffering_msg ) == GST_MESSAGE_BUFFERING );
346
347         /* update when buffering has started. */
348         if ( !streamer->is_buffering )
349         {
350                 debug_log ( "buffering has started.\n" );
351
352                 streamer->is_buffering = TRUE;
353                 streamer->buffering_percent = -1;
354                 streamer->need_update = TRUE;
355         }
356
357         /* update buffer percent */
358         gst_message_parse_buffering ( buffering_msg, &buffer_percent );
359
360         if ( streamer->buffering_percent < buffer_percent )
361         {
362                 debug_log ( "buffering %d%%....\n", buffer_percent );
363                 streamer->buffering_percent = buffer_percent;
364         }
365
366         if ( streamer->buffering_percent == MAX_BUFFER_PERCENT )
367         {
368                 debug_log ( "buffering had done.\n" );
369                 streamer->is_buffering = FALSE;
370         }
371
372         if (!streamer->need_update)
373         {
374                 debug_log ( "don't need to update buffering stats during buffering.\n" );
375                 return;
376         }
377
378         /* Note : Parse the buffering message to get the in/out throughput.
379          *     avg_in is the network throughput and avg_out is the consumed throughtput by the linkded element.
380          */
381         gst_message_parse_buffering_stats ( buffering_msg, &mode, &byte_in_rate, &byte_out_rate, &buffering_left );
382
383         if (streamer->buffer_max_bitrate > 0)
384         {
385                 buffer_criteria = GET_BYTE_FROM_BIT(streamer->buffer_max_bitrate);
386                 byte_out_rate = GET_BYTE_FROM_BIT(streamer->buffer_max_bitrate /3);
387         }
388         else if (streamer->buffer_avg_bitrate > 0)
389         {
390                 buffer_criteria = GET_BYTE_FROM_BIT(streamer->buffer_avg_bitrate * 3);
391                 byte_out_rate = GET_BYTE_FROM_BIT(streamer->buffer_avg_bitrate);
392         }
393
394         debug_log ( "in rate is %d, out rate is %d (bytes/sec).\n", byte_in_rate, byte_out_rate );
395
396         if ( byte_in_rate > 0  &&  byte_out_rate > 0)
397                 buffering_time =  byte_out_rate / byte_in_rate;
398         else if (byte_in_rate <= 0 && byte_out_rate > 0)
399                 buffering_time = MAX_BUFFERING_TIME;
400         else
401                 buffering_time = DEFAULT_BUFFERING_TIME;
402
403         streaming_set_buffering_time(streamer, buffering_time);
404
405         /* calculate buffer low/high percent */
406         low_percent = DEFAULT_BUFFER_LOW_PERCENT;
407
408         if ( buffer_criteria > 0 )
409         {
410                 high_percent_byte = buffer_criteria * streamer->buffering_time;
411                 high_percent = ( (gdouble)high_percent_byte * 100.0 )  / (gdouble)streamer->buffer_size;
412         }
413         else
414         {
415                 high_percent_byte = streamer->buffer_high_percent * streamer->buffer_size / 100;
416                 high_percent= streamer->buffer_high_percent;
417         }
418
419         if ( streamer->buffer_size < high_percent_byte )
420         {
421                 debug_log ( "buffer size[%d bytes] is smaller than high threshold[%d bytes]. update it. \n",
422                         streamer->buffer_size, high_percent_byte );
423
424                 streaming_set_buffer_size(streamer, high_percent_byte * 1.1);
425         }
426
427         streaming_set_buffer_percent(streamer, low_percent, high_percent);
428
429         streamer->need_update = FALSE;
430
431         return;
432 }
433