Merge "[Cherry-pick][Text Autosizing] prevent oscillation of font sizes during autosi...
[framework/web/webkit-efl.git] / Source / WebCore / platform / graphics / gstreamer / MediaPlayerPrivateGStreamer.cpp
1 /*
2  * Copyright (C) 2007, 2009 Apple Inc.  All rights reserved.
3  * Copyright (C) 2007 Collabora Ltd.  All rights reserved.
4  * Copyright (C) 2007 Alp Toker <alp@atoker.com>
5  * Copyright (C) 2009 Gustavo Noronha Silva <gns@gnome.org>
6  * Copyright (C) 2009, 2010 Igalia S.L
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * aint with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 #include "config.h"
25 #include "MediaPlayerPrivateGStreamer.h"
26
27 #if ENABLE(VIDEO) && USE(GSTREAMER)
28
29 #include "ColorSpace.h"
30 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
31 #include "CookieJar.h"
32 #include <power.h>
33 #endif
34 #include "Document.h"
35 #include "Frame.h"
36 #include "FrameView.h"
37 #include "GStreamerGWorld.h"
38 #include "GStreamerUtilities.h"
39 #include "GStreamerVersioning.h"
40 #include "GraphicsContext.h"
41 #include "GraphicsTypes.h"
42 #if ENABLE(TIZEN_MEDIA_STREAM)
43 #include "HTMLMediaElement.h"
44 #endif
45 #include "ImageGStreamer.h"
46 #include "ImageOrientation.h"
47 #include "IntRect.h"
48 #include "KURL.h"
49 #include "MIMETypeRegistry.h"
50 #include "MediaPlayer.h"
51 #include "NotImplemented.h"
52 #include "SecurityOrigin.h"
53 #include "TimeRanges.h"
54 #include "VideoSinkGStreamer.h"
55 #include "WebKitWebSourceGStreamer.h"
56 #include <gst/gst.h>
57 #include <gst/video/video.h>
58 #include <limits>
59 #include <math.h>
60 #include <wtf/gobject/GOwnPtr.h>
61 #include <wtf/text/CString.h>
62
63 #ifdef GST_API_VERSION_1
64 #include <gst/audio/streamvolume.h>
65 #else
66 #include <gst/interfaces/streamvolume.h>
67 #endif
68
69 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER)
70 #include "Page.h"
71 #include "Settings.h"
72 #include "VideoLayerTizen.h"
73 #endif // ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER)
74
75 #if ENABLE(TIZEN_MEDIA_STREAM) || ENABLE(TIZEN_FILE_SYSTEM)
76 #include "URIUtils.h"
77 #endif // ENABLE(TIZEN_MEDIA_STREAM) || ENABLE(TIZEN_FILE_SYSTEM)
78
79 #if ENABLE(TIZEN_MEDIA_STREAM)
80 #include "WebKitCameraSourceGStreamerTizen.h"
81 #endif // ENABLE(TIZEN_MEDIA_STREAM)
82
83 // GstPlayFlags flags from playbin2. It is the policy of GStreamer to
84 // not publicly expose element-specific enums. That's why this
85 // GstPlayFlags enum has been copied here.
86 typedef enum {
87     GST_PLAY_FLAG_VIDEO         = 0x00000001,
88     GST_PLAY_FLAG_AUDIO         = 0x00000002,
89     GST_PLAY_FLAG_TEXT          = 0x00000004,
90     GST_PLAY_FLAG_VIS           = 0x00000008,
91     GST_PLAY_FLAG_SOFT_VOLUME   = 0x00000010,
92     GST_PLAY_FLAG_NATIVE_AUDIO  = 0x00000020,
93     GST_PLAY_FLAG_NATIVE_VIDEO  = 0x00000040,
94     GST_PLAY_FLAG_DOWNLOAD      = 0x00000080,
95     GST_PLAY_FLAG_BUFFERING     = 0x000000100
96 } GstPlayFlags;
97
98 #ifdef GST_API_VERSION_1
99 static const char* gPlaybinName = "playbin";
100 #else
101 static const char* gPlaybinName = "playbin2";
102 #endif
103
104 GST_DEBUG_CATEGORY_STATIC(webkit_media_player_debug);
105 #define GST_CAT_DEFAULT webkit_media_player_debug
106
107 using namespace std;
108
109 namespace WebCore {
110
111 static int greatestCommonDivisor(int a, int b)
112 {
113     while (b) {
114         int temp = a;
115         a = b;
116         b = temp % b;
117     }
118
119     return ABS(a);
120 }
121
122 static gboolean mediaPlayerPrivateMessageCallback(GstBus*, GstMessage* message, MediaPlayerPrivateGStreamer* player)
123 {
124     return player->handleMessage(message);
125 }
126
127 static void mediaPlayerPrivateSourceChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
128 {
129     player->sourceChanged();
130 }
131
132 static void mediaPlayerPrivateVolumeChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
133 {
134     // This is called when playbin receives the notify::volume signal.
135     player->volumeChanged();
136 }
137
138 static gboolean mediaPlayerPrivateVolumeChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
139 {
140     // This is the callback of the timeout source created in ::volumeChanged.
141     player->notifyPlayerOfVolumeChange();
142     return FALSE;
143 }
144
145 static void mediaPlayerPrivateMuteChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
146 {
147     // This is called when playbin receives the notify::mute signal.
148     player->muteChanged();
149 }
150
151 static gboolean mediaPlayerPrivateMuteChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
152 {
153     // This is the callback of the timeout source created in ::muteChanged.
154     player->notifyPlayerOfMute();
155     return FALSE;
156 }
157
158 static void mediaPlayerPrivateVideoSinkCapsChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
159 {
160     player->videoChanged();
161 }
162
163 static void mediaPlayerPrivateVideoChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player)
164 {
165     player->videoChanged();
166 }
167
168 static void mediaPlayerPrivateAudioChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player)
169 {
170     player->audioChanged();
171 }
172
173 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
174 static void mediaPlayerPrivateSourceSetupCallback(GObject*, GstElement* source, MediaPlayerPrivateGStreamer* player)
175 {
176     HTMLMediaElement* element = static_cast<HTMLMediaElement*>(player->player()->mediaPlayerClient());
177
178     // Grab the current document
179     Document* document = element->document();
180     if (!document)
181         document = element->ownerDocument();
182
183     // Grab the frame and network manager
184     Frame* frame = document ? document->frame() : 0;
185     FrameLoader* frameLoader = frame ? frame->loader() : 0;
186
187     String cookie = cookies(document, player->url());
188     if (!cookie.length())
189         cookie = cookieRequestHeaderFieldValue(document, player->url());
190
191     GstStructure* headers = gst_structure_new("extra-headers", "Cookie", G_TYPE_STRING, cookie.utf8().data(), NULL);
192     g_object_set(source, "extra-headers", headers, NULL);
193     gst_structure_free(headers);
194
195 #if ENABLE(TIZEN_WEBKIT2_PROXY)
196     player->setProxy(source);
197 #endif
198
199     if (frameLoader)
200         g_object_set(source, "user-agent", frameLoader->userAgent(player->url()).utf8().data(), NULL);
201 }
202 #endif
203
204 static gboolean mediaPlayerPrivateAudioChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
205 {
206     // This is the callback of the timeout source created in ::audioChanged.
207     player->notifyPlayerOfAudio();
208     return FALSE;
209 }
210
211 static gboolean mediaPlayerPrivateVideoChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
212 {
213     // This is the callback of the timeout source created in ::videoChanged.
214     player->notifyPlayerOfVideo();
215     return FALSE;
216 }
217
218 #if ENABLE(TIZEN_GSTREAMER_VIDEO) && (!ENABLE(TIZEN_ACCELERATED_COMPOSITING) || !USE(TIZEN_TEXTURE_MAPPER) || !ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE) || CPU(X86) || CPU(X86_64))
219 static void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivateGStreamer* playerPrivate)
220 {
221     playerPrivate->triggerRepaint(buffer);
222 }
223 #endif
224
225 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER) && ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
226 static GstBusSyncReply mediaPlayerPrivateSyncHandler(GstBus* bus, GstMessage* message, MediaPlayerPrivateGStreamer* playerPrivate)
227 {
228     // ignore anything but 'prepare-xid' message
229     if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_ELEMENT)
230         return GST_BUS_PASS;
231     if (!gst_structure_has_name (message->structure, "prepare-xid"))
232         return GST_BUS_PASS;
233
234     playerPrivate->xWindowIdPrepared(message);
235     return GST_BUS_DROP;
236 }
237 #endif
238
239 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
240 static ASM_cb_result_t MediaPlayerAudioSessionEventSourcePause(ASM_event_sources_t eventSource, void* callbackData)
241 {
242     MediaPlayer* player = static_cast<MediaPlayer*>(callbackData);
243     if (!player)
244         return ASM_CB_RES_IGNORE;
245
246     switch (eventSource) {
247     case ASM_EVENT_SOURCE_CALL_START:
248     case ASM_EVENT_SOURCE_ALARM_START:
249     case ASM_EVENT_SOURCE_EARJACK_UNPLUG:
250     case ASM_EVENT_SOURCE_MEDIA:
251     case ASM_EVENT_SOURCE_EMERGENCY_START:
252     case ASM_EVENT_SOURCE_OTHER_PLAYER_APP:
253     case ASM_EVENT_SOURCE_RESOURCE_CONFLICT:
254         if (player->hasAudio())
255             player->pause();
256         return ASM_CB_RES_PAUSE;
257     default:
258         return ASM_CB_RES_NONE;
259     }
260 }
261
262 static ASM_cb_result_t MediaPlayerAudioSessionEventSourcePlay(ASM_event_sources_t eventSource, void* callbackData)
263 {
264     MediaPlayer* player = static_cast<MediaPlayer*>(callbackData);
265     if (!player)
266         return ASM_CB_RES_IGNORE;
267
268     switch (eventSource) {
269     case ASM_EVENT_SOURCE_ALARM_END:
270         if (!player->hasVideo()) {
271             player->play();
272             return ASM_CB_RES_PLAYING;
273         }
274         return ASM_CB_RES_NONE;
275     default:
276         return ASM_CB_RES_NONE;
277     }
278 }
279
280 static ASM_cb_result_t mediaPlayerPrivateAudioSessionNotifyCallback(int, ASM_event_sources_t eventSource, ASM_sound_commands_t command, unsigned int, void* callbackData)
281 {
282     if (command == ASM_COMMAND_STOP || command == ASM_COMMAND_PAUSE)
283         return MediaPlayerAudioSessionEventSourcePause(eventSource, callbackData);
284     if (command == ASM_COMMAND_PLAY || command == ASM_COMMAND_RESUME)
285         return MediaPlayerAudioSessionEventSourcePlay(eventSource, callbackData);
286
287     return ASM_CB_RES_NONE;
288 }
289 #endif
290
291 PassOwnPtr<MediaPlayerPrivateInterface> MediaPlayerPrivateGStreamer::create(MediaPlayer* player)
292 {
293     return adoptPtr(new MediaPlayerPrivateGStreamer(player));
294 }
295
296 void MediaPlayerPrivateGStreamer::registerMediaEngine(MediaEngineRegistrar registrar)
297 {
298     if (isAvailable())
299         registrar(create, getSupportedTypes, supportsType, 0, 0, 0);
300 }
301
302 bool initializeGStreamerAndRegisterWebKitElements()
303 {
304     if (!initializeGStreamer())
305         return false;
306
307     GRefPtr<GstElementFactory> srcFactory = gst_element_factory_find("webkitwebsrc");
308     if (!srcFactory)
309 #if ENABLE(TIZEN_MEDIA_STREAM)
310         return gst_element_register(0, "webkitcamerasrc", GST_RANK_PRIMARY + 200, WEBKIT_TYPE_CAMERA_SRC);
311 #else
312         GST_DEBUG_CATEGORY_INIT(webkit_media_player_debug, "webkitmediaplayer", 0, "WebKit media player");
313         return gst_element_register(0, "webkitwebsrc", GST_RANK_PRIMARY + 100, WEBKIT_TYPE_WEB_SRC);
314 #endif // ENABLE(TIZEN_MEDIA_STREAM)
315
316     return true;
317 }
318
319 bool MediaPlayerPrivateGStreamer::isAvailable()
320 {
321     if (!initializeGStreamerAndRegisterWebKitElements())
322         return false;
323
324     GRefPtr<GstElementFactory> factory = gst_element_factory_find(gPlaybinName);
325     return factory;
326 }
327
328 MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer(MediaPlayer* player)
329     : m_player(player)
330     , m_webkitVideoSink(0)
331 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
332     , m_videoSinkBin(0)
333 #endif
334     , m_fpsSink(0)
335     , m_source(0)
336     , m_seekTime(0)
337     , m_changingRate(false)
338     , m_endTime(numeric_limits<float>::infinity())
339     , m_isEndReached(false)
340     , m_networkState(MediaPlayer::Empty)
341     , m_readyState(MediaPlayer::HaveNothing)
342     , m_isStreaming(false)
343     , m_size(IntSize())
344     , m_buffer(0)
345     , m_mediaLocations(0)
346     , m_mediaLocationCurrentIndex(0)
347     , m_resetPipeline(false)
348     , m_paused(true)
349     , m_seeking(false)
350     , m_buffering(false)
351     , m_playbackRate(1)
352     , m_errorOccured(false)
353     , m_mediaDuration(0)
354     , m_startedBuffering(false)
355     , m_fillTimer(this, &MediaPlayerPrivateGStreamer::fillTimerFired)
356     , m_maxTimeLoaded(0)
357     , m_bufferingPercentage(0)
358     , m_preload(MediaPlayer::Auto)
359     , m_delayingLoad(false)
360     , m_mediaDurationKnown(true)
361     , m_maxTimeLoadedAtLastDidLoadingProgress(0)
362     , m_volumeTimerHandler(0)
363     , m_muteTimerHandler(0)
364     , m_hasVideo(false)
365     , m_hasAudio(false)
366     , m_audioTimerHandler(0)
367     , m_videoTimerHandler(0)
368     , m_webkitAudioSink(0)
369     , m_totalBytes(-1)
370 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER)
371     , m_videoLayer(VideoLayerTizen::create(static_cast<HTMLMediaElement*>(player->mediaPlayerClient())))
372 #endif // ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER)
373 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
374     , m_audioSessionManager(AudioSessionManagerGStreamerTizen::createAudioSessionManager())
375 #endif
376     , m_originalPreloadWasAutoAndWasOverridden(false)
377     , m_preservesPitch(false)
378 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
379     , m_suspendTime(0)
380 #endif
381 {
382 }
383
384 MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer()
385 {
386     if (m_fillTimer.isActive())
387         m_fillTimer.stop();
388
389     if (m_buffer)
390         gst_buffer_unref(m_buffer);
391     m_buffer = 0;
392
393     if (m_mediaLocations) {
394         gst_structure_free(m_mediaLocations);
395         m_mediaLocations = 0;
396     }
397
398 #ifndef GST_API_VERSION_1
399     if (m_videoSinkBin) {
400         gst_object_unref(m_videoSinkBin);
401         m_videoSinkBin = 0;
402     }
403 #endif
404
405     if (m_playBin) {
406         GRefPtr<GstBus> bus = webkitGstPipelineGetBus(GST_PIPELINE(m_playBin.get()));
407         ASSERT(bus);
408         g_signal_handlers_disconnect_by_func(bus.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateMessageCallback), this);
409         gst_bus_remove_signal_watch(bus.get());
410
411         gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
412         m_playBin = 0;
413     }
414
415 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
416     if (m_audioSessionManager)
417         m_audioSessionManager->setSoundState(ASM_STATE_STOP);
418 #endif
419
420     m_player = 0;
421
422     if (m_muteTimerHandler)
423         g_source_remove(m_muteTimerHandler);
424
425     if (m_volumeTimerHandler)
426         g_source_remove(m_volumeTimerHandler);
427
428     if (m_videoTimerHandler)
429         g_source_remove(m_videoTimerHandler);
430
431     if (m_audioTimerHandler)
432         g_source_remove(m_audioTimerHandler);
433 }
434
435 void MediaPlayerPrivateGStreamer::load(const String& url)
436 {
437     if (!initializeGStreamerAndRegisterWebKitElements())
438         return;
439
440 #if ENABLE(TIZEN_MEDIA_STREAM) || ENABLE(TIZEN_FILE_SYSTEM)
441     crackURI(url);
442 #endif // ENABLE(TIZEN_MEDIA_STREAM) || ENABLE(TIZEN_FILE_SYSTEM)
443     KURL kurl(KURL(), url);
444     String cleanUrl(url);
445
446     // Clean out everything after file:// url path.
447     if (kurl.isLocalFile())
448         cleanUrl = cleanUrl.substring(0, kurl.pathEnd());
449
450     if (!m_playBin) {
451         createGSTPlayBin();
452         setDownloadBuffering();
453     }
454
455     ASSERT(m_playBin);
456
457     m_url = KURL(KURL(), cleanUrl);
458     g_object_set(m_playBin.get(), "uri", cleanUrl.utf8().data(), NULL);
459
460     LOG_MEDIA_MESSAGE("Load %s", cleanUrl.utf8().data());
461
462     if (m_preload == MediaPlayer::None) {
463         LOG_MEDIA_MESSAGE("Delaying load.");
464         m_delayingLoad = true;
465     }
466
467     // Reset network and ready states. Those will be set properly once
468     // the pipeline pre-rolled.
469 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
470     if (!m_delayingLoad)
471         m_networkState = MediaPlayer::Loading;
472     else
473         m_networkState = MediaPlayer::Idle;
474 #else
475     m_networkState = MediaPlayer::Loading;
476 #endif
477     m_player->networkStateChanged();
478     m_readyState = MediaPlayer::HaveNothing;
479     m_player->readyStateChanged();
480     m_volumeAndMuteInitialized = false;
481
482     // GStreamer needs to have the pipeline set to a paused state to
483     // start providing anything useful.
484 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
485     if (!m_delayingLoad)
486 #endif
487     gst_element_set_state(m_playBin.get(), GST_STATE_PAUSED);
488
489 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
490     if (m_audioSessionManager && !m_delayingLoad)
491         m_audioSessionManager->setSoundState(ASM_STATE_PAUSE);
492 #endif
493
494     if (!m_delayingLoad)
495         commitLoad();
496 }
497
498 void MediaPlayerPrivateGStreamer::commitLoad()
499 {
500     ASSERT(!m_delayingLoad);
501     LOG_MEDIA_MESSAGE("Committing load.");
502     updateStates();
503 }
504
505 float MediaPlayerPrivateGStreamer::playbackPosition() const
506 {
507     if (m_isEndReached) {
508         // Position queries on a null pipeline return 0. If we're at
509         // the end of the stream the pipeline is null but we want to
510         // report either the seek time or the duration because this is
511         // what the Media element spec expects us to do.
512         if (m_seeking)
513             return m_seekTime;
514         if (m_mediaDuration)
515             return m_mediaDuration;
516     }
517
518     float ret = 0.0f;
519
520     GstQuery* query = gst_query_new_position(GST_FORMAT_TIME);
521     if (!gst_element_query(m_playBin.get(), query)) {
522         LOG_MEDIA_MESSAGE("Position query failed...");
523         gst_query_unref(query);
524         return ret;
525     }
526
527     gint64 position;
528     gst_query_parse_position(query, 0, &position);
529
530     // Position is available only if the pipeline is not in GST_STATE_NULL or
531     // GST_STATE_READY state.
532     if (position != static_cast<gint64>(GST_CLOCK_TIME_NONE))
533         ret = static_cast<double>(position) / GST_SECOND;
534
535     LOG_MEDIA_MESSAGE("Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position));
536
537     gst_query_unref(query);
538
539     return ret;
540 }
541
542 bool MediaPlayerPrivateGStreamer::changePipelineState(GstState newState)
543 {
544     ASSERT(newState == GST_STATE_PLAYING || newState == GST_STATE_PAUSED);
545
546     GstState currentState;
547     GstState pending;
548
549     gst_element_get_state(m_playBin.get(), &currentState, &pending, 0);
550     LOG_MEDIA_MESSAGE("Current state: %s, pending: %s", gst_element_state_get_name(currentState), gst_element_state_get_name(pending));
551 #if ENABLE(TIZEN_DLOG_SUPPORT)
552     TIZEN_LOGI("Current state: %s, New state: %s", gst_element_state_get_name(currentState), gst_element_state_get_name(newState));
553 #endif
554     if (currentState == newState || pending == newState)
555         return true;
556
557     GstStateChangeReturn setStateResult = gst_element_set_state(m_playBin.get(), newState);
558     GstState pausedOrPlaying = newState == GST_STATE_PLAYING ? GST_STATE_PAUSED : GST_STATE_PLAYING;
559     if (currentState != pausedOrPlaying && setStateResult == GST_STATE_CHANGE_FAILURE) {
560         loadingFailed(MediaPlayer::Empty);
561         return false;
562     }
563     return true;
564 }
565
566 void MediaPlayerPrivateGStreamer::prepareToPlay()
567 {
568     m_isEndReached = false;
569     m_seeking = false;
570
571     if (m_delayingLoad) {
572         m_delayingLoad = false;
573         commitLoad();
574     }
575 }
576
577 void MediaPlayerPrivateGStreamer::play()
578 {
579 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
580     if (m_audioSessionManager && !m_audioSessionManager->setSoundState(ASM_STATE_PLAYING))
581         return;
582 #endif
583     if (changePipelineState(GST_STATE_PLAYING)) {
584         m_isEndReached = false;
585         LOG_MEDIA_MESSAGE("Play");
586     }
587 }
588
589 void MediaPlayerPrivateGStreamer::pause()
590 {
591 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
592     if (m_audioSessionManager && !m_audioSessionManager->setSoundState(ASM_STATE_PAUSE))
593         return;
594 #endif
595     if (m_isEndReached)
596         return;
597
598     if (changePipelineState(GST_STATE_PAUSED))
599         LOG_MEDIA_MESSAGE("Pause");
600 }
601
602 float MediaPlayerPrivateGStreamer::duration() const
603 {
604     if (!m_playBin)
605         return 0.0f;
606
607     if (m_errorOccured)
608         return 0.0f;
609
610     // Media duration query failed already, don't attempt new useless queries.
611     if (!m_mediaDurationKnown)
612         return numeric_limits<float>::infinity();
613
614     if (m_mediaDuration)
615         return m_mediaDuration;
616
617     GstFormat timeFormat = GST_FORMAT_TIME;
618     gint64 timeLength = 0;
619
620 #ifdef GST_API_VERSION_1
621     bool failure = !gst_element_query_duration(m_playBin.get(), timeFormat, &timeLength) || static_cast<guint64>(timeLength) == GST_CLOCK_TIME_NONE;
622 #else
623     bool failure = !gst_element_query_duration(m_playBin.get(), &timeFormat, &timeLength) || timeFormat != GST_FORMAT_TIME || static_cast<guint64>(timeLength) == GST_CLOCK_TIME_NONE;
624 #endif
625     if (failure) {
626         LOG_MEDIA_MESSAGE("Time duration query failed for %s", m_url.string().utf8().data());
627         return numeric_limits<float>::infinity();
628     }
629
630     LOG_MEDIA_MESSAGE("Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(timeLength));
631
632     return static_cast<double>(timeLength) / GST_SECOND;
633     // FIXME: handle 3.14.9.5 properly
634 }
635
636 float MediaPlayerPrivateGStreamer::currentTime() const
637 {
638     if (!m_playBin)
639         return 0.0f;
640
641     if (m_errorOccured)
642         return 0.0f;
643
644     if (m_seeking)
645         return m_seekTime;
646
647     // Workaround for
648     // https://bugzilla.gnome.org/show_bug.cgi?id=639941 In GStreamer
649     // 0.10.35 basesink reports wrong duration in case of EOS and
650     // negative playback rate. There's no upstream accepted patch for
651     // this bug yet, hence this temporary workaround.
652     if (m_isEndReached && m_playbackRate < 0)
653         return 0.0f;
654
655     return playbackPosition();
656
657 }
658
659 void MediaPlayerPrivateGStreamer::seek(float time)
660 {
661     if (!m_playBin)
662         return;
663
664     if (m_errorOccured)
665         return;
666
667     LOG_MEDIA_MESSAGE("Seek attempt to %f secs", time);
668 #if ENABLE(TIZEN_DLOG_SUPPORT)
669     TIZEN_LOGI("Seek attempt to %f secs", time);
670 #endif
671
672     // Avoid useless seeking.
673     if (time == currentTime())
674         return;
675
676     // Extract the integer part of the time (seconds) and the
677     // fractional part (microseconds). Attempt to round the
678     // microseconds so no floating point precision is lost and we can
679     // perform an accurate seek.
680     float seconds;
681     float microSeconds = modf(time, &seconds) * 1000000;
682     GTimeVal timeValue;
683     timeValue.tv_sec = static_cast<glong>(seconds);
684     timeValue.tv_usec = static_cast<glong>(roundf(microSeconds / 10000) * 10000);
685
686     GstClockTime clockTime = GST_TIMEVAL_TO_TIME(timeValue);
687     LOG_MEDIA_MESSAGE("Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(clockTime));
688
689     if (!gst_element_seek(m_playBin.get(), m_player->rate(),
690             GST_FORMAT_TIME,
691             (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
692             GST_SEEK_TYPE_SET, clockTime,
693             GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
694         LOG_MEDIA_MESSAGE("Seek to %f failed", time);
695 #if ENABLE(TIZEN_DLOG_SUPPORT)
696         TIZEN_LOGE("Seek to %f failed", time);
697 #endif
698     } else {
699         m_seeking = true;
700         m_seekTime = time;
701     }
702 }
703
704 bool MediaPlayerPrivateGStreamer::paused() const
705 {
706     if (m_isEndReached) {
707         LOG_MEDIA_MESSAGE("Ignoring pause at EOS");
708         return true;
709     }
710
711     GstState state;
712     gst_element_get_state(m_playBin.get(), &state, 0, 0);
713     return state == GST_STATE_PAUSED;
714 }
715
716 bool MediaPlayerPrivateGStreamer::seeking() const
717 {
718     return m_seeking;
719 }
720
721 // Returns the size of the video
722 IntSize MediaPlayerPrivateGStreamer::naturalSize() const
723 {
724     if (!hasVideo())
725         return IntSize();
726
727     if (!m_videoSize.isEmpty())
728         return m_videoSize;
729
730     GRefPtr<GstCaps> caps = webkitGstGetPadCaps(m_videoSinkPad.get());
731     if (!caps)
732         return IntSize();
733
734
735     // TODO: handle possible clean aperture data. See
736     // https://bugzilla.gnome.org/show_bug.cgi?id=596571
737     // TODO: handle possible transformation matrix. See
738     // https://bugzilla.gnome.org/show_bug.cgi?id=596326
739
740     // Get the video PAR and original size, if this fails the
741     // video-sink has likely not yet negotiated its caps.
742     int pixelAspectRatioNumerator, pixelAspectRatioDenominator, stride;
743     IntSize originalSize;
744     GstVideoFormat format;
745     if (!getVideoSizeAndFormatFromCaps(caps.get(), originalSize, format, pixelAspectRatioNumerator, pixelAspectRatioDenominator, stride))
746         return IntSize();
747
748     LOG_MEDIA_MESSAGE("Original video size: %dx%d", originalSize.width(), originalSize.height());
749     LOG_MEDIA_MESSAGE("Pixel aspect ratio: %d/%d", pixelAspectRatioNumerator, pixelAspectRatioDenominator);
750
751     // Calculate DAR based on PAR and video size.
752     int displayWidth = originalSize.width() * pixelAspectRatioNumerator;
753     int displayHeight = originalSize.height() * pixelAspectRatioDenominator;
754
755     // Divide display width and height by their GCD to avoid possible overflows.
756     int displayAspectRatioGCD = greatestCommonDivisor(displayWidth, displayHeight);
757     displayWidth /= displayAspectRatioGCD;
758     displayHeight /= displayAspectRatioGCD;
759
760     // Apply DAR to original video size. This is the same behavior as in xvimagesink's setcaps function.
761     guint64 width = 0, height = 0;
762     if (!(originalSize.height() % displayHeight)) {
763         LOG_MEDIA_MESSAGE("Keeping video original height");
764         width = gst_util_uint64_scale_int(originalSize.height(), displayWidth, displayHeight);
765         height = static_cast<guint64>(originalSize.height());
766     } else if (!(originalSize.width() % displayWidth)) {
767         LOG_MEDIA_MESSAGE("Keeping video original width");
768         height = gst_util_uint64_scale_int(originalSize.width(), displayHeight, displayWidth);
769         width = static_cast<guint64>(originalSize.width());
770     } else {
771         LOG_MEDIA_MESSAGE("Approximating while keeping original video height");
772         width = gst_util_uint64_scale_int(originalSize.height(), displayWidth, displayHeight);
773         height = static_cast<guint64>(originalSize.height());
774     }
775
776     LOG_MEDIA_MESSAGE("Natural size: %" G_GUINT64_FORMAT "x%" G_GUINT64_FORMAT, width, height);
777     m_videoSize = IntSize(static_cast<int>(width), static_cast<int>(height));
778     return m_videoSize;
779 }
780
781 void MediaPlayerPrivateGStreamer::videoChanged()
782 {
783     if (m_videoTimerHandler)
784         g_source_remove(m_videoTimerHandler);
785     m_videoTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVideoChangeTimeoutCallback), this);
786 }
787
788 void MediaPlayerPrivateGStreamer::notifyPlayerOfVideo()
789 {
790     m_videoTimerHandler = 0;
791
792     gint videoTracks = 0;
793     if (m_playBin)
794         g_object_get(m_playBin.get(), "n-video", &videoTracks, NULL);
795
796     m_hasVideo = videoTracks > 0;
797
798 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER) && ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
799     int width;
800     int height;
801     if (gst_video_get_size(m_videoSinkPad.get(), &width, &height)) {
802         IntSize size(width, height);
803         if (m_videoSize != size) {
804             m_videoSize = IntSize();
805             m_videoLayer->setOverlay(naturalSize());
806         }
807     }
808 #endif
809     m_videoSize = IntSize();
810
811     m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player);
812 }
813
814 void MediaPlayerPrivateGStreamer::audioChanged()
815 {
816     if (m_audioTimerHandler)
817         g_source_remove(m_audioTimerHandler);
818     m_audioTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateAudioChangeTimeoutCallback), this);
819 }
820
821 void MediaPlayerPrivateGStreamer::notifyPlayerOfAudio()
822 {
823     m_audioTimerHandler = 0;
824
825     gint audioTracks = 0;
826     if (m_playBin)
827         g_object_get(m_playBin.get(), "n-audio", &audioTracks, NULL);
828     m_hasAudio = audioTracks > 0;
829     m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player);
830 }
831
832 void MediaPlayerPrivateGStreamer::setVolume(float volume)
833 {
834     if (!m_playBin)
835         return;
836
837     gst_stream_volume_set_volume(GST_STREAM_VOLUME(m_playBin.get()), GST_STREAM_VOLUME_FORMAT_CUBIC,
838                                  static_cast<double>(volume));
839 }
840
841 void MediaPlayerPrivateGStreamer::notifyPlayerOfVolumeChange()
842 {
843     m_volumeTimerHandler = 0;
844
845     if (!m_player || !m_playBin)
846         return;
847     double volume;
848     volume = gst_stream_volume_get_volume(GST_STREAM_VOLUME(m_playBin.get()), GST_STREAM_VOLUME_FORMAT_CUBIC);
849     // get_volume() can return values superior to 1.0 if the user
850     // applies software user gain via third party application (GNOME
851     // volume control for instance).
852     volume = CLAMP(volume, 0.0, 1.0);
853     m_player->volumeChanged(static_cast<float>(volume));
854 }
855
856 void MediaPlayerPrivateGStreamer::volumeChanged()
857 {
858     if (m_volumeTimerHandler)
859         g_source_remove(m_volumeTimerHandler);
860     m_volumeTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVolumeChangeTimeoutCallback), this);
861 }
862
863 void MediaPlayerPrivateGStreamer::setRate(float rate)
864 {
865     // Avoid useless playback rate update.
866     if (m_playbackRate == rate)
867         return;
868
869     GstState state;
870     GstState pending;
871
872     gst_element_get_state(m_playBin.get(), &state, &pending, 0);
873     if ((state != GST_STATE_PLAYING && state != GST_STATE_PAUSED)
874         || (pending == GST_STATE_PAUSED))
875         return;
876
877     if (isLiveStream())
878         return;
879
880     m_playbackRate = rate;
881     m_changingRate = true;
882
883     if (!rate) {
884         gst_element_set_state(m_playBin.get(), GST_STATE_PAUSED);
885 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
886         if (m_audioSessionManager)
887             m_audioSessionManager->setSoundState(ASM_STATE_PAUSE);
888 #endif
889         return;
890     }
891
892     float currentPosition = static_cast<float>(playbackPosition() * GST_SECOND);
893     GstSeekFlags flags = (GstSeekFlags)(GST_SEEK_FLAG_FLUSH);
894     gint64 start, end;
895     bool mute = false;
896
897     LOG_MEDIA_MESSAGE("Set Rate to %f", rate);
898     if (rate > 0) {
899         // Mute the sound if the playback rate is too extreme and
900         // audio pitch is not adjusted.
901         mute = (!m_preservesPitch && (rate < 0.8 || rate > 2));
902         start = currentPosition;
903         end = GST_CLOCK_TIME_NONE;
904     } else {
905         start = 0;
906         mute = true;
907
908         // If we are at beginning of media, start from the end to
909         // avoid immediate EOS.
910         if (currentPosition <= 0)
911             end = static_cast<gint64>(duration() * GST_SECOND);
912         else
913             end = currentPosition;
914     }
915
916     LOG_MEDIA_MESSAGE("Need to mute audio: %d", (int) mute);
917
918     if (!gst_element_seek(m_playBin.get(), rate, GST_FORMAT_TIME, flags,
919                           GST_SEEK_TYPE_SET, start,
920                           GST_SEEK_TYPE_SET, end))
921         LOG_MEDIA_MESSAGE("Set rate to %f failed", rate);
922     else
923         g_object_set(m_playBin.get(), "mute", mute, NULL);
924 }
925
926 void MediaPlayerPrivateGStreamer::setPreservesPitch(bool preservesPitch)
927 {
928     m_preservesPitch = preservesPitch;
929 }
930
931 MediaPlayer::NetworkState MediaPlayerPrivateGStreamer::networkState() const
932 {
933     return m_networkState;
934 }
935
936 MediaPlayer::ReadyState MediaPlayerPrivateGStreamer::readyState() const
937 {
938     return m_readyState;
939 }
940
941 PassRefPtr<TimeRanges> MediaPlayerPrivateGStreamer::buffered() const
942 {
943     RefPtr<TimeRanges> timeRanges = TimeRanges::create();
944     if (m_errorOccured || isLiveStream())
945         return timeRanges.release();
946
947 #if GST_CHECK_VERSION(0, 10, 31)
948     float mediaDuration(duration());
949     if (!mediaDuration || isinf(mediaDuration))
950         return timeRanges.release();
951
952     GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT);
953
954     if (!gst_element_query(m_playBin.get(), query)) {
955         gst_query_unref(query);
956         return timeRanges.release();
957     }
958
959     gint64 rangeStart = 0, rangeStop = 0;
960     for (guint index = 0; index < gst_query_get_n_buffering_ranges(query); index++) {
961         if (gst_query_parse_nth_buffering_range(query, index, &rangeStart, &rangeStop))
962             timeRanges->add(static_cast<float>((rangeStart * mediaDuration) / 100),
963                             static_cast<float>((rangeStop * mediaDuration) / 100));
964     }
965
966     // Fallback to the more general maxTimeLoaded() if no range has
967     // been found.
968     if (!timeRanges->length())
969         if (float loaded = maxTimeLoaded())
970             timeRanges->add(0, loaded);
971
972     gst_query_unref(query);
973 #else
974     float loaded = maxTimeLoaded();
975     if (!m_errorOccured && !isLiveStream() && loaded > 0)
976         timeRanges->add(0, loaded);
977 #endif
978     return timeRanges.release();
979 }
980
981 gboolean MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message)
982 {
983     GOwnPtr<GError> err;
984     GOwnPtr<gchar> debug;
985     MediaPlayer::NetworkState error;
986     bool issueError = true;
987     bool attemptNextLocation = false;
988     const GstStructure* structure = gst_message_get_structure(message);
989
990     if (structure) {
991         const gchar* messageTypeName = gst_structure_get_name(structure);
992
993         // Redirect messages are sent from elements, like qtdemux, to
994         // notify of the new location(s) of the media.
995         if (!g_strcmp0(messageTypeName, "redirect")) {
996             mediaLocationChanged(message);
997             return TRUE;
998         }
999     }
1000
1001     LOG_MEDIA_MESSAGE("Message received from element %s", GST_MESSAGE_SRC_NAME(message));
1002     switch (GST_MESSAGE_TYPE(message)) {
1003     case GST_MESSAGE_ERROR:
1004         if (m_resetPipeline)
1005             break;
1006         gst_message_parse_error(message, &err.outPtr(), &debug.outPtr());
1007         LOG_MEDIA_MESSAGE("Error %d: %s (url=%s)", err->code, err->message, m_url.string().utf8().data());
1008
1009 #if ENABLE(TIZEN_DLOG_SUPPORT)
1010         TIZEN_LOGE("GST_MESSAGE_ERROR %d: %s (url=%s)", err->code, err->message, m_url.string().utf8().data());
1011 #endif
1012
1013         GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_playBin.get()), GST_DEBUG_GRAPH_SHOW_ALL, "webkit-video.error");
1014
1015         error = MediaPlayer::Empty;
1016         if (err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND
1017             || err->code == GST_STREAM_ERROR_WRONG_TYPE
1018             || err->code == GST_STREAM_ERROR_FAILED
1019             || err->code == GST_CORE_ERROR_MISSING_PLUGIN
1020             || err->code == GST_RESOURCE_ERROR_NOT_FOUND)
1021             error = MediaPlayer::FormatError;
1022         else if (err->domain == GST_STREAM_ERROR) {
1023             // Let the mediaPlayerClient handle the stream error, in
1024             // this case the HTMLMediaElement will emit a stalled
1025             // event.
1026 #if !ENABLE(TIZEN_MEDIA_STREAM)
1027             if (err->code == GST_STREAM_ERROR_TYPE_NOT_FOUND) {
1028                 LOG_MEDIA_MESSAGE("Decode error, let the Media element emit a stalled event.");
1029                 break;
1030             }
1031 #endif
1032             error = MediaPlayer::DecodeError;
1033             attemptNextLocation = true;
1034         } else if (err->domain == GST_RESOURCE_ERROR)
1035             error = MediaPlayer::NetworkError;
1036
1037         if (attemptNextLocation)
1038             issueError = !loadNextLocation();
1039         if (issueError)
1040             loadingFailed(error);
1041         break;
1042     case GST_MESSAGE_EOS:
1043         LOG_MEDIA_MESSAGE("End of Stream");
1044         didEnd();
1045         break;
1046     case GST_MESSAGE_STATE_CHANGED:
1047         // Ignore state changes if load is delayed (preload=none). The
1048         // player state will be updated once commitLoad() is called.
1049         if (m_delayingLoad) {
1050             LOG_MEDIA_MESSAGE("Media load has been delayed. Ignoring state changes for now");
1051             break;
1052         }
1053
1054         // Ignore state changes from internal elements. They are
1055         // forwarded to playbin2 anyway.
1056         if (GST_MESSAGE_SRC(message) == reinterpret_cast<GstObject*>(m_playBin.get())) {
1057             updateStates();
1058
1059             // Construct a filename for the graphviz dot file output.
1060             GstState oldState, newState;
1061             gst_message_parse_state_changed(message, &oldState, &newState, 0);
1062
1063             CString dotFileName = String::format("webkit-video.%s_%s",
1064                                                  gst_element_state_get_name(oldState),
1065                                                  gst_element_state_get_name(newState)).utf8();
1066
1067             GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_playBin.get()), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.data());
1068
1069 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
1070             if (m_suspendTime > 0 && newState == GST_STATE_PAUSED) {
1071                 seek(m_suspendTime);
1072                 m_suspendTime = 0;
1073                 m_player->mediaPlayerClient()->setSuspended(false);
1074             }
1075
1076             HTMLMediaElement* element = static_cast<HTMLMediaElement*>(player()->mediaPlayerClient());
1077             if (element->isVideo()) {
1078                 if (oldState == GST_STATE_PAUSED && newState == GST_STATE_PLAYING)
1079                     power_lock_state(POWER_STATE_NORMAL, 0);
1080                 else if (oldState == GST_STATE_PLAYING && newState == GST_STATE_PAUSED)
1081                     power_unlock_state(POWER_STATE_NORMAL);
1082             }
1083 #endif
1084         }
1085         break;
1086     case GST_MESSAGE_BUFFERING:
1087         processBufferingStats(message);
1088         break;
1089     case GST_MESSAGE_DURATION:
1090         LOG_MEDIA_MESSAGE("Duration changed");
1091         durationChanged();
1092         break;
1093     default:
1094         LOG_MEDIA_MESSAGE("Unhandled GStreamer message type: %s",
1095                     GST_MESSAGE_TYPE_NAME(message));
1096         break;
1097     }
1098     return TRUE;
1099 }
1100
1101 void MediaPlayerPrivateGStreamer::processBufferingStats(GstMessage* message)
1102 {
1103     // This is the immediate buffering that needs to happen so we have
1104     // enough to play right now.
1105     m_buffering = true;
1106     const GstStructure *structure = gst_message_get_structure(message);
1107     gst_structure_get_int(structure, "buffer-percent", &m_bufferingPercentage);
1108
1109     LOG_MEDIA_MESSAGE("[Buffering] Buffering: %d%%.", m_bufferingPercentage);
1110
1111     GstBufferingMode mode;
1112     gst_message_parse_buffering_stats(message, &mode, 0, 0, 0);
1113     if (mode != GST_BUFFERING_DOWNLOAD) {
1114         updateStates();
1115         return;
1116     }
1117
1118     // This is on-disk buffering, that allows us to download much more
1119     // than needed for right now.
1120     if (!m_startedBuffering) {
1121         LOG_MEDIA_MESSAGE("[Buffering] Starting on-disk buffering.");
1122
1123         m_startedBuffering = true;
1124
1125         if (m_fillTimer.isActive())
1126             m_fillTimer.stop();
1127
1128         m_fillTimer.startRepeating(0.2);
1129     }
1130 }
1131
1132 void MediaPlayerPrivateGStreamer::fillTimerFired(Timer<MediaPlayerPrivateGStreamer>*)
1133 {
1134     GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1135
1136     if (!gst_element_query(m_playBin.get(), query)) {
1137         gst_query_unref(query);
1138         return;
1139     }
1140
1141     gint64 start, stop;
1142     gdouble fillStatus = 100.0;
1143
1144     gst_query_parse_buffering_range(query, 0, &start, &stop, 0);
1145     gst_query_unref(query);
1146
1147     if (stop != -1)
1148         fillStatus = 100.0 * stop / GST_FORMAT_PERCENT_MAX;
1149
1150     LOG_MEDIA_MESSAGE("[Buffering] Download buffer filled up to %f%%", fillStatus);
1151
1152     if (!m_mediaDuration)
1153         durationChanged();
1154
1155     // Update maxTimeLoaded only if the media duration is
1156     // available. Otherwise we can't compute it.
1157     if (m_mediaDuration) {
1158         if (fillStatus == 100.0)
1159             m_maxTimeLoaded = m_mediaDuration;
1160         else
1161             m_maxTimeLoaded = static_cast<float>((fillStatus * m_mediaDuration) / 100.0);
1162         LOG_MEDIA_MESSAGE("[Buffering] Updated maxTimeLoaded: %f", m_maxTimeLoaded);
1163     }
1164
1165     if (fillStatus != 100.0) {
1166         updateStates();
1167         return;
1168     }
1169
1170     // Media is now fully loaded. It will play even if network
1171     // connection is cut. Buffering is done, remove the fill source
1172     // from the main loop.
1173     m_fillTimer.stop();
1174     m_startedBuffering = false;
1175     updateStates();
1176 }
1177
1178 float MediaPlayerPrivateGStreamer::maxTimeSeekable() const
1179 {
1180     if (m_errorOccured)
1181         return 0.0f;
1182
1183     LOG_MEDIA_MESSAGE("maxTimeSeekable");
1184     // infinite duration means live stream
1185     if (isinf(duration()))
1186         return 0.0f;
1187
1188     return duration();
1189 }
1190
1191 float MediaPlayerPrivateGStreamer::maxTimeLoaded() const
1192 {
1193     if (m_errorOccured)
1194         return 0.0f;
1195
1196     float loaded = m_maxTimeLoaded;
1197     if (!loaded && !m_fillTimer.isActive())
1198         loaded = duration();
1199     LOG_MEDIA_MESSAGE("maxTimeLoaded: %f", loaded);
1200     return loaded;
1201 }
1202
1203 bool MediaPlayerPrivateGStreamer::didLoadingProgress() const
1204 {
1205     if (!m_playBin || !m_mediaDuration || !totalBytes())
1206         return false;
1207     float currentMaxTimeLoaded = maxTimeLoaded();
1208     bool didLoadingProgress = currentMaxTimeLoaded != m_maxTimeLoadedAtLastDidLoadingProgress;
1209     m_maxTimeLoadedAtLastDidLoadingProgress = currentMaxTimeLoaded;
1210     LOG_MEDIA_MESSAGE("didLoadingProgress: %d", didLoadingProgress);
1211     return didLoadingProgress;
1212 }
1213
1214 unsigned MediaPlayerPrivateGStreamer::totalBytes() const
1215 {
1216     if (m_errorOccured)
1217         return 0;
1218
1219     if (m_totalBytes != -1)
1220         return m_totalBytes;
1221
1222     if (!m_source)
1223         return 0;
1224
1225     GstFormat fmt = GST_FORMAT_BYTES;
1226     gint64 length = 0;
1227 #ifdef GST_API_VERSION_1
1228     if (gst_element_query_duration(m_source.get(), fmt, &length)) {
1229 #else
1230     if (gst_element_query_duration(m_source.get(), &fmt, &length)) {
1231 #endif
1232         LOG_MEDIA_MESSAGE("totalBytes %" G_GINT64_FORMAT, length);
1233         m_totalBytes = static_cast<unsigned>(length);
1234         m_isStreaming = !length;
1235         return m_totalBytes;
1236     }
1237
1238     // Fall back to querying the source pads manually.
1239     // See also https://bugzilla.gnome.org/show_bug.cgi?id=638749
1240     GstIterator* iter = gst_element_iterate_src_pads(m_source.get());
1241     bool done = false;
1242     while (!done) {
1243 #ifdef GST_API_VERSION_1
1244         GValue item = G_VALUE_INIT;
1245         switch (gst_iterator_next(iter, &item)) {
1246         case GST_ITERATOR_OK: {
1247             GstPad* pad = static_cast<GstPad*>(g_value_get_object(&item));
1248             gint64 padLength = 0;
1249             if (gst_pad_query_duration(pad, fmt, &padLength) && padLength > length)
1250                 length = padLength;
1251             break;
1252         }
1253 #else
1254         gpointer data;
1255
1256         switch (gst_iterator_next(iter, &data)) {
1257         case GST_ITERATOR_OK: {
1258             GRefPtr<GstPad> pad = adoptGRef(GST_PAD_CAST(data));
1259             gint64 padLength = 0;
1260             if (gst_pad_query_duration(pad.get(), &fmt, &padLength) && padLength > length)
1261                 length = padLength;
1262             break;
1263         }
1264 #endif
1265         case GST_ITERATOR_RESYNC:
1266             gst_iterator_resync(iter);
1267             break;
1268         case GST_ITERATOR_ERROR:
1269             // Fall through.
1270         case GST_ITERATOR_DONE:
1271             done = true;
1272             break;
1273         }
1274
1275 #ifdef GST_API_VERSION_1
1276         g_value_unset(&item);
1277 #endif
1278     }
1279
1280     gst_iterator_free(iter);
1281
1282     LOG_MEDIA_MESSAGE("totalBytes %" G_GINT64_FORMAT, length);
1283     m_totalBytes = static_cast<unsigned>(length);
1284     m_isStreaming = !length;
1285     return m_totalBytes;
1286 }
1287
1288 unsigned MediaPlayerPrivateGStreamer::decodedFrameCount() const
1289 {
1290     guint64 decodedFrames = 0;
1291     if (m_fpsSink)
1292         g_object_get(m_fpsSink, "frames-rendered", &decodedFrames, NULL);
1293     return static_cast<unsigned>(decodedFrames);
1294 }
1295
1296 unsigned MediaPlayerPrivateGStreamer::droppedFrameCount() const
1297 {
1298     guint64 framesDropped = 0;
1299     if (m_fpsSink)
1300         g_object_get(m_fpsSink, "frames-dropped", &framesDropped, NULL);
1301     return static_cast<unsigned>(framesDropped);
1302 }
1303
1304 unsigned MediaPlayerPrivateGStreamer::audioDecodedByteCount() const
1305 {
1306     GstQuery* query = gst_query_new_position(GST_FORMAT_BYTES);
1307     gint64 position = 0;
1308
1309     if (m_webkitAudioSink && gst_element_query(m_webkitAudioSink.get(), query))
1310         gst_query_parse_position(query, 0, &position);
1311
1312     gst_query_unref(query);
1313     return static_cast<unsigned>(position);
1314 }
1315
1316 unsigned MediaPlayerPrivateGStreamer::videoDecodedByteCount() const
1317 {
1318     GstQuery* query = gst_query_new_position(GST_FORMAT_BYTES);
1319     gint64 position = 0;
1320
1321     if (gst_element_query(m_webkitVideoSink, query))
1322         gst_query_parse_position(query, 0, &position);
1323
1324     gst_query_unref(query);
1325     return static_cast<unsigned>(position);
1326 }
1327
1328 void MediaPlayerPrivateGStreamer::updateAudioSink()
1329 {
1330     if (!m_playBin)
1331         return;
1332
1333     GstElement* sinkPtr = 0;
1334
1335     g_object_get(m_playBin.get(), "audio-sink", &sinkPtr, NULL);
1336     m_webkitAudioSink = adoptGRef(sinkPtr);
1337
1338 }
1339
1340
1341 void MediaPlayerPrivateGStreamer::sourceChanged()
1342 {
1343     GstElement* srcPtr = 0;
1344
1345     g_object_get(m_playBin.get(), "source", &srcPtr, NULL);
1346     m_source = adoptGRef(srcPtr);
1347
1348     if (WEBKIT_IS_WEB_SRC(m_source.get()))
1349         webKitWebSrcSetMediaPlayer(WEBKIT_WEB_SRC(m_source.get()), m_player);
1350 }
1351
1352 void MediaPlayerPrivateGStreamer::cancelLoad()
1353 {
1354     if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
1355         return;
1356
1357     if (m_playBin)
1358         gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
1359 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1360     if (m_audioSessionManager)
1361         m_audioSessionManager->setSoundState(ASM_STATE_STOP);
1362 #endif
1363 }
1364
1365 void MediaPlayerPrivateGStreamer::updateStates()
1366 {
1367     if (!m_playBin)
1368         return;
1369
1370     if (m_errorOccured)
1371         return;
1372
1373     MediaPlayer::NetworkState oldNetworkState = m_networkState;
1374     MediaPlayer::ReadyState oldReadyState = m_readyState;
1375     GstState state;
1376     GstState pending;
1377
1378     GstStateChangeReturn ret = gst_element_get_state(m_playBin.get(),
1379         &state, &pending, 250 * GST_NSECOND);
1380
1381     bool shouldUpdateAfterSeek = false;
1382     switch (ret) {
1383     case GST_STATE_CHANGE_SUCCESS:
1384         LOG_MEDIA_MESSAGE("State: %s, pending: %s",
1385             gst_element_state_get_name(state),
1386             gst_element_state_get_name(pending));
1387
1388         m_resetPipeline = state <= GST_STATE_READY;
1389
1390         // Try to figure out ready and network states.
1391         if (state == GST_STATE_READY) {
1392             m_readyState = MediaPlayer::HaveMetadata;
1393             m_networkState = MediaPlayer::Empty;
1394             // Cache the duration without emiting the durationchange
1395             // event because it's taken care of by the media element
1396             // in this precise case.
1397             if (!m_isEndReached)
1398                 cacheDuration();
1399         } else if ((state == GST_STATE_NULL) || (maxTimeLoaded() == duration())) {
1400             m_networkState = MediaPlayer::Loaded;
1401             m_readyState = MediaPlayer::HaveEnoughData;
1402         } else {
1403             m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData;
1404             m_networkState = MediaPlayer::Loading;
1405         }
1406
1407         if (m_buffering && state != GST_STATE_READY) {
1408             m_readyState = MediaPlayer::HaveCurrentData;
1409             m_networkState = MediaPlayer::Loading;
1410         }
1411
1412         // Now let's try to get the states in more detail using
1413         // information from GStreamer, while we sync states where
1414         // needed.
1415         if (state == GST_STATE_PAUSED) {
1416             if (!m_webkitAudioSink)
1417                 updateAudioSink();
1418
1419             if (!m_volumeAndMuteInitialized) {
1420                 notifyPlayerOfVolumeChange();
1421                 notifyPlayerOfMute();
1422                 m_volumeAndMuteInitialized = true;
1423             }
1424
1425             if (m_buffering && m_bufferingPercentage == 100) {
1426                 m_buffering = false;
1427                 m_bufferingPercentage = 0;
1428                 m_readyState = MediaPlayer::HaveEnoughData;
1429
1430                 LOG_MEDIA_MESSAGE("[Buffering] Complete.");
1431
1432                 if (!m_paused) {
1433                     LOG_MEDIA_MESSAGE("[Buffering] Restarting playback.");
1434                     gst_element_set_state(m_playBin.get(), GST_STATE_PLAYING);
1435 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1436                     if (m_audioSessionManager)
1437                         m_audioSessionManager->setSoundState(ASM_STATE_PLAYING);
1438 #endif
1439                 }
1440             } else if (!m_buffering && (currentTime() < duration())) {
1441                 m_paused = true;
1442             }
1443         } else if (state == GST_STATE_PLAYING) {
1444             m_readyState = MediaPlayer::HaveEnoughData;
1445             m_paused = false;
1446
1447             if (m_buffering && !isLiveStream()) {
1448                 m_readyState = MediaPlayer::HaveCurrentData;
1449                 m_networkState = MediaPlayer::Loading;
1450
1451                 LOG_MEDIA_MESSAGE("[Buffering] Pausing stream for buffering.");
1452
1453                 gst_element_set_state(m_playBin.get(), GST_STATE_PAUSED);
1454 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1455                 if (m_audioSessionManager)
1456                     m_audioSessionManager->setSoundState(ASM_STATE_PAUSE);
1457 #endif
1458             }
1459         } else
1460             m_paused = true;
1461
1462         // Is on-disk buffering in progress?
1463         if (m_fillTimer.isActive())
1464             m_networkState = MediaPlayer::Loading;
1465
1466         if (m_changingRate) {
1467             m_player->rateChanged();
1468             m_changingRate = false;
1469         }
1470
1471         if (m_seeking) {
1472             shouldUpdateAfterSeek = true;
1473             m_seeking = false;
1474         }
1475
1476         break;
1477     case GST_STATE_CHANGE_ASYNC:
1478         LOG_MEDIA_MESSAGE("Async: State: %s, pending: %s",
1479             gst_element_state_get_name(state),
1480             gst_element_state_get_name(pending));
1481         // Change in progress
1482
1483         // On-disk buffering was attempted but the media is live. This
1484         // can't work so disable on-disk buffering and reset the
1485         // pipeline.
1486         if (state == GST_STATE_READY && isLiveStream() && m_preload == MediaPlayer::Auto) {
1487             setPreload(MediaPlayer::None);
1488             gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
1489             gst_element_set_state(m_playBin.get(), GST_STATE_PAUSED);
1490 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1491             if (m_audioSessionManager)
1492                 m_audioSessionManager->setSoundState(ASM_STATE_PAUSE);
1493 #endif
1494         }
1495
1496         // A live stream was paused, reset the pipeline.
1497         if (state == GST_STATE_PAUSED && pending == GST_STATE_PLAYING && isLiveStream()) {
1498             gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
1499             gst_element_set_state(m_playBin.get(), GST_STATE_PLAYING);
1500 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1501             if (m_audioSessionManager)
1502                 m_audioSessionManager->setSoundState(ASM_STATE_PLAYING);
1503 #endif
1504         }
1505
1506         if (!isLiveStream() && !m_buffering)
1507             return;
1508
1509         if (m_seeking) {
1510             shouldUpdateAfterSeek = true;
1511             m_seeking = false;
1512         }
1513         break;
1514     case GST_STATE_CHANGE_FAILURE:
1515         LOG_MEDIA_MESSAGE("Failure: State: %s, pending: %s",
1516             gst_element_state_get_name(state),
1517             gst_element_state_get_name(pending));
1518         // Change failed
1519         return;
1520     case GST_STATE_CHANGE_NO_PREROLL:
1521         LOG_MEDIA_MESSAGE("No preroll: State: %s, pending: %s",
1522             gst_element_state_get_name(state),
1523             gst_element_state_get_name(pending));
1524
1525         if (state == GST_STATE_READY)
1526             m_readyState = MediaPlayer::HaveNothing;
1527         else if (state == GST_STATE_PAUSED) {
1528             m_readyState = MediaPlayer::HaveEnoughData;
1529             m_paused = true;
1530             // Live pipelines go in PAUSED without prerolling.
1531             m_isStreaming = true;
1532         } else if (state == GST_STATE_PLAYING)
1533             m_paused = false;
1534
1535         if (m_seeking) {
1536             shouldUpdateAfterSeek = true;
1537             m_seeking = false;
1538             if (!m_paused) {
1539                 gst_element_set_state(m_playBin.get(), GST_STATE_PLAYING);
1540 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1541                 if (m_audioSessionManager)
1542                     m_audioSessionManager->setSoundState(ASM_STATE_PLAYING);
1543 #endif
1544             }
1545         } else if (!m_paused) {
1546             gst_element_set_state(m_playBin.get(), GST_STATE_PLAYING);
1547 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1548             if (m_audioSessionManager)
1549                 m_audioSessionManager->setSoundState(ASM_STATE_PLAYING);
1550 #endif
1551         }
1552
1553         m_networkState = MediaPlayer::Loading;
1554         break;
1555     default:
1556         LOG_MEDIA_MESSAGE("Else : %d", ret);
1557         break;
1558     }
1559
1560     if (seeking())
1561         m_readyState = MediaPlayer::HaveNothing;
1562
1563     if (shouldUpdateAfterSeek)
1564         timeChanged();
1565
1566     if (m_networkState != oldNetworkState) {
1567         LOG_MEDIA_MESSAGE("Network State Changed from %u to %u",
1568             oldNetworkState, m_networkState);
1569         m_player->networkStateChanged();
1570     }
1571     if (m_readyState != oldReadyState) {
1572         LOG_MEDIA_MESSAGE("Ready State Changed from %u to %u",
1573             oldReadyState, m_readyState);
1574         m_player->readyStateChanged();
1575 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER)
1576         if (state == GST_STATE_PLAYING)
1577             m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
1578 #endif
1579     }
1580 }
1581
1582 void MediaPlayerPrivateGStreamer::mediaLocationChanged(GstMessage* message)
1583 {
1584     if (m_mediaLocations)
1585         gst_structure_free(m_mediaLocations);
1586
1587     const GstStructure* structure = gst_message_get_structure(message);
1588     if (structure) {
1589         // This structure can contain:
1590         // - both a new-location string and embedded locations structure
1591         // - or only a new-location string.
1592         m_mediaLocations = gst_structure_copy(structure);
1593         const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations");
1594
1595         if (locations)
1596             m_mediaLocationCurrentIndex = static_cast<int>(gst_value_list_get_size(locations)) -1;
1597
1598         loadNextLocation();
1599     }
1600 }
1601
1602 bool MediaPlayerPrivateGStreamer::loadNextLocation()
1603 {
1604     if (!m_mediaLocations)
1605         return false;
1606
1607     const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations");
1608     const gchar* newLocation = 0;
1609
1610     if (!locations) {
1611         // Fallback on new-location string.
1612         newLocation = gst_structure_get_string(m_mediaLocations, "new-location");
1613         if (!newLocation)
1614             return false;
1615     }
1616
1617     if (!newLocation) {
1618         if (m_mediaLocationCurrentIndex < 0) {
1619             m_mediaLocations = 0;
1620             return false;
1621         }
1622
1623         const GValue* location = gst_value_list_get_value(locations,
1624                                                           m_mediaLocationCurrentIndex);
1625         const GstStructure* structure = gst_value_get_structure(location);
1626
1627         if (!structure) {
1628             m_mediaLocationCurrentIndex--;
1629             return false;
1630         }
1631
1632         newLocation = gst_structure_get_string(structure, "new-location");
1633     }
1634
1635     if (newLocation) {
1636         // Found a candidate. new-location is not always an absolute url
1637         // though. We need to take the base of the current url and
1638         // append the value of new-location to it.
1639
1640         gchar* currentLocation = 0;
1641         g_object_get(m_playBin.get(), "uri", &currentLocation, NULL);
1642
1643         KURL currentUrl(KURL(), currentLocation);
1644         g_free(currentLocation);
1645
1646         KURL newUrl;
1647
1648         if (gst_uri_is_valid(newLocation))
1649             newUrl = KURL(KURL(), newLocation);
1650         else
1651             newUrl = KURL(KURL(), currentUrl.baseAsString() + newLocation);
1652
1653         RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(currentUrl);
1654         if (securityOrigin->canRequest(newUrl)) {
1655             LOG_MEDIA_MESSAGE("New media url: %s", newUrl.string().utf8().data());
1656
1657             // Reset player states.
1658             m_networkState = MediaPlayer::Loading;
1659             m_player->networkStateChanged();
1660             m_readyState = MediaPlayer::HaveNothing;
1661             m_player->readyStateChanged();
1662
1663             // Reset pipeline state.
1664             m_resetPipeline = true;
1665             gst_element_set_state(m_playBin.get(), GST_STATE_READY);
1666 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1667             if (m_audioSessionManager)
1668                 m_audioSessionManager->setSoundState(ASM_STATE_NONE);
1669 #endif
1670             GstState state;
1671             gst_element_get_state(m_playBin.get(), &state, 0, 0);
1672             if (state <= GST_STATE_READY) {
1673                 // Set the new uri and start playing.
1674                 g_object_set(m_playBin.get(), "uri", newUrl.string().utf8().data(), NULL);
1675                 gst_element_set_state(m_playBin.get(), GST_STATE_PLAYING);
1676 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1677                 if (m_audioSessionManager)
1678                     m_audioSessionManager->setSoundState(ASM_STATE_PLAYING);
1679 #endif
1680                 return true;
1681             }
1682         }
1683     }
1684     m_mediaLocationCurrentIndex--;
1685     return false;
1686
1687 }
1688
1689 void MediaPlayerPrivateGStreamer::loadStateChanged()
1690 {
1691     updateStates();
1692 }
1693
1694 void MediaPlayerPrivateGStreamer::sizeChanged()
1695 {
1696     notImplemented();
1697 }
1698
1699 void MediaPlayerPrivateGStreamer::timeChanged()
1700 {
1701     updateStates();
1702     m_player->timeChanged();
1703 }
1704
1705 void MediaPlayerPrivateGStreamer::didEnd()
1706 {
1707     // Synchronize position and duration values to not confuse the
1708     // HTMLMediaElement. In some cases like reverse playback the
1709     // position is not always reported as 0 for instance.
1710     float now = currentTime();
1711     if (now > 0 && now <= duration() && m_mediaDuration != now) {
1712         m_mediaDurationKnown = true;
1713         m_mediaDuration = now;
1714         m_player->durationChanged();
1715     }
1716
1717     m_isEndReached = true;
1718     timeChanged();
1719
1720     if (!m_player->mediaPlayerClient()->mediaPlayerIsLooping()) {
1721         m_paused = true;
1722 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1723         gst_element_set_state(m_playBin.get(), GST_STATE_PAUSED);
1724         if (m_audioSessionManager)
1725             m_audioSessionManager->setSoundState(ASM_STATE_PAUSE);
1726 #else
1727         gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
1728 #endif
1729
1730 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
1731         HTMLMediaElement* element = static_cast<HTMLMediaElement*>(player()->mediaPlayerClient());
1732         if (element->isVideo())
1733             power_unlock_state(POWER_STATE_NORMAL);
1734
1735 #endif
1736     }
1737 }
1738
1739 void MediaPlayerPrivateGStreamer::cacheDuration()
1740 {
1741     // Reset cached media duration
1742     m_mediaDuration = 0;
1743
1744     // And re-cache it if possible.
1745     GstState state;
1746     gst_element_get_state(m_playBin.get(), &state, 0, 0);
1747     float newDuration = duration();
1748
1749     if (state <= GST_STATE_READY) {
1750         // Don't set m_mediaDurationKnown yet if the pipeline is not
1751         // paused. This allows duration() query to fail at least once
1752         // before playback starts and duration becomes known.
1753         if (!isinf(newDuration))
1754             m_mediaDuration = newDuration;
1755     } else {
1756         m_mediaDurationKnown = !isinf(newDuration);
1757         if (m_mediaDurationKnown)
1758             m_mediaDuration = newDuration;
1759     }
1760
1761     if (!isinf(newDuration))
1762         m_mediaDuration = newDuration;
1763 }
1764
1765 void MediaPlayerPrivateGStreamer::durationChanged()
1766 {
1767     float previousDuration = m_mediaDuration;
1768
1769     cacheDuration();
1770     // Avoid emiting durationchanged in the case where the previous
1771     // duration was 0 because that case is already handled by the
1772     // HTMLMediaElement.
1773     if (previousDuration && m_mediaDuration != previousDuration)
1774         m_player->durationChanged();
1775
1776     if (m_preload == MediaPlayer::None && m_originalPreloadWasAutoAndWasOverridden) {
1777         m_totalBytes = -1;
1778         if (totalBytes() && !isLiveStream()) {
1779             setPreload(MediaPlayer::Auto);
1780             gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
1781             gst_element_set_state(m_playBin.get(), GST_STATE_PAUSED);
1782 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1783             if (m_audioSessionManager)
1784                 m_audioSessionManager->setSoundState(ASM_STATE_PAUSE);
1785 #endif
1786         }
1787     }
1788 }
1789
1790 bool MediaPlayerPrivateGStreamer::supportsMuting() const
1791 {
1792     return true;
1793 }
1794
1795 void MediaPlayerPrivateGStreamer::setMuted(bool muted)
1796 {
1797     if (!m_playBin)
1798         return;
1799
1800     g_object_set(m_playBin.get(), "mute", muted, NULL);
1801 }
1802
1803 void MediaPlayerPrivateGStreamer::notifyPlayerOfMute()
1804 {
1805     m_muteTimerHandler = 0;
1806
1807     if (!m_player || !m_playBin)
1808         return;
1809
1810     gboolean muted;
1811     g_object_get(m_playBin.get(), "mute", &muted, NULL);
1812     m_player->muteChanged(static_cast<bool>(muted));
1813 }
1814
1815 void MediaPlayerPrivateGStreamer::muteChanged()
1816 {
1817     if (m_muteTimerHandler)
1818         g_source_remove(m_muteTimerHandler);
1819     m_muteTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateMuteChangeTimeoutCallback), this);
1820 }
1821
1822 void MediaPlayerPrivateGStreamer::loadingFailed(MediaPlayer::NetworkState error)
1823 {
1824 #if ENABLE(TIZEN_DLOG_SUPPORT)
1825     TIZEN_LOGE("NetworkState : %d", error);
1826 #endif
1827
1828     m_errorOccured = true;
1829     if (m_networkState != error) {
1830         m_networkState = error;
1831         m_player->networkStateChanged();
1832     }
1833     if (m_readyState != MediaPlayer::HaveNothing) {
1834         m_readyState = MediaPlayer::HaveNothing;
1835         m_player->readyStateChanged();
1836     }
1837 }
1838
1839 void MediaPlayerPrivateGStreamer::setSize(const IntSize& size)
1840 {
1841     m_size = size;
1842 }
1843
1844 void MediaPlayerPrivateGStreamer::setVisible(bool visible)
1845 {
1846 }
1847
1848 void MediaPlayerPrivateGStreamer::triggerRepaint(GstBuffer* buffer)
1849 {
1850     g_return_if_fail(GST_IS_BUFFER(buffer));
1851     gst_buffer_replace(&m_buffer, buffer);
1852 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER)
1853 #if !ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
1854     if (m_videoSize.isEmpty())
1855         m_videoSize =  naturalSize();
1856     m_videoLayer->paintVideoLayer(m_videoSize);
1857     return;
1858 #endif
1859 #endif
1860     m_player->repaint();
1861 }
1862
1863 void MediaPlayerPrivateGStreamer::paint(GraphicsContext* context, const IntRect& rect)
1864 {
1865     if (context->paintingDisabled())
1866         return;
1867
1868     if (!m_player->visible())
1869         return;
1870
1871     if (!m_buffer)
1872         return;
1873
1874     GRefPtr<GstCaps> caps = webkitGstGetPadCaps(m_videoSinkPad.get());
1875     if (!caps)
1876         return;
1877
1878     RefPtr<ImageGStreamer> gstImage = ImageGStreamer::createImage(m_buffer, caps.get());
1879     if (!gstImage)
1880         return;
1881
1882     context->drawImage(reinterpret_cast<Image*>(gstImage->image().get()), ColorSpaceSRGB,
1883                        rect, gstImage->rect(), CompositeCopy, DoNotRespectImageOrientation, false);
1884 }
1885
1886 static HashSet<String> mimeTypeCache()
1887 {
1888     initializeGStreamerAndRegisterWebKitElements();
1889
1890     DEFINE_STATIC_LOCAL(HashSet<String>, cache, ());
1891     static bool typeListInitialized = false;
1892
1893     if (typeListInitialized)
1894         return cache;
1895     const char* mimeTypes[] = {
1896         "application/ogg",
1897         "application/vnd.apple.mpegurl",
1898         "application/vnd.rn-realmedia",
1899         "application/x-3gp",
1900 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
1901         "application/x-mpegurl",
1902         "application/x-mpegURL",
1903 #endif
1904         "application/x-pn-realaudio",
1905         "audio/3gpp",
1906         "audio/aac",
1907         "audio/flac",
1908         "audio/iLBC-sh",
1909         "audio/midi",
1910         "audio/mobile-xmf",
1911         "audio/mp1",
1912         "audio/mp2",
1913         "audio/mp3",
1914         "audio/mp4",
1915         "audio/mpeg",
1916         "audio/ogg",
1917         "audio/opus",
1918         "audio/qcelp",
1919         "audio/riff-midi",
1920         "audio/wav",
1921         "audio/webm",
1922         "audio/x-ac3",
1923         "audio/x-aiff",
1924         "audio/x-amr-nb-sh",
1925         "audio/x-amr-wb-sh",
1926         "audio/x-au",
1927         "audio/x-ay",
1928         "audio/x-celt",
1929         "audio/x-dts",
1930         "audio/x-flac",
1931         "audio/x-gbs",
1932         "audio/x-gsm",
1933         "audio/x-gym",
1934         "audio/x-imelody",
1935         "audio/x-ircam",
1936         "audio/x-kss",
1937         "audio/x-m4a",
1938         "audio/x-mod",
1939         "audio/x-mp3",
1940         "audio/x-mpeg",
1941         "audio/x-musepack",
1942         "audio/x-nist",
1943         "audio/x-nsf",
1944         "audio/x-paris",
1945         "audio/x-sap",
1946         "audio/x-sbc",
1947         "audio/x-sds",
1948         "audio/x-shorten",
1949         "audio/x-sid",
1950         "audio/x-spc",
1951         "audio/x-speex",
1952         "audio/x-svx",
1953         "audio/x-ttafile",
1954         "audio/x-vgm",
1955         "audio/x-voc",
1956         "audio/x-vorbis+ogg",
1957         "audio/x-w64",
1958         "audio/x-wav",
1959         "audio/x-wavpack",
1960         "audio/x-wavpack-correction",
1961         "video/3gpp",
1962         "video/mj2",
1963         "video/mp4",
1964         "video/mpeg",
1965         "video/mpegts",
1966         "video/ogg",
1967         "video/quicktime",
1968         "video/vivo",
1969         "video/webm",
1970         "video/x-cdxa",
1971         "video/x-dirac",
1972         "video/x-dv",
1973         "video/x-fli",
1974         "video/x-flv",
1975         "video/x-h263",
1976         "video/x-ivf",
1977         "video/x-m4v",
1978         "video/x-matroska",
1979         "video/x-mng",
1980         "video/x-ms-asf",
1981         "video/x-msvideo",
1982         "video/x-mve",
1983         "video/x-nuv",
1984         "video/x-vcd"
1985     };
1986
1987     for (unsigned i = 0; i < (sizeof(mimeTypes) / sizeof(*mimeTypes)); ++i)
1988         cache.add(String(mimeTypes[i]));
1989
1990     typeListInitialized = true;
1991     return cache;
1992 }
1993
1994 void MediaPlayerPrivateGStreamer::getSupportedTypes(HashSet<String>& types)
1995 {
1996     types = mimeTypeCache();
1997 }
1998
1999 MediaPlayer::SupportsType MediaPlayerPrivateGStreamer::supportsType(const String& type, const String& codecs, const KURL&)
2000 {
2001     if (type.isNull() || type.isEmpty())
2002         return MediaPlayer::IsNotSupported;
2003
2004     // spec says we should not return "probably" if the codecs string is empty
2005     if (mimeTypeCache().contains(type))
2006         return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported;
2007     return MediaPlayer::IsNotSupported;
2008 }
2009
2010 bool MediaPlayerPrivateGStreamer::hasSingleSecurityOrigin() const
2011 {
2012     return true;
2013 }
2014
2015 bool MediaPlayerPrivateGStreamer::supportsFullscreen() const
2016 {
2017 #if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED == 1050
2018     // See <rdar://problem/7389945>
2019     return false;
2020 #else
2021     return true;
2022 #endif
2023 }
2024
2025 PlatformMedia MediaPlayerPrivateGStreamer::platformMedia() const
2026 {
2027     PlatformMedia p;
2028 #ifndef GST_API_VERSION_1
2029     p.type = PlatformMedia::GStreamerGWorldType;
2030     p.media.gstreamerGWorld = m_gstGWorld.get();
2031 #endif
2032     return p;
2033 }
2034
2035 MediaPlayer::MovieLoadType MediaPlayerPrivateGStreamer::movieLoadType() const
2036 {
2037     if (m_readyState == MediaPlayer::HaveNothing)
2038         return MediaPlayer::Unknown;
2039
2040     if (isLiveStream())
2041         return MediaPlayer::LiveStream;
2042
2043     return MediaPlayer::Download;
2044 }
2045
2046 void MediaPlayerPrivateGStreamer::setDownloadBuffering()
2047 {
2048     if (!m_playBin)
2049         return;
2050
2051     GstPlayFlags flags;
2052
2053     g_object_get(m_playBin.get(), "flags", &flags, NULL);
2054 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER) && ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
2055     flags = (GstPlayFlags)(flags | GST_PLAY_FLAG_NATIVE_VIDEO);
2056 #endif
2057     if (m_preload == MediaPlayer::Auto) {
2058         LOG_MEDIA_MESSAGE("Enabling on-disk buffering");
2059         g_object_set(m_playBin.get(), "flags", flags | GST_PLAY_FLAG_DOWNLOAD, NULL);
2060     } else {
2061         LOG_MEDIA_MESSAGE("Disabling on-disk buffering");
2062         g_object_set(m_playBin.get(), "flags", flags & ~GST_PLAY_FLAG_DOWNLOAD, NULL);
2063     }
2064 }
2065
2066 void MediaPlayerPrivateGStreamer::setPreload(MediaPlayer::Preload preload)
2067 {
2068     m_originalPreloadWasAutoAndWasOverridden = m_preload != preload && m_preload == MediaPlayer::Auto;
2069
2070     m_preload = preload;
2071
2072     setDownloadBuffering();
2073
2074     if (m_delayingLoad && m_preload != MediaPlayer::None) {
2075         m_delayingLoad = false;
2076         commitLoad();
2077     }
2078 }
2079
2080 void MediaPlayerPrivateGStreamer::createAudioSink()
2081 {
2082     // Construct audio sink if pitch preserving is enabled.
2083     if (!m_preservesPitch)
2084         return;
2085
2086     if (!m_playBin)
2087         return;
2088
2089     GstElement* scale = gst_element_factory_make("scaletempo", 0);
2090     if (!scale) {
2091         GST_WARNING("Failed to create scaletempo");
2092         return;
2093     }
2094
2095     GstElement* convert = gst_element_factory_make("audioconvert", 0);
2096     GstElement* resample = gst_element_factory_make("audioresample", 0);
2097     GstElement* sink = gst_element_factory_make("autoaudiosink", 0);
2098
2099     GstElement* audioSink = gst_bin_new("audio-sink");
2100     gst_bin_add_many(GST_BIN(audioSink), scale, convert, resample, sink, NULL);
2101
2102     if (!gst_element_link_many(scale, convert, resample, sink, NULL)) {
2103         GST_WARNING("Failed to link audio sink elements");
2104         gst_object_unref(audioSink);
2105         return;
2106     }
2107
2108     GRefPtr<GstPad> pad = adoptGRef(gst_element_get_static_pad(scale, "sink"));
2109     gst_element_add_pad(audioSink, gst_ghost_pad_new("sink", pad.get()));
2110
2111     g_object_set(m_playBin.get(), "audio-sink", audioSink, NULL);
2112 }
2113
2114 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
2115 GstElement* MediaPlayerPrivateGStreamer::createVideoSink()
2116 {
2117 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER) && ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
2118     m_webkitVideoSink = m_videoLayer->createVideoSink();
2119     m_videoSinkPad = adoptGRef(gst_element_get_static_pad(m_webkitVideoSink, "sink"));
2120
2121     // Primary video should be OFF and Secondary video should be FULL SCREEN mode
2122     g_object_set(m_webkitVideoSink, "display-mode", 2, NULL);
2123 #else // ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER) && ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
2124 #ifndef GST_API_VERSION_1
2125     m_webkitVideoSink = webkitVideoSinkNew(m_gstGWorld.get());
2126 #else
2127     m_webkitVideoSink = webkitVideoSinkNew();
2128 #endif
2129     m_videoSinkPad = adoptGRef(gst_element_get_static_pad(m_webkitVideoSink, "sink"));
2130     g_signal_connect(m_webkitVideoSink, "repaint-requested", G_CALLBACK(mediaPlayerPrivateRepaintCallback), this);
2131 #endif // ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER) && ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
2132
2133 #ifndef GST_API_VERSION_1
2134     m_videoSinkBin = gst_bin_new("video-sink");
2135     GstElement* videoTee = gst_element_factory_make("tee", "videoTee");
2136 #if !ENABLE(TIZEN_GSTREAMER_VIDEO)
2137     GstElement* queue = gst_element_factory_make("queue", 0);
2138 #endif
2139     // Take ownership.
2140     gst_object_ref_sink(m_videoSinkBin);
2141
2142     // Build a new video sink consisting of a bin containing a tee
2143     // (meant to distribute data to multiple video sinks) and our
2144     // internal video sink. For fullscreen we create an autovideosink
2145     // and initially block the data flow towards it and configure it
2146 #if !ENABLE(TIZEN_GSTREAMER_VIDEO)
2147     gst_bin_add_many(GST_BIN(m_videoSinkBin), videoTee, queue, NULL);
2148 #else
2149     gst_bin_add_many(GST_BIN(m_videoSinkBin), videoTee, NULL);
2150 #endif
2151
2152 #if !ENABLE(TIZEN_GSTREAMER_VIDEO)
2153     // Link a new src pad from tee to queue1.
2154     gst_element_link_pads_full(videoTee, 0, queue, "sink", GST_PAD_LINK_CHECK_NOTHING);
2155 #endif
2156 #endif
2157
2158     GstElement* actualVideoSink = 0;
2159     m_fpsSink = gst_element_factory_make("fpsdisplaysink", "sink");
2160     if (m_fpsSink) {
2161         // The verbose property has been added in -bad 0.10.22. Making
2162         // this whole code depend on it because we don't want
2163         // fpsdiplaysink to spit data on stdout.
2164         GstElementFactory* factory = GST_ELEMENT_FACTORY(GST_ELEMENT_GET_CLASS(m_fpsSink)->elementfactory);
2165         if (gst_plugin_feature_check_version(GST_PLUGIN_FEATURE(factory), 0, 10, 22)) {
2166             g_object_set(m_fpsSink, "silent", TRUE , NULL);
2167
2168             // Turn off text overlay unless logging is enabled.
2169 #if LOG_DISABLED
2170             g_object_set(m_fpsSink, "text-overlay", FALSE , NULL);
2171 #else
2172             WTFLogChannel* channel = getChannelFromName("Media");
2173             if (channel->state != WTFLogChannelOn)
2174                 g_object_set(m_fpsSink, "text-overlay", FALSE , NULL);
2175 #endif // LOG_DISABLED
2176
2177             if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_fpsSink), "video-sink")) {
2178                 g_object_set(m_fpsSink, "video-sink", m_webkitVideoSink, NULL);
2179 #ifndef GST_API_VERSION_1
2180                 gst_bin_add(GST_BIN(m_videoSinkBin), m_fpsSink);
2181 #endif
2182                 actualVideoSink = m_fpsSink;
2183             } else
2184                 m_fpsSink = 0;
2185         } else
2186             m_fpsSink = 0;
2187     }
2188
2189     if (!m_fpsSink) {
2190 #ifndef GST_API_VERSION_1
2191         gst_bin_add(GST_BIN(m_videoSinkBin), m_webkitVideoSink);
2192 #endif
2193         actualVideoSink = m_webkitVideoSink;
2194     }
2195
2196     ASSERT(actualVideoSink);
2197
2198 #ifndef GST_API_VERSION_1
2199 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
2200     // Link a new src pad from tee to queue1.
2201     GRefPtr<GstPad> srcPad = adoptGRef(gst_element_get_request_pad(videoTee, "src%d"));
2202     GRefPtr<GstPad> sinkPad = adoptGRef(gst_element_get_static_pad(actualVideoSink, "sink"));
2203     gst_pad_link(srcPad.get(), sinkPad.get());
2204 #else
2205     // Faster elements linking.
2206     gst_element_link_pads_full(queue, "src", actualVideoSink, "sink", GST_PAD_LINK_CHECK_NOTHING);
2207 #endif
2208     // Add a ghostpad to the bin so it can proxy to tee.
2209     GRefPtr<GstPad> pad = adoptGRef(gst_element_get_static_pad(videoTee, "sink"));
2210     gst_element_add_pad(m_videoSinkBin, gst_ghost_pad_new("sink", pad.get()));
2211
2212     // Set the bin as video sink of playbin.
2213     return m_videoSinkBin;
2214 #else
2215     return actualVideoSink;
2216 #endif
2217 }
2218 #endif
2219
2220 void MediaPlayerPrivateGStreamer::createGSTPlayBin()
2221 {
2222     ASSERT(!m_playBin);
2223
2224     // gst_element_factory_make() returns a floating reference so
2225     // we should not adopt.
2226     m_playBin = gst_element_factory_make(gPlaybinName, "play");
2227
2228 #ifndef GST_API_VERSION_1
2229     m_gstGWorld = GStreamerGWorld::createGWorld(m_playBin.get());
2230 #endif
2231
2232     GRefPtr<GstBus> bus = webkitGstPipelineGetBus(GST_PIPELINE(m_playBin.get()));
2233     gst_bus_add_signal_watch(bus.get());
2234     g_signal_connect(bus.get(), "message", G_CALLBACK(mediaPlayerPrivateMessageCallback), this);
2235 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER) && ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
2236     gst_bus_set_sync_handler(bus.get(), GstBusSyncHandler(mediaPlayerPrivateSyncHandler), this);
2237 #endif
2238     gst_object_unref(bus.get());
2239
2240     g_object_set(m_playBin.get(), "mute", m_player->muted(), NULL);
2241
2242     g_signal_connect(m_playBin.get(), "notify::volume", G_CALLBACK(mediaPlayerPrivateVolumeChangedCallback), this);
2243     g_signal_connect(m_playBin.get(), "notify::source", G_CALLBACK(mediaPlayerPrivateSourceChangedCallback), this);
2244     g_signal_connect(m_playBin.get(), "notify::mute", G_CALLBACK(mediaPlayerPrivateMuteChangedCallback), this);
2245     g_signal_connect(m_playBin.get(), "video-changed", G_CALLBACK(mediaPlayerPrivateVideoChangedCallback), this);
2246     g_signal_connect(m_playBin.get(), "audio-changed", G_CALLBACK(mediaPlayerPrivateAudioChangedCallback), this);
2247 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
2248     g_signal_connect(m_playBin.get(), "source-setup", G_CALLBACK(mediaPlayerPrivateSourceSetupCallback), this);
2249 #endif
2250
2251 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
2252     HTMLMediaElement* element = static_cast<HTMLMediaElement*>(player()->mediaPlayerClient());
2253     if (element->isVideo()) {
2254         GstElement* videoElement = createVideoSink();
2255         g_object_set(m_playBin.get(), "video-sink", videoElement, NULL);
2256
2257         GRefPtr<GstPad> videoSinkPad = adoptGRef(gst_element_get_static_pad(m_webkitVideoSink, "sink"));
2258         if (videoSinkPad)
2259             g_signal_connect(videoSinkPad.get(), "notify::caps", G_CALLBACK(mediaPlayerPrivateVideoSinkCapsChangedCallback), this);
2260     } else {
2261         GstElement* fakeSink = gst_element_factory_make("fakesink", 0);
2262         g_object_set(fakeSink, "sync", true, NULL);
2263         g_object_set(m_playBin.get(), "video-sink", fakeSink, NULL);
2264     }
2265 #endif
2266
2267 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
2268     if (m_audioSessionManager)
2269         m_audioSessionManager->registerAudioSessionManager(MM_SESSION_TYPE_SHARE, mediaPlayerPrivateAudioSessionNotifyCallback, player());
2270 #endif
2271
2272 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
2273     GstElement* realSink = gst_element_factory_make("avsysaudiosink", 0);
2274     g_object_set(realSink, "close-handle-on-prepare", 1, NULL);
2275     g_object_set(m_playBin.get(), "audio-sink", realSink, NULL);
2276 #else
2277     createAudioSink();
2278 #endif
2279 }
2280
2281 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER)
2282 bool MediaPlayerPrivateGStreamer::supportsAcceleratedRendering() const
2283 {
2284     bool isEmbedVideo = false;
2285     if (m_player->mediaPlayerClient()) {
2286         Document* document = m_player->mediaPlayerClient()->mediaPlayerOwningDocument();
2287         if (document && document->settings()) {
2288             isEmbedVideo = document->settings()->acceleratedCompositingForVideoEnabled()
2289                                 && document->settings()->acceleratedCompositingEnabled();
2290             LOG_MEDIA_MESSAGE("isEmbedVideo: %d", isEmbedVideo);
2291         }
2292     }
2293
2294     return isEmbedVideo;
2295 }
2296
2297 PlatformLayer* MediaPlayerPrivateGStreamer::platformLayer() const
2298 {
2299     return m_videoLayer->platformLayer();
2300 }
2301
2302 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
2303 void MediaPlayerPrivateGStreamer::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& rect)
2304 {
2305     m_videoLayer->paintCurrentFrameInContext(context, rect);
2306 }
2307
2308 void MediaPlayerPrivateGStreamer::xWindowIdPrepared(GstMessage* message)
2309 {
2310     int width;
2311     int height;
2312     gst_structure_get_int(message->structure, "video-width", &width);
2313     gst_structure_get_int(message->structure, "video-height", &height);
2314
2315 #if ENABLE(TIZEN_DLOG_SUPPORT)
2316     TIZEN_LOGI("Width: %d, Height: %d", width, height);
2317 #endif
2318
2319     IntSize size(width, height);
2320     m_videoSize = size;
2321     m_videoLayer->setOverlay(size);
2322 }
2323 #endif // ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
2324 #endif // ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER)
2325
2326 #if ENABLE(TIZEN_WEBKIT2_PROXY)
2327 void MediaPlayerPrivateGStreamer::setProxy(GstElement* source)
2328 {
2329     SoupSession* session = WebCore::ResourceHandle::defaultSession();
2330     if (!session)
2331         return;
2332
2333     SoupURI* proxyUri = 0;
2334     g_object_get(session, SOUP_SESSION_PROXY_URI, &proxyUri, NULL);
2335     if (!proxyUri)
2336         return;
2337
2338     char* proxy = soup_uri_to_string(proxyUri, false);
2339     g_object_set(source, "proxy", proxy, NULL);
2340
2341     soup_uri_free(proxyUri);
2342     g_free(proxy);
2343 }
2344 #endif
2345
2346 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
2347 void MediaPlayerPrivateGStreamer::suspend()
2348 {
2349     m_suspendTime = currentTime();
2350     gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
2351 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
2352     if (m_audioSessionManager)
2353         m_audioSessionManager->setSoundState(ASM_STATE_STOP);
2354 #endif
2355 }
2356
2357 void MediaPlayerPrivateGStreamer::resume()
2358 {
2359     gst_element_set_state(m_playBin.get(), GST_STATE_PAUSED);
2360 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
2361     if (m_audioSessionManager)
2362         m_audioSessionManager->setSoundState(ASM_STATE_PAUSE);
2363 #endif
2364 }
2365
2366 #endif
2367
2368 }
2369
2370 #endif // USE(GSTREAMER)