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