/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#include "jsapi/RTCEncodedFrameBase.h"
#include <cstddef>
#include <span>
#include "api/frame_transformer_interface.h"
#include "js/ArrayBuffer.h"
#include "js/GCAPI.h"
#include "mozilla/HoldDropJSObjects.h"
#include "mozilla/dom/RTCRtpScriptTransformer.h"
#include "mozilla/dom/ScriptSettings.h"
#include "nsIGlobalObject.h"
namespace mozilla::dom {
NS_IMPL_CYCLE_COLLECTION_CLASS(RTCEncodedFrameBase)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(RTCEncodedFrameBase)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner, mGlobal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mData)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(RTCEncodedFrameBase)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner, mGlobal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(RTCEncodedFrameBase)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBERS(mData)
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(RTCEncodedFrameBase)
NS_IMPL_CYCLE_COLLECTING_RELEASE(RTCEncodedFrameBase)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RTCEncodedFrameBase)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
RTCEncodedFrameBase::RTCEncodedFrameBase(nsIGlobalObject* aGlobal,
RTCEncodedFrameState& aState,
RTCRtpScriptTransformer* aOwner)
: mGlobal(aGlobal), mOwner(aOwner), mState(aState), mData(nullptr) {
mState.mTimestamp = mState.mFrame->GetTimestamp();
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(mGlobal))) {
return;
}
mozilla::HoldJSObjects(this);
const auto& frame = mState.mFrame->GetData();
if (frame.data()) {
UniquePtr<
void, JS::FreePolicy> data(js_pod_arena_malloc<uint8_t>(
js::ArrayBufferContentsArena, frame.size()));
memcpy(data.get(), frame.data(), frame.size());
mData = JS::NewArrayBufferWithContents(jsapi.cx(), frame.size(),
std::move(data));
}
else {
mData = JS::NewArrayBuffer(jsapi.cx(),
0);
}
}
RTCEncodedFrameState::RTCEncodedFrameState(
std::unique_ptr<webrtc::TransformableFrameInterface> aFrame,
uint64_t aCounter,
unsigned long aTimestamp)
: mFrame(std::move(aFrame)), mCounter(aCounter), mTimestamp(aTimestamp) {}
RTCEncodedFrameBase::~RTCEncodedFrameBase() {
DetachData();
mozilla::DropJSObjects(this);
}
void RTCEncodedFrameBase::DetachData() {
// We might have handled this in unlink already
if (mGlobal && mData) {
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(mGlobal))) {
return;
}
JS::Rooted<JSObject*> rootedData(jsapi.cx(), mData);
if (rootedData) {
JS::DetachArrayBuffer(jsapi.cx(), rootedData);
}
}
}
nsIGlobalObject* RTCEncodedFrameBase::GetParentObject()
const {
return mGlobal;
}
unsigned long RTCEncodedFrameBase::Timestamp()
const {
return mState.mTimestamp;
}
void RTCEncodedFrameBase::SetData(
const ArrayBuffer& aData) {
mData.set(aData.Obj());
if (mState.mFrame) {
aData.ProcessData([&](
const Span<uint8_t>& aData, JS::AutoChe
ckCannotGC&&) {
mState.mFrame->SetData(
std::span<const uint8_t>(aData.Elements(), aData.Length()));
});
}
}
void RTCEncodedFrameBase::GetData(JSContext* aCx,
JS::Rooted<JSObject*>* aObj) const {
aObj->set(mData);
}
uint64_t RTCEncodedFrameBase::GetCounter() const { return mState.mCounter; }
std::unique_ptr<webrtc::TransformableFrameInterface>
RTCEncodedFrameBase::TakeFrame() {
DetachData();
return std::move(mState.mFrame);
}
size_t RTCEncodedFrameBase::Size() const {
return GetArrayBufferByteLength(mData);
}
RTCEncodedFrameState::~RTCEncodedFrameState() = default;
} // namespace mozilla::dom