MediaStreamAudioSourceNode* AudioContext::createMediaStreamSource(MediaStream* mediaStream, ExceptionState& exceptionState) { ASSERT(isMainThread()); if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return nullptr; } if (!mediaStream) { exceptionState.throwDOMException( InvalidStateError, "invalid MediaStream source"); return nullptr; } MediaStreamTrackVector audioTracks = mediaStream->getAudioTracks(); if (audioTracks.isEmpty()) { exceptionState.throwDOMException( InvalidStateError, "MediaStream has no audio track"); return nullptr; } // Use the first audio track in the media stream. MediaStreamTrack* audioTrack = audioTracks[0]; OwnPtr<AudioSourceProvider> provider = audioTrack->createWebAudioSource(); MediaStreamAudioSourceNode* node = MediaStreamAudioSourceNode::create(this, mediaStream, audioTrack, provider.release()); // FIXME: Only stereo streams are supported right now. We should be able to accept multi-channel streams. node->mediaStreamAudioSourceHandler().setFormat(2, sampleRate()); refNode(node); // context keeps reference until node is disconnected return node; }
MediaElementAudioSourceNode* AudioContext::createMediaElementSource(HTMLMediaElement* mediaElement, ExceptionState& exceptionState) { ASSERT(isMainThread()); if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return nullptr; } if (!mediaElement) { exceptionState.throwDOMException( InvalidStateError, "invalid HTMLMedialElement."); return nullptr; } // First check if this media element already has a source node. if (mediaElement->audioSourceNode()) { exceptionState.throwDOMException( InvalidStateError, "HTMLMediaElement already connected previously to a different MediaElementSourceNode."); return nullptr; } MediaElementAudioSourceNode* node = MediaElementAudioSourceNode::create(this, mediaElement); mediaElement->setAudioSourceNode(&node->mediaElementAudioSourceHandler()); refNode(node); // context keeps reference until node is disconnected return node; }
ChannelMergerNode* AbstractAudioContext::createChannelMerger(size_t numberOfInputs, ExceptionState& exceptionState) { ASSERT(isMainThread()); if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return nullptr; } ChannelMergerNode* node = ChannelMergerNode::create(*this, sampleRate(), numberOfInputs); if (!node) { exceptionState.throwDOMException( IndexSizeError, ExceptionMessages::indexOutsideRange<size_t>( "number of inputs", numberOfInputs, 1, ExceptionMessages::InclusiveBound, AbstractAudioContext::maxNumberOfChannels(), ExceptionMessages::InclusiveBound)); return nullptr; } return node; }
PeriodicWave* AudioContext::createPeriodicWave(DOMFloat32Array* real, DOMFloat32Array* imag, ExceptionState& exceptionState) { ASSERT(isMainThread()); if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return nullptr; } if (!real) { exceptionState.throwDOMException( SyntaxError, "invalid real array"); return nullptr; } if (!imag) { exceptionState.throwDOMException( SyntaxError, "invalid imaginary array"); return nullptr; } if (real->length() > PeriodicWave::kMaxPeriodicWaveArraySize) { exceptionState.throwDOMException( IndexSizeError, ExceptionMessages::indexOutsideRange( "length of the real part array", real->length(), 1u, ExceptionMessages::InclusiveBound, PeriodicWave::kMaxPeriodicWaveArraySize, ExceptionMessages::InclusiveBound)); return nullptr; } if (imag->length() > PeriodicWave::kMaxPeriodicWaveArraySize) { exceptionState.throwDOMException( IndexSizeError, ExceptionMessages::indexOutsideRange( "length of the imaginary part array", imag->length(), 1u, ExceptionMessages::InclusiveBound, PeriodicWave::kMaxPeriodicWaveArraySize, ExceptionMessages::InclusiveBound)); return nullptr; } if (real->length() != imag->length()) { exceptionState.throwDOMException( IndexSizeError, "length of real array (" + String::number(real->length()) + ") and length of imaginary array (" + String::number(imag->length()) + ") must match."); return nullptr; } return PeriodicWave::create(sampleRate(), real, imag); }
ScriptProcessorNode* AudioContext::createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, ExceptionState& exceptionState) { if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return nullptr; } // Set number of output channels to stereo by default. return createScriptProcessor(bufferSize, numberOfInputChannels, 2, exceptionState); }
AnalyserNode* AbstractAudioContext::createAnalyser(ExceptionState& exceptionState) { ASSERT(isMainThread()); if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return nullptr; } return AnalyserNode::create(*this, sampleRate()); }
GainNode* AudioContext::createGain(ExceptionState& exceptionState) { ASSERT(isMainThread()); if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return nullptr; } return GainNode::create(this, sampleRate()); }
ChannelMergerNode* AudioContext::createChannelMerger(ExceptionState& exceptionState) { if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return nullptr; } const unsigned ChannelMergerDefaultNumberOfInputs = 6; return createChannelMerger(ChannelMergerDefaultNumberOfInputs, exceptionState); }
DelayNode* AudioContext::createDelay(ExceptionState& exceptionState) { if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return nullptr; } const double defaultMaxDelayTime = 1; return createDelay(defaultMaxDelayTime, exceptionState); }
DelayNode* AbstractAudioContext::createDelay(double maxDelayTime, ExceptionState& exceptionState) { ASSERT(isMainThread()); if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return nullptr; } return DelayNode::create(*this, sampleRate(), maxDelayTime, exceptionState); }
WaveShaperNode* AudioContext::createWaveShaper(ExceptionState& exceptionState) { ASSERT(isMainThread()); if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return nullptr; } return WaveShaperNode::create(this); }
ScriptProcessorNode* AudioContext::createScriptProcessor(ExceptionState& exceptionState) { if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return nullptr; } // Set number of input/output channels to stereo by default. return createScriptProcessor(0, 2, 2, exceptionState); }
MediaStreamAudioDestinationNode* AudioContext::createMediaStreamDestination(ExceptionState& exceptionState) { if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return nullptr; } // Set number of output channels to stereo by default. return MediaStreamAudioDestinationNode::create(this, 2); }
DelayNode* AudioContext::createDelay(double maxDelayTime, ExceptionState& exceptionState) { ASSERT(isMainThread()); if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return nullptr; } DelayNode* node = DelayNode::create(this, sampleRate(), maxDelayTime, exceptionState); if (exceptionState.hadException()) return nullptr; return node; }
OscillatorNode* AudioContext::createOscillator(ExceptionState& exceptionState) { ASSERT(isMainThread()); if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return nullptr; } OscillatorNode* node = OscillatorNode::create(this, sampleRate()); // Do not add a reference to this source node now. The reference will be added when start() is // called. return node; }
void AudioContext::decodeAudioData(DOMArrayBuffer* audioData, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback, ExceptionState& exceptionState) { if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return; } if (!audioData) { exceptionState.throwDOMException( SyntaxError, "invalid ArrayBuffer for audioData."); return; } m_audioDecoder.decodeAsync(audioData, sampleRate(), successCallback, errorCallback); }
ChannelMergerNode* AudioContext::createChannelMerger(size_t numberOfInputs, ExceptionState& exceptionState) { ASSERT(isMainThread()); if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return nullptr; } ChannelMergerNode* node = ChannelMergerNode::create(this, sampleRate(), numberOfInputs); if (!node) { exceptionState.throwDOMException( IndexSizeError, "number of inputs (" + String::number(numberOfInputs) + ") must be between 1 and " + String::number(AudioContext::maxNumberOfChannels()) + "."); return nullptr; } return node; }
ScriptProcessorNode* AudioContext::createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, size_t numberOfOutputChannels, ExceptionState& exceptionState) { ASSERT(isMainThread()); if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return nullptr; } ScriptProcessorNode* node = ScriptProcessorNode::create(this, sampleRate(), bufferSize, numberOfInputChannels, numberOfOutputChannels); if (!node) { if (!numberOfInputChannels && !numberOfOutputChannels) { exceptionState.throwDOMException( IndexSizeError, "number of input channels and output channels cannot both be zero."); } else if (numberOfInputChannels > AudioContext::maxNumberOfChannels()) { exceptionState.throwDOMException( IndexSizeError, "number of input channels (" + String::number(numberOfInputChannels) + ") exceeds maximum (" + String::number(AudioContext::maxNumberOfChannels()) + ")."); } else if (numberOfOutputChannels > AudioContext::maxNumberOfChannels()) { exceptionState.throwDOMException( IndexSizeError, "number of output channels (" + String::number(numberOfInputChannels) + ") exceeds maximum (" + String::number(AudioContext::maxNumberOfChannels()) + ")."); } else { exceptionState.throwDOMException( IndexSizeError, "buffer size (" + String::number(bufferSize) + ") must be a power of two between 256 and 16384."); } return nullptr; } refNode(node); // context keeps reference until we stop making javascript rendering callbacks return node; }
PeriodicWave* AbstractAudioContext::createPeriodicWave(DOMFloat32Array* real, DOMFloat32Array* imag, const Dictionary& options, ExceptionState& exceptionState) { ASSERT(isMainThread()); if (isContextClosed()) { throwExceptionForClosedState(exceptionState); return nullptr; } if (!real) { exceptionState.throwDOMException( SyntaxError, "invalid real array"); return nullptr; } if (!imag) { exceptionState.throwDOMException( SyntaxError, "invalid imaginary array"); return nullptr; } if (real->length() != imag->length()) { exceptionState.throwDOMException( IndexSizeError, "length of real array (" + String::number(real->length()) + ") and length of imaginary array (" + String::number(imag->length()) + ") must match."); return nullptr; } bool isNormalizationDisabled = false; DictionaryHelper::getWithUndefinedOrNullCheck(options, "disableNormalization", isNormalizationDisabled); return PeriodicWave::create(sampleRate(), real, imag, isNormalizationDisabled); }