void AudioContext::DecodeAudioData(const ArrayBuffer& aBuffer, DecodeSuccessCallback& aSuccessCallback, const Optional<OwningNonNull<DecodeErrorCallback> >& aFailureCallback) { AutoJSAPI jsapi; jsapi.Init(); JSContext* cx = jsapi.cx(); JSAutoCompartment ac(cx, aBuffer.Obj()); aBuffer.ComputeLengthAndData(); // Neuter the array buffer size_t length = aBuffer.Length(); JS::RootedObject obj(cx, aBuffer.Obj()); uint8_t* data = static_cast<uint8_t*>(JS_StealArrayBufferContents(cx, obj)); // Sniff the content of the media. // Failed type sniffing will be handled by AsyncDecodeMedia. nsAutoCString contentType; NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, nullptr, data, length, contentType); nsRefPtr<DecodeErrorCallback> failureCallback; if (aFailureCallback.WasPassed()) { failureCallback = &aFailureCallback.Value(); } nsRefPtr<WebAudioDecodeJob> job( new WebAudioDecodeJob(contentType, this, &aSuccessCallback, failureCallback)); mDecoder.AsyncDecodeMedia(contentType.get(), data, length, *job); // Transfer the ownership to mDecodeJobs mDecodeJobs.AppendElement(job); }
already_AddRefed<Promise> AudioContext::DecodeAudioData(const ArrayBuffer& aBuffer, const Optional<OwningNonNull<DecodeSuccessCallback> >& aSuccessCallback, const Optional<OwningNonNull<DecodeErrorCallback> >& aFailureCallback, ErrorResult& aRv) { nsCOMPtr<nsIGlobalObject> parentObject = do_QueryInterface(GetParentObject()); RefPtr<Promise> promise; AutoJSAPI jsapi; jsapi.Init(); JSContext* cx = jsapi.cx(); JSAutoCompartment ac(cx, aBuffer.Obj()); promise = Promise::Create(parentObject, aRv); if (aRv.Failed()) { return nullptr; } aBuffer.ComputeLengthAndData(); if (aBuffer.IsShared()) { // Throw if the object is mapping shared memory (must opt in). aRv.ThrowTypeError<MSG_TYPEDARRAY_IS_SHARED>(NS_LITERAL_STRING("Argument of AudioContext.decodeAudioData")); return nullptr; } // Detach the array buffer size_t length = aBuffer.Length(); JS::RootedObject obj(cx, aBuffer.Obj()); uint8_t* data = static_cast<uint8_t*>(JS_StealArrayBufferContents(cx, obj)); // Sniff the content of the media. // Failed type sniffing will be handled by AsyncDecodeWebAudio. nsAutoCString contentType; NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, nullptr, data, length, contentType); RefPtr<DecodeErrorCallback> failureCallback; RefPtr<DecodeSuccessCallback> successCallback; if (aFailureCallback.WasPassed()) { failureCallback = &aFailureCallback.Value(); } if (aSuccessCallback.WasPassed()) { successCallback = &aSuccessCallback.Value(); } RefPtr<WebAudioDecodeJob> job( new WebAudioDecodeJob(contentType, this, promise, successCallback, failureCallback)); AsyncDecodeWebAudio(contentType.get(), data, length, *job); // Transfer the ownership to mDecodeJobs mDecodeJobs.AppendElement(job.forget()); return promise.forget(); }
bool TestStealContents() { JS::RootedObject obj(cx, CreateNewObject(8, 12)); CHECK(obj); void* contents = JS_StealArrayBufferContents(cx, obj); CHECK(contents); CHECK(memcmp(contents, test_data + 8, 12) == 0); CHECK(JS_IsDetachedArrayBufferObject(obj)); return true; }
already_AddRefed<ThreadSharedFloatArrayBufferList> AudioBuffer::StealJSArrayDataIntoSharedChannels(JSContext* aJSContext) { // "1. If any of the AudioBuffer's ArrayBuffer have been detached, abort // these steps, and return a zero-length channel data buffers to the // invoker." for (uint32_t i = 0; i < mJSChannels.Length(); ++i) { JSObject* channelArray = mJSChannels[i]; if (!channelArray || mLength != JS_GetTypedArrayLength(channelArray)) { // Either empty buffer or one of the arrays' buffers was detached. return nullptr; } } // "2. Detach all ArrayBuffers for arrays previously returned by // getChannelData on this AudioBuffer." // "3. Retain the underlying data buffers from those ArrayBuffers and return // references to them to the invoker." RefPtr<ThreadSharedFloatArrayBufferList> result = new ThreadSharedFloatArrayBufferList(mJSChannels.Length()); for (uint32_t i = 0; i < mJSChannels.Length(); ++i) { if (mJSChannels[i]) { JS::ExposeObjectToActiveJS(mJSChannels[i]); } JS::Rooted<JSObject*> arrayBufferView(aJSContext, mJSChannels[i]); bool isSharedMemory; JS::Rooted<JSObject*> arrayBuffer(aJSContext, JS_GetArrayBufferViewBuffer(aJSContext, arrayBufferView, &isSharedMemory)); if (arrayBuffer) { JS::ExposeObjectToActiveJS(arrayBuffer); } // The channel data arrays should all have originated in // RestoreJSChannelData, where they are created unshared. MOZ_ASSERT(!isSharedMemory); auto stolenData = arrayBuffer ? static_cast<float*>(JS_StealArrayBufferContents(aJSContext, arrayBuffer)) : nullptr; if (stolenData) { result->SetData(i, stolenData, js_free, stolenData); } else { NS_ASSERTION(i == 0, "some channels lost when contents not acquired"); return nullptr; } } for (uint32_t i = 0; i < mJSChannels.Length(); ++i) { mJSChannels[i] = nullptr; } return result.forget(); }
already_AddRefed<Promise> AudioContext::DecodeAudioData(const ArrayBuffer& aBuffer, const Optional<OwningNonNull<DecodeSuccessCallback> >& aSuccessCallback, const Optional<OwningNonNull<DecodeErrorCallback> >& aFailureCallback) { ErrorResult rv; nsCOMPtr<nsIGlobalObject> parentObject = do_QueryInterface(GetParentObject()); nsRefPtr<Promise> promise; AutoJSAPI jsapi; jsapi.Init(); JSContext* cx = jsapi.cx(); JSAutoCompartment ac(cx, aBuffer.Obj()); promise = Promise::Create(parentObject, rv); if (rv.Failed()) { return nullptr; } aBuffer.ComputeLengthAndData(); // Neuter the array buffer size_t length = aBuffer.Length(); JS::RootedObject obj(cx, aBuffer.Obj()); uint8_t* data = static_cast<uint8_t*>(JS_StealArrayBufferContents(cx, obj)); // Sniff the content of the media. // Failed type sniffing will be handled by AsyncDecodeMedia. nsAutoCString contentType; NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, nullptr, data, length, contentType); nsRefPtr<DecodeErrorCallback> failureCallback; nsRefPtr<DecodeSuccessCallback> successCallback; if (aFailureCallback.WasPassed()) { failureCallback = &aFailureCallback.Value(); } if (aSuccessCallback.WasPassed()) { successCallback = &aSuccessCallback.Value(); } nsRefPtr<WebAudioDecodeJob> job( new WebAudioDecodeJob(contentType, this, promise, successCallback, failureCallback)); mDecoder.AsyncDecodeMedia(contentType.get(), data, length, *job); // Transfer the ownership to mDecodeJobs mDecodeJobs.AppendElement(job.forget()); return promise.forget(); }
static already_AddRefed<ThreadSharedFloatArrayBufferList> StealJSArrayDataIntoThreadSharedFloatArrayBufferList(JSContext* aJSContext, const nsTArray<JSObject*>& aJSArrays) { nsRefPtr<ThreadSharedFloatArrayBufferList> result = new ThreadSharedFloatArrayBufferList(aJSArrays.Length()); for (uint32_t i = 0; i < aJSArrays.Length(); ++i) { JS::RootedObject arrayBuffer(aJSContext, JS_GetArrayBufferViewBuffer(aJSArrays[i])); void* dataToFree = nullptr; uint8_t* stolenData = nullptr; if (arrayBuffer && JS_StealArrayBufferContents(aJSContext, arrayBuffer, &dataToFree, &stolenData)) { result->SetData(i, dataToFree, reinterpret_cast<float*>(stolenData)); } else { return nullptr; } } return result.forget(); }