1/*
2 This file is part of the WebKit open source project.
3 This file has been generated by generate-bindings.pl. DO NOT MODIFY!
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21#include "config.h"
22
23#if ENABLE(WEB_RTC)
24
25#include "JSRTCRtpTransceiver.h"
26
27#include "JSDOMAttribute.h"
28#include "JSDOMBinding.h"
29#include "JSDOMConstructorNotConstructable.h"
30#include "JSDOMConvertBoolean.h"
31#include "JSDOMConvertEnumeration.h"
32#include "JSDOMConvertInterface.h"
33#include "JSDOMConvertNullable.h"
34#include "JSDOMConvertStrings.h"
35#include "JSDOMExceptionHandling.h"
36#include "JSDOMGlobalObject.h"
37#include "JSDOMOperation.h"
38#include "JSDOMWrapperCache.h"
39#include "JSRTCRtpReceiver.h"
40#include "JSRTCRtpSender.h"
41#include "JSRTCRtpTransceiverDirection.h"
42#include "RuntimeEnabledFeatures.h"
43#include "ScriptExecutionContext.h"
44#include <JavaScriptCore/FunctionPrototype.h>
45#include <JavaScriptCore/HeapSnapshotBuilder.h>
46#include <JavaScriptCore/JSCInlines.h>
47#include <wtf/GetPtr.h>
48#include <wtf/PointerPreparations.h>
49#include <wtf/URL.h>
50
51
52namespace WebCore {
53using namespace JSC;
54
55// Functions
56
57JSC::EncodedJSValue JSC_HOST_CALL jsRTCRtpTransceiverPrototypeFunctionStop(JSC::ExecState*);
58
59// Attributes
60
61JSC::EncodedJSValue jsRTCRtpTransceiverConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
62bool setJSRTCRtpTransceiverConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
63JSC::EncodedJSValue jsRTCRtpTransceiverMid(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
64JSC::EncodedJSValue jsRTCRtpTransceiverSender(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
65JSC::EncodedJSValue jsRTCRtpTransceiverReceiver(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
66JSC::EncodedJSValue jsRTCRtpTransceiverStopped(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
67JSC::EncodedJSValue jsRTCRtpTransceiverDirection(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
68bool setJSRTCRtpTransceiverDirection(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
69JSC::EncodedJSValue jsRTCRtpTransceiverCurrentDirection(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
70
71class JSRTCRtpTransceiverPrototype : public JSC::JSNonFinalObject {
72public:
73 using Base = JSC::JSNonFinalObject;
74 static JSRTCRtpTransceiverPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure)
75 {
76 JSRTCRtpTransceiverPrototype* ptr = new (NotNull, JSC::allocateCell<JSRTCRtpTransceiverPrototype>(vm.heap)) JSRTCRtpTransceiverPrototype(vm, globalObject, structure);
77 ptr->finishCreation(vm);
78 return ptr;
79 }
80
81 DECLARE_INFO;
82 static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
83 {
84 return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
85 }
86
87private:
88 JSRTCRtpTransceiverPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure)
89 : JSC::JSNonFinalObject(vm, structure)
90 {
91 }
92
93 void finishCreation(JSC::VM&);
94};
95
96using JSRTCRtpTransceiverConstructor = JSDOMConstructorNotConstructable<JSRTCRtpTransceiver>;
97
98template<> JSValue JSRTCRtpTransceiverConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject)
99{
100 UNUSED_PARAM(vm);
101 return globalObject.functionPrototype();
102}
103
104template<> void JSRTCRtpTransceiverConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject)
105{
106 putDirect(vm, vm.propertyNames->prototype, JSRTCRtpTransceiver::prototype(vm, globalObject), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
107 putDirect(vm, vm.propertyNames->name, jsNontrivialString(&vm, String("RTCRtpTransceiver"_s)), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
108 putDirect(vm, vm.propertyNames->length, jsNumber(0), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
109}
110
111template<> const ClassInfo JSRTCRtpTransceiverConstructor::s_info = { "RTCRtpTransceiver", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSRTCRtpTransceiverConstructor) };
112
113/* Hash table for prototype */
114
115static const HashTableValue JSRTCRtpTransceiverPrototypeTableValues[] =
116{
117 { "constructor", static_cast<unsigned>(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsRTCRtpTransceiverConstructor), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSRTCRtpTransceiverConstructor) } },
118 { "mid", static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsRTCRtpTransceiverMid), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(0) } },
119 { "sender", static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsRTCRtpTransceiverSender), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(0) } },
120 { "receiver", static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsRTCRtpTransceiverReceiver), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(0) } },
121 { "stopped", static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsRTCRtpTransceiverStopped), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(0) } },
122 { "direction", static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsRTCRtpTransceiverDirection), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSRTCRtpTransceiverDirection) } },
123 { "currentDirection", static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsRTCRtpTransceiverCurrentDirection), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(0) } },
124 { "stop", static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t)static_cast<RawNativeFunction>(jsRTCRtpTransceiverPrototypeFunctionStop), (intptr_t) (0) } },
125};
126
127const ClassInfo JSRTCRtpTransceiverPrototype::s_info = { "RTCRtpTransceiverPrototype", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSRTCRtpTransceiverPrototype) };
128
129void JSRTCRtpTransceiverPrototype::finishCreation(VM& vm)
130{
131 Base::finishCreation(vm);
132 reifyStaticProperties(vm, JSRTCRtpTransceiver::info(), JSRTCRtpTransceiverPrototypeTableValues, *this);
133 bool hasDisabledRuntimeProperties = false;
134 if (!RuntimeEnabledFeatures::sharedFeatures().webRTCUnifiedPlanEnabled()) {
135 hasDisabledRuntimeProperties = true;
136 auto propertyName = Identifier::fromString(&vm, reinterpret_cast<const LChar*>("currentDirection"), strlen("currentDirection"));
137 VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
138 JSObject::deleteProperty(this, globalObject()->globalExec(), propertyName);
139 }
140 if (hasDisabledRuntimeProperties && structure()->isDictionary())
141 flattenDictionaryObject(vm);
142}
143
144const ClassInfo JSRTCRtpTransceiver::s_info = { "RTCRtpTransceiver", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSRTCRtpTransceiver) };
145
146JSRTCRtpTransceiver::JSRTCRtpTransceiver(Structure* structure, JSDOMGlobalObject& globalObject, Ref<RTCRtpTransceiver>&& impl)
147 : JSDOMWrapper<RTCRtpTransceiver>(structure, globalObject, WTFMove(impl))
148{
149}
150
151void JSRTCRtpTransceiver::finishCreation(VM& vm)
152{
153 Base::finishCreation(vm);
154 ASSERT(inherits(vm, info()));
155
156}
157
158JSObject* JSRTCRtpTransceiver::createPrototype(VM& vm, JSDOMGlobalObject& globalObject)
159{
160 return JSRTCRtpTransceiverPrototype::create(vm, &globalObject, JSRTCRtpTransceiverPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype()));
161}
162
163JSObject* JSRTCRtpTransceiver::prototype(VM& vm, JSDOMGlobalObject& globalObject)
164{
165 return getDOMPrototype<JSRTCRtpTransceiver>(vm, globalObject);
166}
167
168JSValue JSRTCRtpTransceiver::getConstructor(VM& vm, const JSGlobalObject* globalObject)
169{
170 return getDOMConstructor<JSRTCRtpTransceiverConstructor>(vm, *jsCast<const JSDOMGlobalObject*>(globalObject));
171}
172
173void JSRTCRtpTransceiver::destroy(JSC::JSCell* cell)
174{
175 JSRTCRtpTransceiver* thisObject = static_cast<JSRTCRtpTransceiver*>(cell);
176 thisObject->JSRTCRtpTransceiver::~JSRTCRtpTransceiver();
177}
178
179template<> inline JSRTCRtpTransceiver* IDLAttribute<JSRTCRtpTransceiver>::cast(ExecState& state, EncodedJSValue thisValue)
180{
181 return jsDynamicCast<JSRTCRtpTransceiver*>(state.vm(), JSValue::decode(thisValue));
182}
183
184template<> inline JSRTCRtpTransceiver* IDLOperation<JSRTCRtpTransceiver>::cast(ExecState& state)
185{
186 return jsDynamicCast<JSRTCRtpTransceiver*>(state.vm(), state.thisValue());
187}
188
189EncodedJSValue jsRTCRtpTransceiverConstructor(ExecState* state, EncodedJSValue thisValue, PropertyName)
190{
191 VM& vm = state->vm();
192 auto throwScope = DECLARE_THROW_SCOPE(vm);
193 auto* prototype = jsDynamicCast<JSRTCRtpTransceiverPrototype*>(vm, JSValue::decode(thisValue));
194 if (UNLIKELY(!prototype))
195 return throwVMTypeError(state, throwScope);
196 return JSValue::encode(JSRTCRtpTransceiver::getConstructor(state->vm(), prototype->globalObject()));
197}
198
199bool setJSRTCRtpTransceiverConstructor(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)
200{
201 VM& vm = state->vm();
202 auto throwScope = DECLARE_THROW_SCOPE(vm);
203 auto* prototype = jsDynamicCast<JSRTCRtpTransceiverPrototype*>(vm, JSValue::decode(thisValue));
204 if (UNLIKELY(!prototype)) {
205 throwVMTypeError(state, throwScope);
206 return false;
207 }
208 // Shadowing a built-in constructor
209 return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
210}
211
212static inline JSValue jsRTCRtpTransceiverMidGetter(ExecState& state, JSRTCRtpTransceiver& thisObject, ThrowScope& throwScope)
213{
214 UNUSED_PARAM(throwScope);
215 UNUSED_PARAM(state);
216 auto& impl = thisObject.wrapped();
217 JSValue result = toJS<IDLNullable<IDLDOMString>>(state, throwScope, impl.mid());
218 return result;
219}
220
221EncodedJSValue jsRTCRtpTransceiverMid(ExecState* state, EncodedJSValue thisValue, PropertyName)
222{
223 return IDLAttribute<JSRTCRtpTransceiver>::get<jsRTCRtpTransceiverMidGetter, CastedThisErrorBehavior::Assert>(*state, thisValue, "mid");
224}
225
226static inline JSValue jsRTCRtpTransceiverSenderGetter(ExecState& state, JSRTCRtpTransceiver& thisObject, ThrowScope& throwScope)
227{
228 UNUSED_PARAM(throwScope);
229 UNUSED_PARAM(state);
230 auto& impl = thisObject.wrapped();
231 JSValue result = toJS<IDLInterface<RTCRtpSender>>(state, *thisObject.globalObject(), throwScope, impl.sender());
232 return result;
233}
234
235EncodedJSValue jsRTCRtpTransceiverSender(ExecState* state, EncodedJSValue thisValue, PropertyName)
236{
237 return IDLAttribute<JSRTCRtpTransceiver>::get<jsRTCRtpTransceiverSenderGetter, CastedThisErrorBehavior::Assert>(*state, thisValue, "sender");
238}
239
240static inline JSValue jsRTCRtpTransceiverReceiverGetter(ExecState& state, JSRTCRtpTransceiver& thisObject, ThrowScope& throwScope)
241{
242 UNUSED_PARAM(throwScope);
243 UNUSED_PARAM(state);
244 auto& impl = thisObject.wrapped();
245 JSValue result = toJS<IDLInterface<RTCRtpReceiver>>(state, *thisObject.globalObject(), throwScope, impl.receiver());
246 return result;
247}
248
249EncodedJSValue jsRTCRtpTransceiverReceiver(ExecState* state, EncodedJSValue thisValue, PropertyName)
250{
251 return IDLAttribute<JSRTCRtpTransceiver>::get<jsRTCRtpTransceiverReceiverGetter, CastedThisErrorBehavior::Assert>(*state, thisValue, "receiver");
252}
253
254static inline JSValue jsRTCRtpTransceiverStoppedGetter(ExecState& state, JSRTCRtpTransceiver& thisObject, ThrowScope& throwScope)
255{
256 UNUSED_PARAM(throwScope);
257 UNUSED_PARAM(state);
258 auto& impl = thisObject.wrapped();
259 JSValue result = toJS<IDLBoolean>(state, throwScope, impl.stopped());
260 return result;
261}
262
263EncodedJSValue jsRTCRtpTransceiverStopped(ExecState* state, EncodedJSValue thisValue, PropertyName)
264{
265 return IDLAttribute<JSRTCRtpTransceiver>::get<jsRTCRtpTransceiverStoppedGetter, CastedThisErrorBehavior::Assert>(*state, thisValue, "stopped");
266}
267
268static inline JSValue jsRTCRtpTransceiverDirectionGetter(ExecState& state, JSRTCRtpTransceiver& thisObject, ThrowScope& throwScope)
269{
270 UNUSED_PARAM(throwScope);
271 UNUSED_PARAM(state);
272 auto& impl = thisObject.wrapped();
273 JSValue result = toJS<IDLEnumeration<RTCRtpTransceiverDirection>>(state, throwScope, impl.direction());
274 return result;
275}
276
277EncodedJSValue jsRTCRtpTransceiverDirection(ExecState* state, EncodedJSValue thisValue, PropertyName)
278{
279 return IDLAttribute<JSRTCRtpTransceiver>::get<jsRTCRtpTransceiverDirectionGetter, CastedThisErrorBehavior::Assert>(*state, thisValue, "direction");
280}
281
282static inline bool setJSRTCRtpTransceiverDirectionSetter(ExecState& state, JSRTCRtpTransceiver& thisObject, JSValue value, ThrowScope& throwScope)
283{
284 UNUSED_PARAM(throwScope);
285 auto& impl = thisObject.wrapped();
286 auto optionalNativeValue = parseEnumeration<RTCRtpTransceiverDirection>(state, value);
287 RETURN_IF_EXCEPTION(throwScope, false);
288 if (UNLIKELY(!optionalNativeValue))
289 return false;
290 auto nativeValue = optionalNativeValue.value();
291 AttributeSetter::call(state, throwScope, [&] {
292 return impl.setDirection(WTFMove(nativeValue));
293 });
294 return true;
295}
296
297bool setJSRTCRtpTransceiverDirection(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)
298{
299 return IDLAttribute<JSRTCRtpTransceiver>::set<setJSRTCRtpTransceiverDirectionSetter>(*state, thisValue, encodedValue, "direction");
300}
301
302static inline JSValue jsRTCRtpTransceiverCurrentDirectionGetter(ExecState& state, JSRTCRtpTransceiver& thisObject, ThrowScope& throwScope)
303{
304 UNUSED_PARAM(throwScope);
305 UNUSED_PARAM(state);
306 auto& impl = thisObject.wrapped();
307 JSValue result = toJS<IDLNullable<IDLEnumeration<RTCRtpTransceiverDirection>>>(state, throwScope, impl.currentDirection());
308 return result;
309}
310
311EncodedJSValue jsRTCRtpTransceiverCurrentDirection(ExecState* state, EncodedJSValue thisValue, PropertyName)
312{
313 return IDLAttribute<JSRTCRtpTransceiver>::get<jsRTCRtpTransceiverCurrentDirectionGetter, CastedThisErrorBehavior::Assert>(*state, thisValue, "currentDirection");
314}
315
316static inline JSC::EncodedJSValue jsRTCRtpTransceiverPrototypeFunctionStopBody(JSC::ExecState* state, typename IDLOperation<JSRTCRtpTransceiver>::ClassParameter castedThis, JSC::ThrowScope& throwScope)
317{
318 UNUSED_PARAM(state);
319 UNUSED_PARAM(throwScope);
320 auto& impl = castedThis->wrapped();
321 impl.stop();
322 return JSValue::encode(jsUndefined());
323}
324
325EncodedJSValue JSC_HOST_CALL jsRTCRtpTransceiverPrototypeFunctionStop(ExecState* state)
326{
327 return IDLOperation<JSRTCRtpTransceiver>::call<jsRTCRtpTransceiverPrototypeFunctionStopBody>(*state, "stop");
328}
329
330void JSRTCRtpTransceiver::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
331{
332 auto* thisObject = jsCast<JSRTCRtpTransceiver*>(cell);
333 builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
334 if (thisObject->scriptExecutionContext())
335 builder.setLabelForCell(cell, "url " + thisObject->scriptExecutionContext()->url().string());
336 Base::heapSnapshot(cell, builder);
337}
338
339bool JSRTCRtpTransceiverOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
340{
341 UNUSED_PARAM(handle);
342 UNUSED_PARAM(visitor);
343 UNUSED_PARAM(reason);
344 return false;
345}
346
347void JSRTCRtpTransceiverOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)
348{
349 auto* jsRTCRtpTransceiver = static_cast<JSRTCRtpTransceiver*>(handle.slot()->asCell());
350 auto& world = *static_cast<DOMWrapperWorld*>(context);
351 uncacheWrapper(world, &jsRTCRtpTransceiver->wrapped(), jsRTCRtpTransceiver);
352}
353
354#if ENABLE(BINDING_INTEGRITY)
355#if PLATFORM(WIN)
356#pragma warning(disable: 4483)
357extern "C" { extern void (*const __identifier("??_7RTCRtpTransceiver@WebCore@@6B@")[])(); }
358#else
359extern "C" { extern void* _ZTVN7WebCore17RTCRtpTransceiverE[]; }
360#endif
361#endif
362
363JSC::JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject* globalObject, Ref<RTCRtpTransceiver>&& impl)
364{
365
366#if ENABLE(BINDING_INTEGRITY)
367 void* actualVTablePointer = *(reinterpret_cast<void**>(impl.ptr()));
368#if PLATFORM(WIN)
369 void* expectedVTablePointer = WTF_PREPARE_VTBL_POINTER_FOR_INSPECTION(__identifier("??_7RTCRtpTransceiver@WebCore@@6B@"));
370#else
371 void* expectedVTablePointer = WTF_PREPARE_VTBL_POINTER_FOR_INSPECTION(&_ZTVN7WebCore17RTCRtpTransceiverE[2]);
372#endif
373
374 // If this fails RTCRtpTransceiver does not have a vtable, so you need to add the
375 // ImplementationLacksVTable attribute to the interface definition
376 static_assert(std::is_polymorphic<RTCRtpTransceiver>::value, "RTCRtpTransceiver is not polymorphic");
377
378 // If you hit this assertion you either have a use after free bug, or
379 // RTCRtpTransceiver has subclasses. If RTCRtpTransceiver has subclasses that get passed
380 // to toJS() we currently require RTCRtpTransceiver you to opt out of binding hardening
381 // by adding the SkipVTableValidation attribute to the interface IDL definition
382 RELEASE_ASSERT(actualVTablePointer == expectedVTablePointer);
383#endif
384 return createWrapper<RTCRtpTransceiver>(globalObject, WTFMove(impl));
385}
386
387JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, RTCRtpTransceiver& impl)
388{
389 return wrap(state, globalObject, impl);
390}
391
392RTCRtpTransceiver* JSRTCRtpTransceiver::toWrapped(JSC::VM& vm, JSC::JSValue value)
393{
394 if (auto* wrapper = jsDynamicCast<JSRTCRtpTransceiver*>(vm, value))
395 return &wrapper->wrapped();
396 return nullptr;
397}
398
399}
400
401#endif // ENABLE(WEB_RTC)
402