1 /*
2 * Copyright (c) 2002-2025 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.NativePromise;
18 import org.htmlunit.html.HtmlMedia;
19 import org.htmlunit.javascript.configuration.JsxClass;
20 import org.htmlunit.javascript.configuration.JsxConstant;
21 import org.htmlunit.javascript.configuration.JsxConstructor;
22 import org.htmlunit.javascript.configuration.JsxFunction;
23 import org.htmlunit.javascript.configuration.JsxGetter;
24 import org.htmlunit.javascript.configuration.JsxSetter;
25 import org.htmlunit.javascript.host.dom.DOMException;
26 import org.htmlunit.javascript.host.dom.Node;
27
28 /**
29 * The JavaScript object {@code HTMLMediaElement}.
30 *
31 * @author Ahmed Ashour
32 * @author Ronald Brill
33 */
34 @JsxClass
35 public class HTMLMediaElement extends HTMLElement {
36
37 /**
38 * No information is available about the media resource.
39 */
40 @JsxConstant
41 public static final int HAVE_NOTHING = 0;
42
43 /**
44 * Enough of the media resource has been retrieved that the metadata attributes are initialized.
45 * Seeking will no longer raise an exception.
46 */
47 @JsxConstant
48 public static final int HAVE_METADATA = 1;
49
50 /**
51 * Data is available for the current playback position, but not enough to actually play more than one frame.
52 */
53 @JsxConstant
54 public static final int HAVE_CURRENT_DATA = 2;
55
56 /**
57 * Data for the current playback position as well as for at least a little bit of time
58 * into the future is available (in other words, at least two frames of video, for example).
59 */
60 @JsxConstant
61 public static final int HAVE_FUTURE_DATA = 3;
62
63 /**
64 * Enough data is available—and the download rate is high enough—that the media
65 * can be played through to the end without interruption.
66 */
67 @JsxConstant
68 public static final int HAVE_ENOUGH_DATA = 4;
69
70 /** There is no data yet. */
71 @JsxConstant
72 public static final int NETWORK_EMPTY = 0;
73
74 /** Network is idle. */
75 @JsxConstant
76 public static final int NETWORK_IDLE = 1;
77
78 /** The media is loading. */
79 @JsxConstant
80 public static final int NETWORK_LOADING = 2;
81
82 /** There is no source. */
83 @JsxConstant
84 public static final int NETWORK_NO_SOURCE = 3;
85
86 /**
87 * JavaScript constructor.
88 */
89 @Override
90 @JsxConstructor
91 public void jsConstructor() {
92 super.jsConstructor();
93 }
94
95 /**
96 * Determines whether the specified media type can be played back.
97 * @param type the type
98 * @return "probably", "maybe", or ""
99 */
100 @JsxFunction
101 public String canPlayType(final String type) {
102 final HtmlMedia element = (HtmlMedia) getDomNodeOrNull();
103 if (element == null) {
104 return "maybe";
105 }
106 return element.canPlayType(type);
107 }
108
109 /**
110 * Begins playback of the media.
111 *
112 * @return a Promise which is fulfilled when playback has been started,
113 * or is rejected if for any reason playback cannot be started
114 */
115 @JsxFunction
116 public NativePromise play() {
117 return setupRejectedPromise(() ->
118 new DOMException("HtmlUnit does not support media play().", DOMException.NOT_FOUND_ERR));
119 }
120
121 /**
122 * Pauses playback of the media.
123 */
124 @JsxFunction
125 public void pause() {
126 // nothing to do
127 }
128
129 /**
130 * Resets the media element to its initial state and begins the process
131 * of selecting a media source and loading the media in preparation
132 * for playback to begin at the beginning.
133 */
134 @JsxFunction
135 public void load() {
136 // nothing to do
137 }
138
139 /**
140 * Gets the JavaScript property {@code nodeType} for the current node.
141 * @return the node type
142 */
143 @JsxGetter
144 @Override
145 public int getNodeType() {
146 final HtmlMedia element = (HtmlMedia) getDomNodeOrNull();
147 if (element == null) {
148 return Node.ELEMENT_NODE;
149 }
150 return element.getNodeType();
151 }
152
153 /**
154 * {@inheritDoc}
155 */
156 @JsxGetter
157 @Override
158 public String getNodeName() {
159 return getNodeNameCustomize();
160 }
161
162 /**
163 * Separate method to be able to override this in subclasses.
164 *
165 * @return the node name
166 */
167 protected String getNodeNameCustomize() {
168 final HtmlMedia element = (HtmlMedia) getDomNodeOrNull();
169 if (element == null) {
170 return "MEDIA";
171 }
172 return element.getNodeName();
173 }
174
175 /**
176 * Returns the URL of the audio to embed.
177 * @return the value of the {@code src} attribute
178 */
179 @JsxGetter
180 public String getSrc() {
181 final HtmlMedia media = (HtmlMedia) getDomNodeOrDie();
182 return media.getSrc();
183 }
184
185 /**
186 * Sets the value of the {@code src} attribute.
187 * @param src the value of the {@code src} attribute
188 */
189 @JsxSetter
190 public void setSrc(final String src) {
191 final HtmlMedia media = (HtmlMedia) getDomNodeOrDie();
192 media.setSrc(src);
193 }
194
195 /**
196 * Returns the absolute URL of the chosen media resource.
197 * This could happen, for example, if the web server selects a
198 * media file based on the resolution of the user's display.
199 * The value is an empty string if the networkState property is EMPTY.
200 * @return the absolute URL of the chosen media resource
201 */
202 @JsxGetter
203 public String getCurrentSrc() {
204 final HtmlMedia media = (HtmlMedia) getDomNodeOrDie();
205 return media.getCurrentSrc();
206 }
207 }