View Javadoc
1   /*
2    * Copyright (c) 2002-2026 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host.html;
16  
17  import org.htmlunit.corejs.javascript.Context;
18  import org.htmlunit.corejs.javascript.Function;
19  import org.htmlunit.corejs.javascript.NativePromise;
20  import org.htmlunit.corejs.javascript.Scriptable;
21  import org.htmlunit.corejs.javascript.VarScope;
22  import org.htmlunit.html.HtmlMedia;
23  import org.htmlunit.javascript.JavaScriptEngine;
24  import org.htmlunit.javascript.configuration.JsxClass;
25  import org.htmlunit.javascript.configuration.JsxConstant;
26  import org.htmlunit.javascript.configuration.JsxConstructor;
27  import org.htmlunit.javascript.configuration.JsxFunction;
28  import org.htmlunit.javascript.configuration.JsxGetter;
29  import org.htmlunit.javascript.configuration.JsxSetter;
30  import org.htmlunit.javascript.host.dom.DOMException;
31  import org.htmlunit.javascript.host.dom.Node;
32  
33  /**
34   * The JavaScript object {@code HTMLMediaElement}.
35   *
36   * @author Ahmed Ashour
37   * @author Ronald Brill
38   *
39   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement">MDN Documentation</a>
40   */
41  @JsxClass
42  public class HTMLMediaElement extends HTMLElement {
43  
44      /**
45       * No information is available about the media resource.
46       */
47      @JsxConstant
48      public static final int HAVE_NOTHING = 0;
49  
50      /**
51       * Enough of the media resource has been retrieved that the metadata attributes are initialized.
52       * Seeking will no longer raise an exception.
53       */
54      @JsxConstant
55      public static final int HAVE_METADATA = 1;
56  
57      /**
58       * Data is available for the current playback position, but not enough to actually play more than one frame.
59       */
60      @JsxConstant
61      public static final int HAVE_CURRENT_DATA = 2;
62  
63      /**
64       * Data for the current playback position as well as for at least a little bit of time
65       * into the future is available (in other words, at least two frames of video, for example).
66       */
67      @JsxConstant
68      public static final int HAVE_FUTURE_DATA = 3;
69  
70      /**
71       * Enough data is available—and the download rate is high enough—that the media
72       * can be played through to the end without interruption.
73       */
74      @JsxConstant
75      public static final int HAVE_ENOUGH_DATA = 4;
76  
77      /** There is no data yet. */
78      @JsxConstant
79      public static final int NETWORK_EMPTY = 0;
80  
81      /** Network is idle. */
82      @JsxConstant
83      public static final int NETWORK_IDLE = 1;
84  
85      /** The media is loading. */
86      @JsxConstant
87      public static final int NETWORK_LOADING = 2;
88  
89      /** There is no source. */
90      @JsxConstant
91      public static final int NETWORK_NO_SOURCE = 3;
92  
93      /**
94       * JavaScript constructor.
95       */
96      @Override
97      @JsxConstructor
98      public void jsConstructor() {
99          super.jsConstructor();
100     }
101 
102     /**
103      * Determines whether the specified media type can be played back.
104      * @param context the context
105      * @param scope the scope
106      * @param thisObj this object
107      * @param args the arguments
108      * @param function the function
109      * @return "probably", "maybe", or ""
110      */
111     @JsxFunction
112     public static String canPlayType(final Context context, final VarScope scope,
113             final Scriptable thisObj, final Object[] args, final Function function) {
114         if (!(thisObj instanceof HTMLMediaElement htmlMedia)) {
115             throw JavaScriptEngine.reportRuntimeError(
116                     "HTMLMediaElement.canPlayType() failed - this is not a HTMLMediaElement");
117         }
118 
119         if (args.length == 0) {
120             throw JavaScriptEngine.typeError(
121                     "HTMLMediaElement.canPlayType(): At least 1 argument required, but only 0 passed.");
122         }
123 
124         return htmlMedia.getBrowserVersion().canPlayType(JavaScriptEngine.toString(args[0]));
125     }
126 
127     /**
128      * Begins playback of the media.
129      *
130      * @return a Promise which is fulfilled when playback has been started,
131      *         or is rejected if for any reason playback cannot be started
132      */
133     @JsxFunction
134     public NativePromise play() {
135         return setupRejectedPromise(() ->
136                     new DOMException("HtmlUnit does not support media play().", DOMException.NOT_FOUND_ERR));
137     }
138 
139     /**
140      * Pauses playback of the media.
141      */
142     @JsxFunction
143     public void pause() {
144         // nothing to do
145     }
146 
147     /**
148      * Resets the media element to its initial state and begins the process
149      * of selecting a media source and loading the media in preparation
150      * for playback to begin at the beginning.
151      */
152     @JsxFunction
153     public void load() {
154         // nothing to do
155     }
156 
157     /**
158      * Gets the JavaScript property {@code nodeType} for the current node.
159      * @return the node type
160      */
161     @JsxGetter
162     @Override
163     public int getNodeType() {
164         final HtmlMedia element = (HtmlMedia) getDomNodeOrNull();
165         if (element == null) {
166             return Node.ELEMENT_NODE;
167         }
168         return element.getNodeType();
169     }
170 
171     /**
172      * {@inheritDoc}
173      */
174     @JsxGetter
175     @Override
176     public String getNodeName() {
177         return getNodeNameCustomize();
178     }
179 
180     /**
181      * Separate method to be able to override this in subclasses.
182      *
183      * @return the node name
184      */
185     protected String getNodeNameCustomize() {
186         final HtmlMedia element = (HtmlMedia) getDomNodeOrNull();
187         if (element == null) {
188             return "MEDIA";
189         }
190         return element.getNodeName();
191     }
192 
193     /**
194      * Returns the URL of the audio to embed.
195      * @return the value of the {@code src} attribute
196      */
197     @JsxGetter
198     public String getSrc() {
199         final HtmlMedia media = (HtmlMedia) getDomNodeOrDie();
200         return media.getSrc();
201     }
202 
203     /**
204      * Sets the value of the {@code src} attribute.
205      * @param src the value of the {@code src} attribute
206      */
207     @JsxSetter
208     public void setSrc(final String src) {
209         final HtmlMedia media = (HtmlMedia) getDomNodeOrDie();
210         media.setSrc(src);
211     }
212 
213     /**
214      * Returns the absolute URL of the chosen media resource.
215      * This could happen, for example, if the web server selects a
216      * media file based on the resolution of the user's display.
217      * The value is an empty string if the networkState property is EMPTY.
218      * @return the absolute URL of the chosen media resource
219      */
220     @JsxGetter
221     public String getCurrentSrc() {
222         final HtmlMedia media = (HtmlMedia) getDomNodeOrDie();
223         return media.getCurrentSrc();
224     }
225 }