[GLIB] Use GUniquePtr instead of GOwnPtr
[WebKit-https.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, 2011, 2012, 2013 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 "GStreamerUtilities.h"
30 #include "URL.h"
31 #include "MIMETypeRegistry.h"
32 #include "MediaPlayer.h"
33 #include "NotImplemented.h"
34 #include "SecurityOrigin.h"
35 #include "TimeRanges.h"
36 #include "WebKitWebSourceGStreamer.h"
37 #include <gst/gst.h>
38 #include <gst/pbutils/missing-plugins.h>
39 #include <limits>
40 #include <wtf/gobject/GOwnPtr.h>
41 #include <wtf/gobject/GUniquePtr.h>
42 #include <wtf/text/CString.h>
43
44 #if ENABLE(VIDEO_TRACK)
45 #include "AudioTrackPrivateGStreamer.h"
46 #include "InbandMetadataTextTrackPrivateGStreamer.h"
47 #include "InbandTextTrackPrivateGStreamer.h"
48 #include "TextCombinerGStreamer.h"
49 #include "TextSinkGStreamer.h"
50 #include "VideoTrackPrivateGStreamer.h"
51 #endif
52
53 #include <gst/audio/streamvolume.h>
54
55 #if ENABLE(MEDIA_SOURCE)
56 #include "MediaSource.h"
57 #include "WebKitMediaSourceGStreamer.h"
58 #endif
59
60 // GstPlayFlags flags from playbin2. It is the policy of GStreamer to
61 // not publicly expose element-specific enums. That's why this
62 // GstPlayFlags enum has been copied here.
63 typedef enum {
64     GST_PLAY_FLAG_VIDEO         = 0x00000001,
65     GST_PLAY_FLAG_AUDIO         = 0x00000002,
66     GST_PLAY_FLAG_TEXT          = 0x00000004,
67     GST_PLAY_FLAG_VIS           = 0x00000008,
68     GST_PLAY_FLAG_SOFT_VOLUME   = 0x00000010,
69     GST_PLAY_FLAG_NATIVE_AUDIO  = 0x00000020,
70     GST_PLAY_FLAG_NATIVE_VIDEO  = 0x00000040,
71     GST_PLAY_FLAG_DOWNLOAD      = 0x00000080,
72     GST_PLAY_FLAG_BUFFERING     = 0x000000100
73 } GstPlayFlags;
74
75 // Max interval in seconds to stay in the READY state on manual
76 // state change requests.
77 static const guint gReadyStateTimerInterval = 60;
78
79 GST_DEBUG_CATEGORY_EXTERN(webkit_media_player_debug);
80 #define GST_CAT_DEFAULT webkit_media_player_debug
81
82 using namespace std;
83
84 namespace WebCore {
85
86 static gboolean mediaPlayerPrivateMessageCallback(GstBus*, GstMessage* message, MediaPlayerPrivateGStreamer* player)
87 {
88     return player->handleMessage(message);
89 }
90
91 static void mediaPlayerPrivateSourceChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
92 {
93     player->sourceChanged();
94 }
95
96 static void mediaPlayerPrivateVideoSinkCapsChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
97 {
98     player->videoCapsChanged();
99 }
100
101 static void mediaPlayerPrivateVideoChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player)
102 {
103     player->videoChanged();
104 }
105
106 static void mediaPlayerPrivateAudioChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player)
107 {
108     player->audioChanged();
109 }
110
111 static gboolean mediaPlayerPrivateAudioChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
112 {
113     // This is the callback of the timeout source created in ::audioChanged.
114     player->notifyPlayerOfAudio();
115     return FALSE;
116 }
117
118 static void setAudioStreamPropertiesCallback(GstChildProxy*, GObject* object, gchar*,
119     MediaPlayerPrivateGStreamer* player)
120 {
121     player->setAudioStreamProperties(object);
122 }
123
124 static gboolean mediaPlayerPrivateVideoChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
125 {
126     // This is the callback of the timeout source created in ::videoChanged.
127     player->notifyPlayerOfVideo();
128     return FALSE;
129 }
130
131 static gboolean mediaPlayerPrivateVideoCapsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
132 {
133     // This is the callback of the timeout source created in ::videoCapsChanged.
134     player->notifyPlayerOfVideoCaps();
135     return FALSE;
136 }
137
138 #if ENABLE(VIDEO_TRACK)
139 static void mediaPlayerPrivateTextChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player)
140 {
141     player->textChanged();
142 }
143
144 static gboolean mediaPlayerPrivateTextChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
145 {
146     // This is the callback of the timeout source created in ::textChanged.
147     player->notifyPlayerOfText();
148     return FALSE;
149 }
150
151 static GstFlowReturn mediaPlayerPrivateNewTextSampleCallback(GObject*, MediaPlayerPrivateGStreamer* player)
152 {
153     player->newTextSample();
154     return GST_FLOW_OK;
155 }
156 #endif
157
158 static gboolean mediaPlayerPrivateReadyStateTimeoutCallback(MediaPlayerPrivateGStreamer* player)
159 {
160     // This is the callback of the timeout source created in ::changePipelineState.
161     // Reset pipeline if we are sitting on READY state when timeout is reached
162     player->changePipelineState(GST_STATE_NULL);
163     return FALSE;
164 }
165
166 static void mediaPlayerPrivatePluginInstallerResultFunction(GstInstallPluginsReturn result, gpointer userData)
167 {
168     MediaPlayerPrivateGStreamer* player = reinterpret_cast<MediaPlayerPrivateGStreamer*>(userData);
169     player->handlePluginInstallerResult(result);
170 }
171
172 static GstClockTime toGstClockTime(float time)
173 {
174     // Extract the integer part of the time (seconds) and the fractional part (microseconds). Attempt to
175     // round the microseconds so no floating point precision is lost and we can perform an accurate seek.
176     float seconds;
177     float microSeconds = modf(time, &seconds) * 1000000;
178     GTimeVal timeValue;
179     timeValue.tv_sec = static_cast<glong>(seconds);
180     timeValue.tv_usec = static_cast<glong>(roundf(microSeconds / 10000) * 10000);
181     return GST_TIMEVAL_TO_TIME(timeValue);
182 }
183
184 void MediaPlayerPrivateGStreamer::setAudioStreamProperties(GObject* object)
185 {
186     if (g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstPulseSink"))
187         return;
188
189     const char* role = m_player->mediaPlayerClient() && m_player->mediaPlayerClient()->mediaPlayerIsVideo()
190         ? "video" : "music";
191     GstStructure* structure = gst_structure_new("stream-properties", "media.role", G_TYPE_STRING, role, NULL);
192     g_object_set(object, "stream-properties", structure, NULL);
193     gst_structure_free(structure);
194     GUniquePtr<gchar> elementName(gst_element_get_name(GST_ELEMENT(object)));
195     LOG_MEDIA_MESSAGE("Set media.role as %s at %s", role, elementName.get());
196 }
197
198 PassOwnPtr<MediaPlayerPrivateInterface> MediaPlayerPrivateGStreamer::create(MediaPlayer* player)
199 {
200     return adoptPtr(new MediaPlayerPrivateGStreamer(player));
201 }
202
203 void MediaPlayerPrivateGStreamer::registerMediaEngine(MediaEngineRegistrar registrar)
204 {
205     if (isAvailable())
206         registrar(create, getSupportedTypes, supportsType, 0, 0, 0);
207 }
208
209 bool initializeGStreamerAndRegisterWebKitElements()
210 {
211     if (!initializeGStreamer())
212         return false;
213
214     GRefPtr<GstElementFactory> srcFactory = gst_element_factory_find("webkitwebsrc");
215     if (!srcFactory) {
216         GST_DEBUG_CATEGORY_INIT(webkit_media_player_debug, "webkitmediaplayer", 0, "WebKit media player");
217         gst_element_register(0, "webkitwebsrc", GST_RANK_PRIMARY + 100, WEBKIT_TYPE_WEB_SRC);
218     }
219
220 #if ENABLE(MEDIA_SOURCE)
221     GRefPtr<GstElementFactory> WebKitMediaSrcFactory = gst_element_factory_find("webkitmediasrc");
222     if (!WebKitMediaSrcFactory)
223         gst_element_register(0, "webkitmediasrc", GST_RANK_PRIMARY + 100, WEBKIT_TYPE_MEDIA_SRC);
224 #endif
225     return true;
226 }
227
228 bool MediaPlayerPrivateGStreamer::isAvailable()
229 {
230     if (!initializeGStreamerAndRegisterWebKitElements())
231         return false;
232
233     GRefPtr<GstElementFactory> factory = gst_element_factory_find("playbin");
234     return factory;
235 }
236
237 MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer(MediaPlayer* player)
238     : MediaPlayerPrivateGStreamerBase(player)
239     , m_source(0)
240     , m_seekTime(0)
241     , m_changingRate(false)
242     , m_endTime(numeric_limits<float>::infinity())
243     , m_isEndReached(false)
244     , m_isStreaming(false)
245     , m_mediaLocations(0)
246     , m_mediaLocationCurrentIndex(0)
247     , m_resetPipeline(false)
248     , m_paused(true)
249     , m_seeking(false)
250     , m_seekIsPending(false)
251     , m_timeOfOverlappingSeek(-1)
252     , m_buffering(false)
253     , m_playbackRate(1)
254     , m_lastPlaybackRate(1)
255     , m_errorOccured(false)
256     , m_mediaDuration(0)
257     , m_downloadFinished(false)
258     , m_fillTimer(this, &MediaPlayerPrivateGStreamer::fillTimerFired)
259     , m_maxTimeLoaded(0)
260     , m_bufferingPercentage(0)
261     , m_preload(player->preload())
262     , m_delayingLoad(false)
263     , m_mediaDurationKnown(true)
264     , m_maxTimeLoadedAtLastDidLoadingProgress(0)
265     , m_volumeAndMuteInitialized(false)
266     , m_hasVideo(false)
267     , m_hasAudio(false)
268     , m_audioTimerHandler(0)
269     , m_textTimerHandler(0)
270     , m_videoTimerHandler(0)
271     , m_videoCapsTimerHandler(0)
272     , m_readyTimerHandler(0)
273     , m_totalBytes(-1)
274     , m_preservesPitch(false)
275     , m_requestedState(GST_STATE_VOID_PENDING)
276     , m_missingPlugins(false)
277 {
278 }
279
280 MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer()
281 {
282 #if ENABLE(VIDEO_TRACK)
283     for (size_t i = 0; i < m_audioTracks.size(); ++i)
284         m_audioTracks[i]->disconnect();
285
286     for (size_t i = 0; i < m_textTracks.size(); ++i)
287         m_textTracks[i]->disconnect();
288
289     for (size_t i = 0; i < m_videoTracks.size(); ++i)
290         m_videoTracks[i]->disconnect();
291 #endif
292     if (m_fillTimer.isActive())
293         m_fillTimer.stop();
294
295     if (m_mediaLocations) {
296         gst_structure_free(m_mediaLocations);
297         m_mediaLocations = 0;
298     }
299
300     if (m_autoAudioSink)
301         g_signal_handlers_disconnect_by_func(G_OBJECT(m_autoAudioSink.get()),
302             reinterpret_cast<gpointer>(setAudioStreamPropertiesCallback), this);
303
304     if (m_readyTimerHandler)
305         g_source_remove(m_readyTimerHandler);
306
307     if (m_playBin) {
308         GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_playBin.get())));
309         ASSERT(bus);
310         g_signal_handlers_disconnect_by_func(bus.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateMessageCallback), this);
311         gst_bus_remove_signal_watch(bus.get());
312
313         g_signal_handlers_disconnect_by_func(m_playBin.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateSourceChangedCallback), this);
314         g_signal_handlers_disconnect_by_func(m_playBin.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateVideoChangedCallback), this);
315         g_signal_handlers_disconnect_by_func(m_playBin.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateAudioChangedCallback), this);
316 #if ENABLE(VIDEO_TRACK)
317         g_signal_handlers_disconnect_by_func(m_playBin.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateNewTextSampleCallback), this);
318         g_signal_handlers_disconnect_by_func(m_playBin.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateTextChangedCallback), this);
319 #endif
320
321         gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
322         m_playBin.clear();
323     }
324
325     GRefPtr<GstPad> videoSinkPad = adoptGRef(gst_element_get_static_pad(m_webkitVideoSink.get(), "sink"));
326     g_signal_handlers_disconnect_by_func(videoSinkPad.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateVideoSinkCapsChangedCallback), this);
327
328     if (m_videoTimerHandler)
329         g_source_remove(m_videoTimerHandler);
330
331     if (m_audioTimerHandler)
332         g_source_remove(m_audioTimerHandler);
333
334     if (m_textTimerHandler)
335         g_source_remove(m_textTimerHandler);
336
337     if (m_videoCapsTimerHandler)
338         g_source_remove(m_videoCapsTimerHandler);
339 }
340
341 void MediaPlayerPrivateGStreamer::load(const String& url)
342 {
343     if (!initializeGStreamerAndRegisterWebKitElements())
344         return;
345
346     URL kurl(URL(), url);
347     String cleanUrl(url);
348
349     // Clean out everything after file:// url path.
350     if (kurl.isLocalFile())
351         cleanUrl = cleanUrl.substring(0, kurl.pathEnd());
352
353     if (!m_playBin)
354         createGSTPlayBin();
355
356     ASSERT(m_playBin);
357
358     m_url = URL(URL(), cleanUrl);
359     g_object_set(m_playBin.get(), "uri", cleanUrl.utf8().data(), NULL);
360
361     INFO_MEDIA_MESSAGE("Load %s", cleanUrl.utf8().data());
362
363     if (m_preload == MediaPlayer::None) {
364         LOG_MEDIA_MESSAGE("Delaying load.");
365         m_delayingLoad = true;
366     }
367
368     // Reset network and ready states. Those will be set properly once
369     // the pipeline pre-rolled.
370     m_networkState = MediaPlayer::Loading;
371     m_player->networkStateChanged();
372     m_readyState = MediaPlayer::HaveNothing;
373     m_player->readyStateChanged();
374     m_volumeAndMuteInitialized = false;
375
376     if (!m_delayingLoad)
377         commitLoad();
378 }
379
380 #if ENABLE(MEDIA_SOURCE)
381 void MediaPlayerPrivateGStreamer::load(const String& url, PassRefPtr<HTMLMediaSource> mediaSource)
382 {
383     String mediasourceUri = String::format("mediasource%s", url.utf8().data());
384     m_mediaSource = mediaSource;
385     load(mediasourceUri);
386 }
387 #endif
388
389 void MediaPlayerPrivateGStreamer::commitLoad()
390 {
391     ASSERT(!m_delayingLoad);
392     LOG_MEDIA_MESSAGE("Committing load.");
393
394     // GStreamer needs to have the pipeline set to a paused state to
395     // start providing anything useful.
396     changePipelineState(GST_STATE_PAUSED);
397
398     setDownloadBuffering();
399     updateStates();
400 }
401
402 float MediaPlayerPrivateGStreamer::playbackPosition() const
403 {
404     if (m_isEndReached) {
405         // Position queries on a null pipeline return 0. If we're at
406         // the end of the stream the pipeline is null but we want to
407         // report either the seek time or the duration because this is
408         // what the Media element spec expects us to do.
409         if (m_seeking)
410             return m_seekTime;
411         if (m_mediaDuration)
412             return m_mediaDuration;
413         return 0;
414     }
415
416     // Position is only available if no async state change is going on and the state is either paused or playing.
417     gint64 position = GST_CLOCK_TIME_NONE;
418     GstQuery* query= gst_query_new_position(GST_FORMAT_TIME);
419     if (gst_element_query(m_playBin.get(), query))
420         gst_query_parse_position(query, 0, &position);
421
422     float result = 0.0f;
423     if (static_cast<GstClockTime>(position) != GST_CLOCK_TIME_NONE)
424         result = static_cast<double>(position) / GST_SECOND;
425     else if (m_canFallBackToLastFinishedSeekPositon)
426         result = m_seekTime;
427
428     LOG_MEDIA_MESSAGE("Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position));
429
430     gst_query_unref(query);
431
432     return result;
433 }
434
435 bool MediaPlayerPrivateGStreamer::changePipelineState(GstState newState)
436 {
437     ASSERT(m_playBin);
438
439     GstState currentState;
440     GstState pending;
441
442     gst_element_get_state(m_playBin.get(), &currentState, &pending, 0);
443     if (currentState == newState || pending == newState) {
444         LOG_MEDIA_MESSAGE("Rejected state change to %s from %s with %s pending", gst_element_state_get_name(newState),
445             gst_element_state_get_name(currentState), gst_element_state_get_name(pending));
446         return true;
447     }
448
449     LOG_MEDIA_MESSAGE("Changing state change to %s from %s with %s pending", gst_element_state_get_name(newState),
450         gst_element_state_get_name(currentState), gst_element_state_get_name(pending));
451
452     GstStateChangeReturn setStateResult = gst_element_set_state(m_playBin.get(), newState);
453     GstState pausedOrPlaying = newState == GST_STATE_PLAYING ? GST_STATE_PAUSED : GST_STATE_PLAYING;
454     if (currentState != pausedOrPlaying && setStateResult == GST_STATE_CHANGE_FAILURE) {
455         return false;
456     }
457
458     // Create a timer when entering the READY state so that we can free resources
459     // if we stay for too long on READY.
460     // Also lets remove the timer if we request a state change for any state other than READY.
461     // See also https://bugs.webkit.org/show_bug.cgi?id=117354
462     if (newState == GST_STATE_READY && !m_readyTimerHandler) {
463         m_readyTimerHandler = g_timeout_add_seconds(gReadyStateTimerInterval, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateReadyStateTimeoutCallback), this);
464         g_source_set_name_by_id(m_readyTimerHandler, "[WebKit] mediaPlayerPrivateReadyStateTimeoutCallback");
465     } else if (newState != GST_STATE_READY && m_readyTimerHandler) {
466         g_source_remove(m_readyTimerHandler);
467         m_readyTimerHandler = 0;
468     }
469
470     return true;
471 }
472
473 void MediaPlayerPrivateGStreamer::prepareToPlay()
474 {
475     m_preload = MediaPlayer::Auto;
476     if (m_delayingLoad) {
477         m_delayingLoad = false;
478         commitLoad();
479     }
480 }
481
482 void MediaPlayerPrivateGStreamer::play()
483 {
484     if (changePipelineState(GST_STATE_PLAYING)) {
485         m_isEndReached = false;
486         m_delayingLoad = false;
487         m_preload = MediaPlayer::Auto;
488         setDownloadBuffering();
489         LOG_MEDIA_MESSAGE("Play");
490     } else {
491         loadingFailed(MediaPlayer::Empty);
492     }
493 }
494
495 void MediaPlayerPrivateGStreamer::pause()
496 {
497     GstState currentState, pendingState;
498     gst_element_get_state(m_playBin.get(), &currentState, &pendingState, 0);
499     if (currentState < GST_STATE_PAUSED && pendingState <= GST_STATE_PAUSED)
500         return;
501
502     if (changePipelineState(GST_STATE_PAUSED))
503         INFO_MEDIA_MESSAGE("Pause");
504     else
505         loadingFailed(MediaPlayer::Empty);
506 }
507
508 float MediaPlayerPrivateGStreamer::duration() const
509 {
510     if (!m_playBin)
511         return 0.0f;
512
513     if (m_errorOccured)
514         return 0.0f;
515
516     // Media duration query failed already, don't attempt new useless queries.
517     if (!m_mediaDurationKnown)
518         return numeric_limits<float>::infinity();
519
520     if (m_mediaDuration)
521         return m_mediaDuration;
522
523     GstFormat timeFormat = GST_FORMAT_TIME;
524     gint64 timeLength = 0;
525
526     bool failure = !gst_element_query_duration(m_playBin.get(), timeFormat, &timeLength) || static_cast<guint64>(timeLength) == GST_CLOCK_TIME_NONE;
527     if (failure) {
528         LOG_MEDIA_MESSAGE("Time duration query failed for %s", m_url.string().utf8().data());
529         return numeric_limits<float>::infinity();
530     }
531
532     LOG_MEDIA_MESSAGE("Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(timeLength));
533
534     m_mediaDuration = static_cast<double>(timeLength) / GST_SECOND;
535     return m_mediaDuration;
536     // FIXME: handle 3.14.9.5 properly
537 }
538
539 float MediaPlayerPrivateGStreamer::currentTime() const
540 {
541     if (!m_playBin)
542         return 0.0f;
543
544     if (m_errorOccured)
545         return 0.0f;
546
547     if (m_seeking)
548         return m_seekTime;
549
550     // Workaround for
551     // https://bugzilla.gnome.org/show_bug.cgi?id=639941 In GStreamer
552     // 0.10.35 basesink reports wrong duration in case of EOS and
553     // negative playback rate. There's no upstream accepted patch for
554     // this bug yet, hence this temporary workaround.
555     if (m_isEndReached && m_playbackRate < 0)
556         return 0.0f;
557
558     return playbackPosition();
559 }
560
561 void MediaPlayerPrivateGStreamer::seek(float time)
562 {
563     if (!m_playBin)
564         return;
565
566     if (m_errorOccured)
567         return;
568
569     INFO_MEDIA_MESSAGE("[Seek] seek attempt to %f secs", time);
570
571     // Avoid useless seeking.
572     if (time == currentTime())
573         return;
574
575     if (isLiveStream())
576         return;
577
578     GstClockTime clockTime = toGstClockTime(time);
579     INFO_MEDIA_MESSAGE("[Seek] seeking to %" GST_TIME_FORMAT " (%f)", GST_TIME_ARGS(clockTime), time);
580
581     if (m_seeking) {
582         m_timeOfOverlappingSeek = time;
583         if (m_seekIsPending) {
584             m_seekTime = time;
585             return;
586         }
587     }
588
589     GstState state;
590     GstStateChangeReturn getStateResult = gst_element_get_state(m_playBin.get(), &state, 0, 0);
591     if (getStateResult == GST_STATE_CHANGE_FAILURE || getStateResult == GST_STATE_CHANGE_NO_PREROLL) {
592         LOG_MEDIA_MESSAGE("[Seek] cannot seek, current state change is %s", gst_element_state_change_return_get_name(getStateResult));
593         return;
594     }
595     if (getStateResult == GST_STATE_CHANGE_ASYNC || state < GST_STATE_PAUSED || m_isEndReached) {
596         m_seekIsPending = true;
597         if (m_isEndReached) {
598             LOG_MEDIA_MESSAGE("[Seek] reset pipeline");
599             m_resetPipeline = true;
600             if (!changePipelineState(GST_STATE_PAUSED))
601                 loadingFailed(MediaPlayer::Empty);
602         }
603     } else {
604         // We can seek now.
605         if (!doSeek(clockTime, m_player->rate(), static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE))) {
606             LOG_MEDIA_MESSAGE("[Seek] seeking to %f failed", time);
607             return;
608         }
609     }
610
611     m_seeking = true;
612     m_seekTime = time;
613     m_isEndReached = false;
614 }
615
616 bool MediaPlayerPrivateGStreamer::doSeek(gint64 position, float rate, GstSeekFlags seekType)
617 {
618     gint64 startTime, endTime;
619
620     if (rate > 0) {
621         startTime = position;
622         endTime = GST_CLOCK_TIME_NONE;
623     } else {
624         startTime = 0;
625         // If we are at beginning of media, start from the end to
626         // avoid immediate EOS.
627         if (position < 0)
628             endTime = static_cast<gint64>(duration() * GST_SECOND);
629         else
630             endTime = position;
631     }
632
633     return gst_element_seek(m_playBin.get(), rate, GST_FORMAT_TIME, seekType,
634         GST_SEEK_TYPE_SET, startTime, GST_SEEK_TYPE_SET, endTime);
635 }
636
637 void MediaPlayerPrivateGStreamer::updatePlaybackRate()
638 {
639     if (!m_changingRate)
640         return;
641
642     float currentPosition = static_cast<float>(playbackPosition() * GST_SECOND);
643     bool mute = false;
644
645     INFO_MEDIA_MESSAGE("Set Rate to %f", m_playbackRate);
646
647     if (m_playbackRate > 0) {
648         // Mute the sound if the playback rate is too extreme and
649         // audio pitch is not adjusted.
650         mute = (!m_preservesPitch && (m_playbackRate < 0.8 || m_playbackRate > 2));
651     } else {
652         if (currentPosition == 0.0f)
653             currentPosition = -1.0f;
654         mute = true;
655     }
656
657     INFO_MEDIA_MESSAGE("Need to mute audio?: %d", (int) mute);
658     if (doSeek(currentPosition, m_playbackRate, static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH))) {
659         g_object_set(m_playBin.get(), "mute", mute, NULL);
660         m_lastPlaybackRate = m_playbackRate;
661     } else {
662         m_playbackRate = m_lastPlaybackRate;
663         ERROR_MEDIA_MESSAGE("Set rate to %f failed", m_playbackRate);
664     }
665     m_changingRate = false;
666     m_player->rateChanged();
667 }
668
669 bool MediaPlayerPrivateGStreamer::paused() const
670 {
671     if (m_isEndReached) {
672         LOG_MEDIA_MESSAGE("Ignoring pause at EOS");
673         return true;
674     }
675
676     GstState state;
677     gst_element_get_state(m_playBin.get(), &state, 0, 0);
678     return state == GST_STATE_PAUSED;
679 }
680
681 bool MediaPlayerPrivateGStreamer::seeking() const
682 {
683     return m_seeking;
684 }
685
686 void MediaPlayerPrivateGStreamer::videoChanged()
687 {
688     if (m_videoTimerHandler)
689         g_source_remove(m_videoTimerHandler);
690     m_videoTimerHandler = g_idle_add_full(G_PRIORITY_DEFAULT, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVideoChangeTimeoutCallback), this, 0);
691 }
692
693 void MediaPlayerPrivateGStreamer::videoCapsChanged()
694 {
695     if (m_videoCapsTimerHandler)
696         g_source_remove(m_videoCapsTimerHandler);
697     m_videoCapsTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVideoCapsChangeTimeoutCallback), this);
698 }
699
700 void MediaPlayerPrivateGStreamer::notifyPlayerOfVideo()
701 {
702     m_videoTimerHandler = 0;
703
704     gint numTracks = 0;
705     if (m_playBin)
706         g_object_get(m_playBin.get(), "n-video", &numTracks, NULL);
707
708     m_hasVideo = numTracks > 0;
709
710 #if ENABLE(VIDEO_TRACK)
711     for (gint i = 0; i < numTracks; ++i) {
712         GRefPtr<GstPad> pad;
713         g_signal_emit_by_name(m_playBin.get(), "get-video-pad", i, &pad.outPtr(), NULL);
714         ASSERT(pad);
715
716         if (i < static_cast<gint>(m_videoTracks.size())) {
717             RefPtr<VideoTrackPrivateGStreamer> existingTrack = m_videoTracks[i];
718             existingTrack->setIndex(i);
719             if (existingTrack->pad() == pad)
720                 continue;
721         }
722
723         RefPtr<VideoTrackPrivateGStreamer> track = VideoTrackPrivateGStreamer::create(m_playBin, i, pad);
724         m_videoTracks.append(track);
725         m_player->addVideoTrack(track.release());
726     }
727
728     while (static_cast<gint>(m_videoTracks.size()) > numTracks) {
729         RefPtr<VideoTrackPrivateGStreamer> track = m_videoTracks.last();
730         track->disconnect();
731         m_videoTracks.removeLast();
732         m_player->removeVideoTrack(track.release());
733     }
734 #endif
735
736     m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player);
737 }
738
739 void MediaPlayerPrivateGStreamer::notifyPlayerOfVideoCaps()
740 {
741     m_videoCapsTimerHandler = 0;
742     m_videoSize = IntSize();
743     m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player);
744 }
745
746 void MediaPlayerPrivateGStreamer::audioChanged()
747 {
748     if (m_audioTimerHandler)
749         g_source_remove(m_audioTimerHandler);
750     m_audioTimerHandler = g_idle_add_full(G_PRIORITY_DEFAULT, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateAudioChangeTimeoutCallback), this, 0);
751 }
752
753 void MediaPlayerPrivateGStreamer::notifyPlayerOfAudio()
754 {
755     m_audioTimerHandler = 0;
756
757     gint numTracks = 0;
758     if (m_playBin)
759         g_object_get(m_playBin.get(), "n-audio", &numTracks, NULL);
760
761     m_hasAudio = numTracks > 0;
762
763 #if ENABLE(VIDEO_TRACK)
764     for (gint i = 0; i < numTracks; ++i) {
765         GRefPtr<GstPad> pad;
766         g_signal_emit_by_name(m_playBin.get(), "get-audio-pad", i, &pad.outPtr(), NULL);
767         ASSERT(pad);
768
769         if (i < static_cast<gint>(m_audioTracks.size())) {
770             RefPtr<AudioTrackPrivateGStreamer> existingTrack = m_audioTracks[i];
771             existingTrack->setIndex(i);
772             if (existingTrack->pad() == pad)
773                 continue;
774         }
775
776         RefPtr<AudioTrackPrivateGStreamer> track = AudioTrackPrivateGStreamer::create(m_playBin, i, pad);
777         m_audioTracks.insert(i, track);
778         m_player->addAudioTrack(track.release());
779     }
780
781     while (static_cast<gint>(m_audioTracks.size()) > numTracks) {
782         RefPtr<AudioTrackPrivateGStreamer> track = m_audioTracks.last();
783         track->disconnect();
784         m_audioTracks.removeLast();
785         m_player->removeAudioTrack(track.release());
786     }
787 #endif
788
789     m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player);
790 }
791
792 #if ENABLE(VIDEO_TRACK)
793 void MediaPlayerPrivateGStreamer::textChanged()
794 {
795     if (m_textTimerHandler)
796         g_source_remove(m_textTimerHandler);
797     m_textTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateTextChangeTimeoutCallback), this);
798 }
799
800 void MediaPlayerPrivateGStreamer::notifyPlayerOfText()
801 {
802     m_textTimerHandler = 0;
803
804     gint numTracks = 0;
805     if (m_playBin)
806         g_object_get(m_playBin.get(), "n-text", &numTracks, NULL);
807
808     for (gint i = 0; i < numTracks; ++i) {
809         GRefPtr<GstPad> pad;
810         g_signal_emit_by_name(m_playBin.get(), "get-text-pad", i, &pad.outPtr(), NULL);
811         ASSERT(pad);
812
813         if (i < static_cast<gint>(m_textTracks.size())) {
814             RefPtr<InbandTextTrackPrivateGStreamer> existingTrack = m_textTracks[i];
815             existingTrack->setIndex(i);
816             if (existingTrack->pad() == pad)
817                 continue;
818         }
819
820         RefPtr<InbandTextTrackPrivateGStreamer> track = InbandTextTrackPrivateGStreamer::create(i, pad);
821         m_textTracks.insert(i, track);
822         m_player->addTextTrack(track.release());
823     }
824
825     while (static_cast<gint>(m_textTracks.size()) > numTracks) {
826         RefPtr<InbandTextTrackPrivateGStreamer> track = m_textTracks.last();
827         track->disconnect();
828         m_textTracks.removeLast();
829         m_player->removeTextTrack(track.release());
830     }
831 }
832
833 void MediaPlayerPrivateGStreamer::newTextSample()
834 {
835     if (!m_textAppSink)
836         return;
837
838     GRefPtr<GstEvent> streamStartEvent = adoptGRef(
839         gst_pad_get_sticky_event(m_textAppSinkPad.get(), GST_EVENT_STREAM_START, 0));
840
841     GRefPtr<GstSample> sample;
842     g_signal_emit_by_name(m_textAppSink.get(), "pull-sample", &sample.outPtr(), NULL);
843     ASSERT(sample);
844
845     if (streamStartEvent) {
846         bool found = FALSE;
847         const gchar* id;
848         gst_event_parse_stream_start(streamStartEvent.get(), &id);
849         for (size_t i = 0; i < m_textTracks.size(); ++i) {
850             RefPtr<InbandTextTrackPrivateGStreamer> track = m_textTracks[i];
851             if (track->streamId() == id) {
852                 track->handleSample(sample);
853                 found = true;
854                 break;
855             }
856         }
857         if (!found)
858             WARN_MEDIA_MESSAGE("Got sample with unknown stream ID.");
859     } else
860         WARN_MEDIA_MESSAGE("Unable to handle sample with no stream start event.");
861 }
862 #endif
863
864 void MediaPlayerPrivateGStreamer::setRate(float rate)
865 {
866     // Avoid useless playback rate update.
867     if (m_playbackRate == rate) {
868         // and make sure that upper layers were notified if rate was set
869
870         if (!m_changingRate && m_player->rate() != m_playbackRate)
871             m_player->rateChanged();
872         return;
873     }
874
875     if (isLiveStream()) {
876         // notify upper layers that we cannot handle passed rate.
877         m_changingRate = false;
878         m_player->rateChanged();
879         return;
880     }
881
882     GstState state;
883     GstState pending;
884
885     m_playbackRate = rate;
886     m_changingRate = true;
887
888     gst_element_get_state(m_playBin.get(), &state, &pending, 0);
889     if ((state != GST_STATE_PLAYING && state != GST_STATE_PAUSED)
890         || (pending == GST_STATE_PAUSED))
891         return;
892
893     if (!rate) {
894         changePipelineState(GST_STATE_PAUSED);
895         return;
896     }
897
898     updatePlaybackRate();
899 }
900
901 void MediaPlayerPrivateGStreamer::setPreservesPitch(bool preservesPitch)
902 {
903     m_preservesPitch = preservesPitch;
904 }
905
906 PassRefPtr<TimeRanges> MediaPlayerPrivateGStreamer::buffered() const
907 {
908     RefPtr<TimeRanges> timeRanges = TimeRanges::create();
909     if (m_errorOccured || isLiveStream())
910         return timeRanges.release();
911
912 #if GST_CHECK_VERSION(0, 10, 31)
913     float mediaDuration(duration());
914     if (!mediaDuration || std::isinf(mediaDuration))
915         return timeRanges.release();
916
917     GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT);
918
919     if (!gst_element_query(m_playBin.get(), query)) {
920         gst_query_unref(query);
921         return timeRanges.release();
922     }
923
924     for (guint index = 0; index < gst_query_get_n_buffering_ranges(query); index++) {
925         gint64 rangeStart = 0, rangeStop = 0;
926         if (gst_query_parse_nth_buffering_range(query, index, &rangeStart, &rangeStop))
927             timeRanges->add(static_cast<float>((rangeStart * mediaDuration) / GST_FORMAT_PERCENT_MAX),
928                 static_cast<float>((rangeStop * mediaDuration) / GST_FORMAT_PERCENT_MAX));
929     }
930
931     // Fallback to the more general maxTimeLoaded() if no range has
932     // been found.
933     if (!timeRanges->length())
934         if (float loaded = maxTimeLoaded())
935             timeRanges->add(0, loaded);
936
937     gst_query_unref(query);
938 #else
939     float loaded = maxTimeLoaded();
940     if (!m_errorOccured && !isLiveStream() && loaded > 0)
941         timeRanges->add(0, loaded);
942 #endif
943     return timeRanges.release();
944 }
945
946 gboolean MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message)
947 {
948     GOwnPtr<GError> err;
949     GOwnPtr<gchar> debug;
950     MediaPlayer::NetworkState error;
951     bool issueError = true;
952     bool attemptNextLocation = false;
953     const GstStructure* structure = gst_message_get_structure(message);
954     GstState requestedState, currentState;
955
956     m_canFallBackToLastFinishedSeekPositon = false;
957
958     if (structure) {
959         const gchar* messageTypeName = gst_structure_get_name(structure);
960
961         // Redirect messages are sent from elements, like qtdemux, to
962         // notify of the new location(s) of the media.
963         if (!g_strcmp0(messageTypeName, "redirect")) {
964             mediaLocationChanged(message);
965             return TRUE;
966         }
967     }
968
969     // We ignore state changes from internal elements. They are forwarded to playbin2 anyway.
970     bool messageSourceIsPlaybin = GST_MESSAGE_SRC(message) == reinterpret_cast<GstObject*>(m_playBin.get());
971
972     LOG_MEDIA_MESSAGE("Message %s received from element %s", GST_MESSAGE_TYPE_NAME(message), GST_MESSAGE_SRC_NAME(message));
973     switch (GST_MESSAGE_TYPE(message)) {
974     case GST_MESSAGE_ERROR:
975         if (m_resetPipeline)
976             break;
977         if (m_missingPlugins)
978             break;
979         gst_message_parse_error(message, &err.outPtr(), &debug.outPtr());
980         ERROR_MEDIA_MESSAGE("Error %d: %s (url=%s)", err->code, err->message, m_url.string().utf8().data());
981
982         GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_playBin.get()), GST_DEBUG_GRAPH_SHOW_ALL, "webkit-video.error");
983
984         error = MediaPlayer::Empty;
985         if (err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND
986             || err->code == GST_STREAM_ERROR_WRONG_TYPE
987             || err->code == GST_STREAM_ERROR_FAILED
988             || err->code == GST_CORE_ERROR_MISSING_PLUGIN
989             || err->code == GST_RESOURCE_ERROR_NOT_FOUND)
990             error = MediaPlayer::FormatError;
991         else if (err->domain == GST_STREAM_ERROR) {
992             // Let the mediaPlayerClient handle the stream error, in
993             // this case the HTMLMediaElement will emit a stalled
994             // event.
995             if (err->code == GST_STREAM_ERROR_TYPE_NOT_FOUND) {
996                 ERROR_MEDIA_MESSAGE("Decode error, let the Media element emit a stalled event.");
997                 break;
998             }
999             error = MediaPlayer::DecodeError;
1000             attemptNextLocation = true;
1001         } else if (err->domain == GST_RESOURCE_ERROR)
1002             error = MediaPlayer::NetworkError;
1003
1004         if (attemptNextLocation)
1005             issueError = !loadNextLocation();
1006         if (issueError)
1007             loadingFailed(error);
1008         break;
1009     case GST_MESSAGE_EOS:
1010         didEnd();
1011         break;
1012     case GST_MESSAGE_ASYNC_DONE:
1013         if (!messageSourceIsPlaybin || m_delayingLoad)
1014             break;
1015         asyncStateChangeDone();
1016         break;
1017     case GST_MESSAGE_STATE_CHANGED: {
1018         if (!messageSourceIsPlaybin || m_delayingLoad)
1019             break;
1020         updateStates();
1021
1022         // Construct a filename for the graphviz dot file output.
1023         GstState newState;
1024         gst_message_parse_state_changed(message, &currentState, &newState, 0);
1025         CString dotFileName = String::format("webkit-video.%s_%s", gst_element_state_get_name(currentState), gst_element_state_get_name(newState)).utf8();
1026         GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_playBin.get()), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.data());
1027
1028         break;
1029     }
1030     case GST_MESSAGE_BUFFERING:
1031         processBufferingStats(message);
1032         break;
1033     case GST_MESSAGE_DURATION_CHANGED:
1034         if (messageSourceIsPlaybin)
1035             durationChanged();
1036         break;
1037     case GST_MESSAGE_REQUEST_STATE:
1038         gst_message_parse_request_state(message, &requestedState);
1039         gst_element_get_state(m_playBin.get(), &currentState, NULL, 250);
1040         if (requestedState < currentState) {
1041             GUniquePtr<gchar> elementName(gst_element_get_name(GST_ELEMENT(message)));
1042             INFO_MEDIA_MESSAGE("Element %s requested state change to %s", elementName.get(),
1043                 gst_element_state_get_name(requestedState));
1044             m_requestedState = requestedState;
1045             if (!changePipelineState(requestedState))
1046                 loadingFailed(MediaPlayer::Empty);
1047         }
1048         break;
1049     case GST_MESSAGE_ELEMENT:
1050         if (gst_is_missing_plugin_message(message)) {
1051             gchar* detail = gst_missing_plugin_message_get_installer_detail(message);
1052             gchar* detailArray[2] = {detail, 0};
1053             GstInstallPluginsReturn result = gst_install_plugins_async(detailArray, 0, mediaPlayerPrivatePluginInstallerResultFunction, this);
1054             m_missingPlugins = result == GST_INSTALL_PLUGINS_STARTED_OK;
1055             g_free(detail);
1056         }
1057         break;
1058 #if ENABLE(VIDEO_TRACK)
1059     case GST_MESSAGE_TOC:
1060         processTableOfContents(message);
1061         break;
1062 #endif
1063     default:
1064         LOG_MEDIA_MESSAGE("Unhandled GStreamer message type: %s",
1065                     GST_MESSAGE_TYPE_NAME(message));
1066         break;
1067     }
1068     return TRUE;
1069 }
1070
1071 void MediaPlayerPrivateGStreamer::handlePluginInstallerResult(GstInstallPluginsReturn result)
1072 {
1073     m_missingPlugins = false;
1074     if (result == GST_INSTALL_PLUGINS_SUCCESS) {
1075         changePipelineState(GST_STATE_READY);
1076         changePipelineState(GST_STATE_PAUSED);
1077     }
1078 }
1079
1080 void MediaPlayerPrivateGStreamer::processBufferingStats(GstMessage* message)
1081 {
1082     m_buffering = true;
1083     const GstStructure *structure = gst_message_get_structure(message);
1084     gst_structure_get_int(structure, "buffer-percent", &m_bufferingPercentage);
1085
1086     LOG_MEDIA_MESSAGE("[Buffering] Buffering: %d%%.", m_bufferingPercentage);
1087
1088     updateStates();
1089 }
1090
1091 #if ENABLE(VIDEO_TRACK)
1092 void MediaPlayerPrivateGStreamer::processTableOfContents(GstMessage* message)
1093 {
1094     if (m_chaptersTrack)
1095         m_player->removeTextTrack(m_chaptersTrack);
1096
1097     m_chaptersTrack = InbandMetadataTextTrackPrivateGStreamer::create(InbandTextTrackPrivate::Chapters);
1098     m_player->addTextTrack(m_chaptersTrack);
1099
1100     GRefPtr<GstToc> toc;
1101     gboolean updated;
1102     gst_message_parse_toc(message, &toc.outPtr(), &updated);
1103     ASSERT(toc);
1104
1105     for (GList* i = gst_toc_get_entries(toc.get()); i; i = i->next)
1106         processTableOfContentsEntry(static_cast<GstTocEntry*>(i->data), 0);
1107 }
1108
1109 void MediaPlayerPrivateGStreamer::processTableOfContentsEntry(GstTocEntry* entry, GstTocEntry* parent)
1110 {
1111     UNUSED_PARAM(parent);
1112     ASSERT(entry);
1113
1114     RefPtr<GenericCueData> cue = GenericCueData::create();
1115
1116     gint64 start = -1, stop = -1;
1117     gst_toc_entry_get_start_stop_times(entry, &start, &stop);
1118     if (start != -1)
1119         cue->setStartTime(static_cast<double>(start) / GST_SECOND);
1120     if (stop != -1)
1121         cue->setEndTime(static_cast<double>(stop) / GST_SECOND);
1122
1123     GstTagList* tags = gst_toc_entry_get_tags(entry);
1124     if (tags) {
1125         gchar* title =  0;
1126         gst_tag_list_get_string(tags, GST_TAG_TITLE, &title);
1127         if (title) {
1128             cue->setContent(title);
1129             g_free(title);
1130         }
1131     }
1132
1133     m_chaptersTrack->client()->addGenericCue(m_chaptersTrack.get(), cue.release());
1134
1135     for (GList* i = gst_toc_entry_get_sub_entries(entry); i; i = i->next)
1136         processTableOfContentsEntry(static_cast<GstTocEntry*>(i->data), entry);
1137 }
1138 #endif
1139
1140 void MediaPlayerPrivateGStreamer::fillTimerFired(Timer<MediaPlayerPrivateGStreamer>*)
1141 {
1142     GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1143
1144     if (!gst_element_query(m_playBin.get(), query)) {
1145         gst_query_unref(query);
1146         return;
1147     }
1148
1149     gint64 start, stop;
1150     gdouble fillStatus = 100.0;
1151
1152     gst_query_parse_buffering_range(query, 0, &start, &stop, 0);
1153     gst_query_unref(query);
1154
1155     if (stop != -1)
1156         fillStatus = 100.0 * stop / GST_FORMAT_PERCENT_MAX;
1157
1158     LOG_MEDIA_MESSAGE("[Buffering] Download buffer filled up to %f%%", fillStatus);
1159
1160     if (!m_mediaDuration)
1161         durationChanged();
1162
1163     // Update maxTimeLoaded only if the media duration is
1164     // available. Otherwise we can't compute it.
1165     if (m_mediaDuration) {
1166         if (fillStatus == 100.0)
1167             m_maxTimeLoaded = m_mediaDuration;
1168         else
1169             m_maxTimeLoaded = static_cast<float>((fillStatus * m_mediaDuration) / 100.0);
1170         LOG_MEDIA_MESSAGE("[Buffering] Updated maxTimeLoaded: %f", m_maxTimeLoaded);
1171     }
1172
1173     m_downloadFinished = fillStatus == 100.0;
1174     if (!m_downloadFinished) {
1175         updateStates();
1176         return;
1177     }
1178
1179     // Media is now fully loaded. It will play even if network
1180     // connection is cut. Buffering is done, remove the fill source
1181     // from the main loop.
1182     m_fillTimer.stop();
1183     updateStates();
1184 }
1185
1186 float MediaPlayerPrivateGStreamer::maxTimeSeekable() const
1187 {
1188     if (m_errorOccured)
1189         return 0.0f;
1190
1191     LOG_MEDIA_MESSAGE("maxTimeSeekable");
1192     // infinite duration means live stream
1193     if (std::isinf(duration()))
1194         return 0.0f;
1195
1196     return duration();
1197 }
1198
1199 float MediaPlayerPrivateGStreamer::maxTimeLoaded() const
1200 {
1201     if (m_errorOccured)
1202         return 0.0f;
1203
1204     float loaded = m_maxTimeLoaded;
1205     if (m_isEndReached && m_mediaDuration)
1206         loaded = m_mediaDuration;
1207     LOG_MEDIA_MESSAGE("maxTimeLoaded: %f", loaded);
1208     return loaded;
1209 }
1210
1211 bool MediaPlayerPrivateGStreamer::didLoadingProgress() const
1212 {
1213     if (!m_playBin || !m_mediaDuration || !totalBytes())
1214         return false;
1215     float currentMaxTimeLoaded = maxTimeLoaded();
1216     bool didLoadingProgress = currentMaxTimeLoaded != m_maxTimeLoadedAtLastDidLoadingProgress;
1217     m_maxTimeLoadedAtLastDidLoadingProgress = currentMaxTimeLoaded;
1218     LOG_MEDIA_MESSAGE("didLoadingProgress: %d", didLoadingProgress);
1219     return didLoadingProgress;
1220 }
1221
1222 unsigned MediaPlayerPrivateGStreamer::totalBytes() const
1223 {
1224     if (m_errorOccured)
1225         return 0;
1226
1227     if (m_totalBytes != -1)
1228         return m_totalBytes;
1229
1230     if (!m_source)
1231         return 0;
1232
1233     GstFormat fmt = GST_FORMAT_BYTES;
1234     gint64 length = 0;
1235     if (gst_element_query_duration(m_source.get(), fmt, &length)) {
1236         INFO_MEDIA_MESSAGE("totalBytes %" G_GINT64_FORMAT, length);
1237         m_totalBytes = static_cast<unsigned>(length);
1238         m_isStreaming = !length;
1239         return m_totalBytes;
1240     }
1241
1242     // Fall back to querying the source pads manually.
1243     // See also https://bugzilla.gnome.org/show_bug.cgi?id=638749
1244     GstIterator* iter = gst_element_iterate_src_pads(m_source.get());
1245     bool done = false;
1246     while (!done) {
1247         GValue item = G_VALUE_INIT;
1248         switch (gst_iterator_next(iter, &item)) {
1249         case GST_ITERATOR_OK: {
1250             GstPad* pad = static_cast<GstPad*>(g_value_get_object(&item));
1251             gint64 padLength = 0;
1252             if (gst_pad_query_duration(pad, fmt, &padLength) && padLength > length)
1253                 length = padLength;
1254             break;
1255         }
1256         case GST_ITERATOR_RESYNC:
1257             gst_iterator_resync(iter);
1258             break;
1259         case GST_ITERATOR_ERROR:
1260             // Fall through.
1261         case GST_ITERATOR_DONE:
1262             done = true;
1263             break;
1264         }
1265
1266         g_value_unset(&item);
1267     }
1268
1269     gst_iterator_free(iter);
1270
1271     INFO_MEDIA_MESSAGE("totalBytes %" G_GINT64_FORMAT, length);
1272     m_totalBytes = static_cast<unsigned>(length);
1273     m_isStreaming = !length;
1274     return m_totalBytes;
1275 }
1276
1277 void MediaPlayerPrivateGStreamer::sourceChanged()
1278 {
1279     m_source.clear();
1280     g_object_get(m_playBin.get(), "source", &m_source.outPtr(), NULL);
1281
1282     if (WEBKIT_IS_WEB_SRC(m_source.get()))
1283         webKitWebSrcSetMediaPlayer(WEBKIT_WEB_SRC(m_source.get()), m_player);
1284 #if ENABLE(MEDIA_SOURCE)
1285     if (m_mediaSource && WEBKIT_IS_MEDIA_SRC(m_source.get())) {
1286         MediaSourceGStreamer::open(m_mediaSource.get(), WEBKIT_MEDIA_SRC(m_source.get()));
1287         webKitMediaSrcSetPlayBin(WEBKIT_MEDIA_SRC(m_source.get()), m_playBin.get());
1288     }
1289 #endif
1290 }
1291
1292 void MediaPlayerPrivateGStreamer::cancelLoad()
1293 {
1294     if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
1295         return;
1296
1297     if (m_playBin)
1298         changePipelineState(GST_STATE_READY);
1299 }
1300
1301 void MediaPlayerPrivateGStreamer::asyncStateChangeDone()
1302 {
1303     if (!m_playBin || m_errorOccured)
1304         return;
1305
1306     if (m_seeking) {
1307         if (m_seekIsPending)
1308             updateStates();
1309         else {
1310             LOG_MEDIA_MESSAGE("[Seek] seeked to %f", m_seekTime);
1311             m_seeking = false;
1312             if (m_timeOfOverlappingSeek != m_seekTime && m_timeOfOverlappingSeek != -1) {
1313                 seek(m_timeOfOverlappingSeek);
1314                 m_timeOfOverlappingSeek = -1;
1315                 return;
1316             }
1317             m_timeOfOverlappingSeek = -1;
1318
1319             // The pipeline can still have a pending state. In this case a position query will fail.
1320             // Right now we can use m_seekTime as a fallback.
1321             m_canFallBackToLastFinishedSeekPositon = true;
1322             timeChanged();
1323         }
1324     } else
1325         updateStates();
1326 }
1327
1328 void MediaPlayerPrivateGStreamer::updateStates()
1329 {
1330     if (!m_playBin)
1331         return;
1332
1333     if (m_errorOccured)
1334         return;
1335
1336     MediaPlayer::NetworkState oldNetworkState = m_networkState;
1337     MediaPlayer::ReadyState oldReadyState = m_readyState;
1338     GstState state;
1339     GstState pending;
1340
1341     GstStateChangeReturn getStateResult = gst_element_get_state(m_playBin.get(), &state, &pending, 250 * GST_NSECOND);
1342
1343     bool shouldUpdatePlaybackState = false;
1344     switch (getStateResult) {
1345     case GST_STATE_CHANGE_SUCCESS: {
1346         LOG_MEDIA_MESSAGE("State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending));
1347
1348         // Do nothing if on EOS and state changed to READY to avoid recreating the player
1349         // on HTMLMediaElement and properly generate the video 'ended' event.
1350         if (m_isEndReached && state == GST_STATE_READY)
1351             break;
1352
1353         if (state <= GST_STATE_READY) {
1354             m_resetPipeline = true;
1355             m_mediaDuration = 0;
1356         } else {
1357             m_resetPipeline = false;
1358             cacheDuration();
1359         }
1360
1361         bool didBuffering = m_buffering;
1362
1363         // Update ready and network states.
1364         switch (state) {
1365         case GST_STATE_NULL:
1366             m_readyState = MediaPlayer::HaveNothing;
1367             m_networkState = MediaPlayer::Empty;
1368             break;
1369         case GST_STATE_READY:
1370             m_readyState = MediaPlayer::HaveMetadata;
1371             m_networkState = MediaPlayer::Empty;
1372             break;
1373         case GST_STATE_PAUSED:
1374         case GST_STATE_PLAYING:
1375             if (m_buffering) {
1376                 if (m_bufferingPercentage == 100) {
1377                     LOG_MEDIA_MESSAGE("[Buffering] Complete.");
1378                     m_buffering = false;
1379                     m_readyState = MediaPlayer::HaveEnoughData;
1380                     m_networkState = m_downloadFinished ? MediaPlayer::Idle : MediaPlayer::Loading;
1381                 } else {
1382                     m_readyState = MediaPlayer::HaveCurrentData;
1383                     m_networkState = MediaPlayer::Loading;
1384                 }
1385             } else if (m_downloadFinished) {
1386                 m_readyState = MediaPlayer::HaveEnoughData;
1387                 m_networkState = MediaPlayer::Loaded;
1388             } else {
1389                 m_readyState = MediaPlayer::HaveFutureData;
1390                 m_networkState = MediaPlayer::Loading;
1391             }
1392
1393             break;
1394         default:
1395             ASSERT_NOT_REACHED();
1396             break;
1397         }
1398
1399         // Sync states where needed.
1400         if (state == GST_STATE_PAUSED) {
1401             if (!m_volumeAndMuteInitialized) {
1402                 notifyPlayerOfVolumeChange();
1403                 notifyPlayerOfMute();
1404                 m_volumeAndMuteInitialized = true;
1405             }
1406
1407             if (didBuffering && !m_buffering && !m_paused) {
1408                 LOG_MEDIA_MESSAGE("[Buffering] Restarting playback.");
1409                 changePipelineState(GST_STATE_PLAYING);
1410             }
1411         } else if (state == GST_STATE_PLAYING) {
1412             m_paused = false;
1413
1414             if (m_buffering && !isLiveStream()) {
1415                 LOG_MEDIA_MESSAGE("[Buffering] Pausing stream for buffering.");
1416                 changePipelineState(GST_STATE_PAUSED);
1417             }
1418         } else
1419             m_paused = true;
1420
1421         if (m_requestedState == GST_STATE_PAUSED && state == GST_STATE_PAUSED) {
1422             shouldUpdatePlaybackState = true;
1423             LOG_MEDIA_MESSAGE("Requested state change to %s was completed", gst_element_state_get_name(state));
1424         }
1425
1426         break;
1427     }
1428     case GST_STATE_CHANGE_ASYNC:
1429         LOG_MEDIA_MESSAGE("Async: State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending));
1430         // Change in progress.
1431         break;
1432     case GST_STATE_CHANGE_FAILURE:
1433         LOG_MEDIA_MESSAGE("Failure: State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending));
1434         // Change failed
1435         return;
1436     case GST_STATE_CHANGE_NO_PREROLL:
1437         LOG_MEDIA_MESSAGE("No preroll: State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending));
1438
1439         // Live pipelines go in PAUSED without prerolling.
1440         m_isStreaming = true;
1441         setDownloadBuffering();
1442
1443         if (state == GST_STATE_READY)
1444             m_readyState = MediaPlayer::HaveNothing;
1445         else if (state == GST_STATE_PAUSED) {
1446             m_readyState = MediaPlayer::HaveEnoughData;
1447             m_paused = true;
1448         } else if (state == GST_STATE_PLAYING)
1449             m_paused = false;
1450
1451         if (!m_paused)
1452             changePipelineState(GST_STATE_PLAYING);
1453
1454         m_networkState = MediaPlayer::Loading;
1455         break;
1456     default:
1457         LOG_MEDIA_MESSAGE("Else : %d", getStateResult);
1458         break;
1459     }
1460
1461     m_requestedState = GST_STATE_VOID_PENDING;
1462
1463     if (shouldUpdatePlaybackState)
1464         m_player->playbackStateChanged();
1465
1466     if (m_networkState != oldNetworkState) {
1467         LOG_MEDIA_MESSAGE("Network State Changed from %u to %u", oldNetworkState, m_networkState);
1468         m_player->networkStateChanged();
1469     }
1470     if (m_readyState != oldReadyState) {
1471         LOG_MEDIA_MESSAGE("Ready State Changed from %u to %u", oldReadyState, m_readyState);
1472         m_player->readyStateChanged();
1473     }
1474
1475     if (getStateResult == GST_STATE_CHANGE_SUCCESS && state >= GST_STATE_PAUSED) {
1476         updatePlaybackRate();
1477         if (m_seekIsPending) {
1478             LOG_MEDIA_MESSAGE("[Seek] committing pending seek to %f", m_seekTime);
1479             m_seekIsPending = false;
1480             m_seeking = doSeek(toGstClockTime(m_seekTime), m_player->rate(), static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE));
1481             if (!m_seeking)
1482                 LOG_MEDIA_MESSAGE("[Seek] seeking to %f failed", m_seekTime);
1483         }
1484     }
1485 }
1486
1487 void MediaPlayerPrivateGStreamer::mediaLocationChanged(GstMessage* message)
1488 {
1489     if (m_mediaLocations)
1490         gst_structure_free(m_mediaLocations);
1491
1492     const GstStructure* structure = gst_message_get_structure(message);
1493     if (structure) {
1494         // This structure can contain:
1495         // - both a new-location string and embedded locations structure
1496         // - or only a new-location string.
1497         m_mediaLocations = gst_structure_copy(structure);
1498         const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations");
1499
1500         if (locations)
1501             m_mediaLocationCurrentIndex = static_cast<int>(gst_value_list_get_size(locations)) -1;
1502
1503         loadNextLocation();
1504     }
1505 }
1506
1507 bool MediaPlayerPrivateGStreamer::loadNextLocation()
1508 {
1509     if (!m_mediaLocations)
1510         return false;
1511
1512     const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations");
1513     const gchar* newLocation = 0;
1514
1515     if (!locations) {
1516         // Fallback on new-location string.
1517         newLocation = gst_structure_get_string(m_mediaLocations, "new-location");
1518         if (!newLocation)
1519             return false;
1520     }
1521
1522     if (!newLocation) {
1523         if (m_mediaLocationCurrentIndex < 0) {
1524             m_mediaLocations = 0;
1525             return false;
1526         }
1527
1528         const GValue* location = gst_value_list_get_value(locations,
1529                                                           m_mediaLocationCurrentIndex);
1530         const GstStructure* structure = gst_value_get_structure(location);
1531
1532         if (!structure) {
1533             m_mediaLocationCurrentIndex--;
1534             return false;
1535         }
1536
1537         newLocation = gst_structure_get_string(structure, "new-location");
1538     }
1539
1540     if (newLocation) {
1541         // Found a candidate. new-location is not always an absolute url
1542         // though. We need to take the base of the current url and
1543         // append the value of new-location to it.
1544         URL baseUrl = gst_uri_is_valid(newLocation) ? URL() : m_url;
1545         URL newUrl = URL(baseUrl, newLocation);
1546
1547         RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(m_url);
1548         if (securityOrigin->canRequest(newUrl)) {
1549             INFO_MEDIA_MESSAGE("New media url: %s", newUrl.string().utf8().data());
1550
1551             // Reset player states.
1552             m_networkState = MediaPlayer::Loading;
1553             m_player->networkStateChanged();
1554             m_readyState = MediaPlayer::HaveNothing;
1555             m_player->readyStateChanged();
1556
1557             // Reset pipeline state.
1558             m_resetPipeline = true;
1559             changePipelineState(GST_STATE_READY);
1560
1561             GstState state;
1562             gst_element_get_state(m_playBin.get(), &state, 0, 0);
1563             if (state <= GST_STATE_READY) {
1564                 // Set the new uri and start playing.
1565                 g_object_set(m_playBin.get(), "uri", newUrl.string().utf8().data(), NULL);
1566                 m_url = newUrl;
1567                 changePipelineState(GST_STATE_PLAYING);
1568                 return true;
1569             }
1570         } else
1571             INFO_MEDIA_MESSAGE("Not allowed to load new media location: %s", newUrl.string().utf8().data());
1572     }
1573     m_mediaLocationCurrentIndex--;
1574     return false;
1575 }
1576
1577 void MediaPlayerPrivateGStreamer::loadStateChanged()
1578 {
1579     updateStates();
1580 }
1581
1582 void MediaPlayerPrivateGStreamer::timeChanged()
1583 {
1584     updateStates();
1585     m_player->timeChanged();
1586 }
1587
1588 void MediaPlayerPrivateGStreamer::didEnd()
1589 {
1590     // Synchronize position and duration values to not confuse the
1591     // HTMLMediaElement. In some cases like reverse playback the
1592     // position is not always reported as 0 for instance.
1593     float now = currentTime();
1594     if (now > 0 && now <= duration() && m_mediaDuration != now) {
1595         m_mediaDurationKnown = true;
1596         m_mediaDuration = now;
1597         m_player->durationChanged();
1598     }
1599
1600     m_isEndReached = true;
1601     timeChanged();
1602
1603     if (!m_player->mediaPlayerClient()->mediaPlayerIsLooping()) {
1604         m_paused = true;
1605         changePipelineState(GST_STATE_READY);
1606         m_downloadFinished = false;
1607     }
1608 }
1609
1610 void MediaPlayerPrivateGStreamer::cacheDuration()
1611 {
1612     if (m_mediaDuration || !m_mediaDurationKnown)
1613         return;
1614
1615     float newDuration = duration();
1616     if (std::isinf(newDuration)) {
1617         // Only pretend that duration is not available if the the query failed in a stable pipeline state.
1618         GstState state;
1619         if (gst_element_get_state(m_playBin.get(), &state, 0, 0) == GST_STATE_CHANGE_SUCCESS && state > GST_STATE_READY)
1620             m_mediaDurationKnown = false;
1621         return;
1622     }
1623
1624     m_mediaDuration = newDuration;
1625 }
1626
1627 void MediaPlayerPrivateGStreamer::durationChanged()
1628 {
1629     float previousDuration = m_mediaDuration;
1630
1631     cacheDuration();
1632     // Avoid emiting durationchanged in the case where the previous
1633     // duration was 0 because that case is already handled by the
1634     // HTMLMediaElement.
1635     if (previousDuration && m_mediaDuration != previousDuration)
1636         m_player->durationChanged();
1637 }
1638
1639 void MediaPlayerPrivateGStreamer::loadingFailed(MediaPlayer::NetworkState error)
1640 {
1641     m_errorOccured = true;
1642     if (m_networkState != error) {
1643         m_networkState = error;
1644         m_player->networkStateChanged();
1645     }
1646     if (m_readyState != MediaPlayer::HaveNothing) {
1647         m_readyState = MediaPlayer::HaveNothing;
1648         m_player->readyStateChanged();
1649     }
1650
1651     // Loading failed, remove ready timer.
1652     if (m_readyTimerHandler) {
1653         g_source_remove(m_readyTimerHandler);
1654         m_readyTimerHandler = 0;
1655     }
1656 }
1657
1658 static HashSet<String> mimeTypeCache()
1659 {
1660     initializeGStreamerAndRegisterWebKitElements();
1661
1662     DEFINE_STATIC_LOCAL(HashSet<String>, cache, ());
1663     static bool typeListInitialized = false;
1664
1665     if (typeListInitialized)
1666         return cache;
1667
1668     const char* mimeTypes[] = {
1669         "application/ogg",
1670         "application/vnd.apple.mpegurl",
1671         "application/vnd.rn-realmedia",
1672         "application/x-3gp",
1673         "application/x-pn-realaudio",
1674         "audio/3gpp",
1675         "audio/aac",
1676         "audio/flac",
1677         "audio/iLBC-sh",
1678         "audio/midi",
1679         "audio/mobile-xmf",
1680         "audio/mp1",
1681         "audio/mp2",
1682         "audio/mp3",
1683         "audio/mp4",
1684         "audio/mpeg",
1685         "audio/ogg",
1686         "audio/opus",
1687         "audio/qcelp",
1688         "audio/riff-midi",
1689         "audio/speex",
1690         "audio/wav",
1691         "audio/webm",
1692         "audio/x-ac3",
1693         "audio/x-aiff",
1694         "audio/x-amr-nb-sh",
1695         "audio/x-amr-wb-sh",
1696         "audio/x-au",
1697         "audio/x-ay",
1698         "audio/x-celt",
1699         "audio/x-dts",
1700         "audio/x-flac",
1701         "audio/x-gbs",
1702         "audio/x-gsm",
1703         "audio/x-gym",
1704         "audio/x-imelody",
1705         "audio/x-ircam",
1706         "audio/x-kss",
1707         "audio/x-m4a",
1708         "audio/x-mod",
1709         "audio/x-mp3",
1710         "audio/x-mpeg",
1711         "audio/x-musepack",
1712         "audio/x-nist",
1713         "audio/x-nsf",
1714         "audio/x-paris",
1715         "audio/x-sap",
1716         "audio/x-sbc",
1717         "audio/x-sds",
1718         "audio/x-shorten",
1719         "audio/x-sid",
1720         "audio/x-spc",
1721         "audio/x-speex",
1722         "audio/x-svx",
1723         "audio/x-ttafile",
1724         "audio/x-vgm",
1725         "audio/x-voc",
1726         "audio/x-vorbis+ogg",
1727         "audio/x-w64",
1728         "audio/x-wav",
1729         "audio/x-wavpack",
1730         "audio/x-wavpack-correction",
1731         "video/3gpp",
1732         "video/mj2",
1733         "video/mp4",
1734         "video/mpeg",
1735         "video/mpegts",
1736         "video/ogg",
1737         "video/quicktime",
1738         "video/vivo",
1739         "video/webm",
1740         "video/x-cdxa",
1741         "video/x-dirac",
1742         "video/x-dv",
1743         "video/x-fli",
1744         "video/x-flv",
1745         "video/x-h263",
1746         "video/x-ivf",
1747         "video/x-m4v",
1748         "video/x-matroska",
1749         "video/x-mng",
1750         "video/x-ms-asf",
1751         "video/x-msvideo",
1752         "video/x-mve",
1753         "video/x-nuv",
1754         "video/x-vcd"
1755     };
1756
1757     for (unsigned i = 0; i < (sizeof(mimeTypes) / sizeof(*mimeTypes)); ++i)
1758         cache.add(String(mimeTypes[i]));
1759
1760     typeListInitialized = true;
1761     return cache;
1762 }
1763
1764 void MediaPlayerPrivateGStreamer::getSupportedTypes(HashSet<String>& types)
1765 {
1766     types = mimeTypeCache();
1767 }
1768
1769 MediaPlayer::SupportsType MediaPlayerPrivateGStreamer::supportsType(const MediaEngineSupportParameters& parameters)
1770 {
1771     if (parameters.type.isNull() || parameters.type.isEmpty())
1772         return MediaPlayer::IsNotSupported;
1773
1774     // spec says we should not return "probably" if the codecs string is empty
1775     if (mimeTypeCache().contains(parameters.type))
1776         return parameters.codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported;
1777     return MediaPlayer::IsNotSupported;
1778 }
1779
1780 void MediaPlayerPrivateGStreamer::setDownloadBuffering()
1781 {
1782     if (!m_playBin)
1783         return;
1784
1785     GstPlayFlags flags;
1786     g_object_get(m_playBin.get(), "flags", &flags, NULL);
1787
1788     // We don't want to stop downloading if we already started it.
1789     if (flags & GST_PLAY_FLAG_DOWNLOAD && m_readyState > MediaPlayer::HaveNothing && !m_resetPipeline)
1790         return;
1791
1792     bool shouldDownload = !isLiveStream() && m_preload == MediaPlayer::Auto;
1793     if (shouldDownload) {
1794         LOG_MEDIA_MESSAGE("Enabling on-disk buffering");
1795         g_object_set(m_playBin.get(), "flags", flags | GST_PLAY_FLAG_DOWNLOAD, NULL);
1796         m_fillTimer.startRepeating(0.2);
1797     } else {
1798         LOG_MEDIA_MESSAGE("Disabling on-disk buffering");
1799         g_object_set(m_playBin.get(), "flags", flags & ~GST_PLAY_FLAG_DOWNLOAD, NULL);
1800         m_fillTimer.stop();
1801     }
1802 }
1803
1804 void MediaPlayerPrivateGStreamer::setPreload(MediaPlayer::Preload preload)
1805 {
1806     if (preload == MediaPlayer::Auto && isLiveStream())
1807         return;
1808
1809     m_preload = preload;
1810     setDownloadBuffering();
1811
1812     if (m_delayingLoad && m_preload != MediaPlayer::None) {
1813         m_delayingLoad = false;
1814         commitLoad();
1815     }
1816 }
1817
1818 GstElement* MediaPlayerPrivateGStreamer::createAudioSink()
1819 {
1820     m_autoAudioSink = gst_element_factory_make("autoaudiosink", 0);
1821     g_signal_connect(m_autoAudioSink.get(), "child-added", G_CALLBACK(setAudioStreamPropertiesCallback), this);
1822
1823     // Construct audio sink only if pitch preserving is enabled.
1824     if (!m_preservesPitch)
1825         return m_autoAudioSink.get();
1826
1827     GstElement* scale = gst_element_factory_make("scaletempo", 0);
1828     if (!scale) {
1829         GST_WARNING("Failed to create scaletempo");
1830         return m_autoAudioSink.get();
1831     }
1832
1833     GstElement* audioSinkBin = gst_bin_new("audio-sink");
1834     GstElement* convert = gst_element_factory_make("audioconvert", 0);
1835     GstElement* resample = gst_element_factory_make("audioresample", 0);
1836
1837     gst_bin_add_many(GST_BIN(audioSinkBin), scale, convert, resample, m_autoAudioSink.get(), NULL);
1838
1839     if (!gst_element_link_many(scale, convert, resample, m_autoAudioSink.get(), NULL)) {
1840         GST_WARNING("Failed to link audio sink elements");
1841         gst_object_unref(audioSinkBin);
1842         return m_autoAudioSink.get();
1843     }
1844
1845     GRefPtr<GstPad> pad = adoptGRef(gst_element_get_static_pad(scale, "sink"));
1846     gst_element_add_pad(audioSinkBin, gst_ghost_pad_new("sink", pad.get()));
1847     return audioSinkBin;
1848 }
1849
1850 GstElement* MediaPlayerPrivateGStreamer::audioSink() const
1851 {
1852     GstElement* sink;
1853     g_object_get(m_playBin.get(), "audio-sink", &sink, nullptr);
1854     return sink;
1855 }
1856
1857 void MediaPlayerPrivateGStreamer::createGSTPlayBin()
1858 {
1859     ASSERT(!m_playBin);
1860
1861     // gst_element_factory_make() returns a floating reference so
1862     // we should not adopt.
1863     m_playBin = gst_element_factory_make("playbin", "play");
1864     setStreamVolumeElement(GST_STREAM_VOLUME(m_playBin.get()));
1865
1866     GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_playBin.get())));
1867     gst_bus_add_signal_watch(bus.get());
1868     g_signal_connect(bus.get(), "message", G_CALLBACK(mediaPlayerPrivateMessageCallback), this);
1869
1870     g_object_set(m_playBin.get(), "mute", m_player->muted(), NULL);
1871
1872     g_signal_connect(m_playBin.get(), "notify::source", G_CALLBACK(mediaPlayerPrivateSourceChangedCallback), this);
1873     g_signal_connect(m_playBin.get(), "video-changed", G_CALLBACK(mediaPlayerPrivateVideoChangedCallback), this);
1874     g_signal_connect(m_playBin.get(), "audio-changed", G_CALLBACK(mediaPlayerPrivateAudioChangedCallback), this);
1875 #if ENABLE(VIDEO_TRACK)
1876     if (webkitGstCheckVersion(1, 1, 2)) {
1877         g_signal_connect(m_playBin.get(), "text-changed", G_CALLBACK(mediaPlayerPrivateTextChangedCallback), this);
1878
1879         GstElement* textCombiner = webkitTextCombinerNew();
1880         ASSERT(textCombiner);
1881         g_object_set(m_playBin.get(), "text-stream-combiner", textCombiner, NULL);
1882
1883         m_textAppSink = webkitTextSinkNew();
1884         ASSERT(m_textAppSink);
1885
1886         m_textAppSinkPad = adoptGRef(gst_element_get_static_pad(m_textAppSink.get(), "sink"));
1887         ASSERT(m_textAppSinkPad);
1888
1889         g_object_set(m_textAppSink.get(), "emit-signals", true, "enable-last-sample", false, "caps", gst_caps_new_empty_simple("text/vtt"), NULL);
1890         g_signal_connect(m_textAppSink.get(), "new-sample", G_CALLBACK(mediaPlayerPrivateNewTextSampleCallback), this);
1891
1892         g_object_set(m_playBin.get(), "text-sink", m_textAppSink.get(), NULL);
1893     }
1894 #endif
1895
1896     g_object_set(m_playBin.get(), "video-sink", createVideoSink(), "audio-sink", createAudioSink(), nullptr);
1897
1898     GRefPtr<GstPad> videoSinkPad = adoptGRef(gst_element_get_static_pad(m_webkitVideoSink.get(), "sink"));
1899     if (videoSinkPad)
1900         g_signal_connect(videoSinkPad.get(), "notify::caps", G_CALLBACK(mediaPlayerPrivateVideoSinkCapsChangedCallback), this);
1901 }
1902
1903 void MediaPlayerPrivateGStreamer::simulateAudioInterruption()
1904 {
1905     GstMessage* message = gst_message_new_request_state(GST_OBJECT(m_playBin.get()), GST_STATE_PAUSED);
1906     gst_element_post_message(m_playBin.get(), message);
1907 }
1908
1909 }
1910
1911 #endif // USE(GSTREAMER)