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 }