1 // This may look like C code, but it's really -*- C++ -*-
2 /*
3  * Copyright (C) 2010 Emweb bv, Herent, Belgium.
4  *
5  * See the LICENSE file for terms of use.
6  */
7 #ifndef WABSTRACT_MEDIA_H_
8 #define WABSTRACT_MEDIA_H_
9 
10 #include <Wt/WInteractWidget.h>
11 #include <Wt/WLink.h>
12 #include <Wt/WFlags.h>
13 
14 namespace Wt {
15 
16 /*! \brief Enumeration for playback options
17  */
18 enum class PlayerOption {
19   Autoplay = 1, //!< Start playing as soon as the video is loaded
20   Loop     = 2, //!< Enable loop mode
21   Controls = 4  //!< Show video controls in the browser
22 };
23 
24 /*! \brief Enumeration for preload strategy
25  */
26 enum class MediaPreloadMode {
27   None,    //!< Hints that the user will probably not play the video
28   Auto,    //!< Hints that it is ok to download the entire resource
29   Metadata //!< Hints that retrieving metadata is a good option
30 };
31 
32 /*! \class WAbstractMedia Wt/WAbstractMedia.h Wt/WAbstractMedia.h
33  *  \brief Abstract baseclass for native media elements.
34  *
35  * This class is an abstract base class for HTML5 media elements
36  * (&lt;audio&gt;, &lt;video&gt;).
37  *
38  */
39 class WT_API WAbstractMedia : public WInteractWidget
40 {
41 public:
42   /*! \brief Typedef for enum Wt::PlayerOption */
43   typedef PlayerOption Option;
44 
45   /*! \brief Typedef for enum Wt::MediaPreloadMode */
46   typedef MediaPreloadMode PreloadMode;
47 
48   /*! \brief Typedef for enum Wt::MediaReadyState */
49   typedef MediaReadyState ReadyState;
50 
51   /*! \brief Consctructor for a media widget.
52    *
53    * A freshly constructed media widget has no options set, no media
54    * sources, and has preload mode set to PreloadAuto.
55    */
56   WAbstractMedia();
57 
58   ~WAbstractMedia();
59 
60   /*! \brief Set the media element options
61    *
62    * \sa Options
63    */
64   void setOptions(const WFlags<PlayerOption> &flags);
65 
66   /*! \brief Retrieve the configured options
67    */
68   WFlags<PlayerOption> getOptions() const;
69 
70   /*! \brief Set the preload mode
71    */
72   void setPreloadMode(MediaPreloadMode mode);
73 
74   /*! \brief Retrieve the preload mode
75    */
76   MediaPreloadMode preloadMode() const;
77 
78   /*! \brief Removes all source elements
79    *
80    * This method can be used to remove all media sources. Afterward, you
81    * may add new media sources with calls to addSource().
82    *
83    * Use this to reuse a WAbstractMedia instantiation to play something else.
84    */
85   void clearSources();
86 
87   /*! \brief Add a media source
88    *
89    * This method specifies a media source (which may be a URL or
90    * dynamic resource). You may add as many media sources as you
91    * want. The browser will select the appropriate media stream to
92    * display to the user.
93    *
94    * This method specifies a media source using the URL, the mime type,
95    * and the media attribute. HTML allows for empty type and media
96    * attributes.
97    */
98   void addSource(const WLink& source, const std::string &type = "",
99 		 const std::string &media = "");
100 
101   /*! \brief Content to be shown when media cannot be played
102    *
103    * As not all browsers are HTML5 compliant, it is a good idea to
104    * provide fallback options when the media cannot be displayed.  If
105    * the media can be played by the browser, the alternative content
106    * will be suppressed.
107    *
108    * The two reasons to display the alternative content are (1) the
109    * media tag is not supported, or (2) the media tag is supported, but
110    * none of the media sources are supported by the browser. In the first
111    * case, fall-back is automatic and does not rely on JavaScript in the
112    * browser; in the latter case, JavaScript is required to make the
113    * fallback work.
114    *
115    * The alternative content can be any widget: you can set it to an
116    * alternative media player (QuickTime, Flash, ...), show a
117    * Flash movie, an animated gif, a text, a poster image, ...
118    */
119   void setAlternativeContent(std::unique_ptr<WWidget> alternative);
120 
121   /*! \brief Invoke play() on the media element
122    *
123    * JavaScript must be available for this function to work.
124    */
125   void play();
126 
127   /*! \brief Invoke pause() on the media element
128    *
129    * JavaScript must be available for this function to work.
130    */
131   void pause();
132 
133   /*! \brief Returns whether the media is playing.
134    */
playing()135   bool playing() const { return playing_; }
136 
137   /*! \brief Returns the media's readyState
138    */
readyState()139   MediaReadyState readyState() const { return readyState_; }
140 
141   /*! \brief Event signal emitted when playback has begun.
142    *
143    * This event fires when play was invoked, or when the media element
144    * starts playing because the Autoplay option was provided.
145    *
146    * \note When JavaScript is disabled, the signal will never fire.
147    */
148   EventSignal<>& playbackStarted();
149 
150   /*! \brief Event signal emitted when the playback has paused.
151    *
152    * \note When JavaScript is disabled, the signal will never fire.
153    */
154   EventSignal<>& playbackPaused();
155 
156   /*! \brief Event signal emitted when the playback stopped because
157    *         the end of the media was reached.
158    *
159    * \note When JavaScript is disabled, the signal will never fire.
160    */
161   EventSignal<>& ended();
162 
163   /*! \brief Event signal emitted when the current playback position has
164    *         changed.
165    *
166    * This event is fired when the playback position has changed,
167    * both when the media is in a normal playing mode, but also when it has
168    * changed discontinuously because of another reason.
169    *
170    * \note When JavaScript is disabled, the signal will never fire.
171    */
172   EventSignal<>& timeUpdated();
173 
174   /*! \brief Event signal emitted when the playback volume has changed.
175    *
176    * \note When JavaScript is disabled, the signal will never fire.
177    */
178   EventSignal<>& volumeChanged();
179 
180   /*! \brief Returns the JavaScript reference to the media object, or null.
181    *
182    * It is possible, for browser compatibility reasons, that jsRef()
183    * is not the media element. jsMediaRef() is guaranteed to be an
184    * expression that evaluates to the media object. This expression
185    * may yield null, if the video object is not rendered at all
186    * (e.g. on older versions of Internet Explorer).
187    */
188   std::string jsMediaRef() const;
189 
190 protected:
191   virtual void getDomChanges(std::vector<DomElement *>& result,
192 			     WApplication *app) override;
193   virtual DomElement *createDomElement(WApplication *app) override;
194   virtual void iterateChildren(const HandleWidgetMethod& method) const override;
195 
196   virtual void updateMediaDom(DomElement& element, bool all);
197   virtual DomElement *createMediaDomElement() = 0;
198 
199   virtual void setFormData(const FormData& formData) override;
200   virtual void enableAjax() override;
201 
202 private:
203   struct Source
204 #ifdef WT_TARGET_JAVA
205     : public WObject
206 #endif
207   {
208     Source(WAbstractMedia *parent, const WLink& link, const std::string &type,
209            const std::string &media);
210     ~Source();
211 
212     void resourceChanged();
213 
214     WAbstractMedia *parent;
215     Wt::Signals::connection connection;
216     std::string type, media;
217     WLink link;
218   };
219   void renderSource(DomElement* element, WAbstractMedia::Source &source,
220 		    bool isLast);
221 
222   std::vector<std::unique_ptr<Source> > sources_;
223   std::size_t sourcesRendered_;
224   std::string mediaId_;
225   WFlags<PlayerOption> flags_;
226   MediaPreloadMode preloadMode_;
227   std::unique_ptr<WWidget> alternative_;
228   bool flagsChanged_, preloadChanged_, sourcesChanged_;
229 
230   // Vars received from client
231   bool playing_;
232   double volume_;
233   double current_;
234   double duration_;
235   bool ended_;
236   MediaReadyState readyState_;
237 
238   static const char *PLAYBACKSTARTED_SIGNAL;
239   static const char *PLAYBACKPAUSED_SIGNAL;
240   static const char *ENDED_SIGNAL;
241   static const char *TIMEUPDATED_SIGNAL;
242   static const char *VOLUMECHANGED_SIGNAL;
243 
244   void loadJavaScript();
245 };
246 
247 W_DECLARE_OPERATORS_FOR_FLAGS(PlayerOption)
248 
249 }
250 
251 #endif // WABSTRACT_MEDIA_H_
252 
253