Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010, Google Inc. All rights reserved. | 2 * Copyright (C) 2010, Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 23 */ | 23 */ |
| 24 | 24 |
| 25 #include "config.h" | 25 #include "config.h" |
| 26 | 26 |
| 27 #if ENABLE(WEB_AUDIO) | 27 #if ENABLE(WEB_AUDIO) |
| 28 | 28 |
| 29 #include "modules/webaudio/AudioContext.h" | 29 #include "modules/webaudio/AudioContext.h" |
| 30 | 30 |
| 31 #include "bindings/v8/ExceptionMessages.h" | |
| 31 #include "bindings/v8/ExceptionState.h" | 32 #include "bindings/v8/ExceptionState.h" |
| 32 #include "core/dom/Document.h" | 33 #include "core/dom/Document.h" |
| 33 #include "core/dom/ExceptionCode.h" | 34 #include "core/dom/ExceptionCode.h" |
| 34 #include "core/html/HTMLMediaElement.h" | 35 #include "core/html/HTMLMediaElement.h" |
| 35 #include "core/inspector/ScriptCallStack.h" | 36 #include "core/inspector/ScriptCallStack.h" |
| 36 #include "core/platform/audio/FFTFrame.h" | 37 #include "core/platform/audio/FFTFrame.h" |
| 37 #include "core/platform/audio/HRTFDatabaseLoader.h" | 38 #include "core/platform/audio/HRTFDatabaseLoader.h" |
| 38 #include "core/platform/audio/HRTFPanner.h" | 39 #include "core/platform/audio/HRTFPanner.h" |
| 39 #include "modules/mediastream/MediaStream.h" | 40 #include "modules/mediastream/MediaStream.h" |
| 40 #include "modules/webaudio/AnalyserNode.h" | 41 #include "modules/webaudio/AnalyserNode.h" |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 286 // of dealing with all of its ActiveDOMObjects at this point. uninitialize() can de-reference other | 287 // of dealing with all of its ActiveDOMObjects at this point. uninitialize() can de-reference other |
| 287 // ActiveDOMObjects so let's schedule uninitialize() to be called later. | 288 // ActiveDOMObjects so let's schedule uninitialize() to be called later. |
| 288 // FIXME: see if there's a more direct way to handle this issue. | 289 // FIXME: see if there's a more direct way to handle this issue. |
| 289 callOnMainThread(stopDispatch, this); | 290 callOnMainThread(stopDispatch, this); |
| 290 } | 291 } |
| 291 | 292 |
| 292 PassRefPtr<AudioBuffer> AudioContext::createBuffer(unsigned numberOfChannels, si ze_t numberOfFrames, float sampleRate, ExceptionState& es) | 293 PassRefPtr<AudioBuffer> AudioContext::createBuffer(unsigned numberOfChannels, si ze_t numberOfFrames, float sampleRate, ExceptionState& es) |
| 293 { | 294 { |
| 294 RefPtr<AudioBuffer> audioBuffer = AudioBuffer::create(numberOfChannels, numb erOfFrames, sampleRate); | 295 RefPtr<AudioBuffer> audioBuffer = AudioBuffer::create(numberOfChannels, numb erOfFrames, sampleRate); |
| 295 if (!audioBuffer.get()) { | 296 if (!audioBuffer.get()) { |
| 296 es.throwUninformativeAndGenericDOMException(SyntaxError); | 297 es.throwDOMException( |
| 298 SyntaxError, | |
| 299 ExceptionMessages::failedToConstruct( | |
| 300 "AudioBuffer", | |
| 301 "invalid number of channels, frames, or sample rate.")); | |
|
Mike West
2013/09/27 06:44:39
For these kinds of errors, it would be nice to tel
Raymond Toy (Google)
2013/09/27 16:24:10
Agreed. I'll try to make this (and all others) mor
| |
| 297 return 0; | 302 return 0; |
| 298 } | 303 } |
| 299 | 304 |
| 300 return audioBuffer; | 305 return audioBuffer; |
| 301 } | 306 } |
| 302 | 307 |
| 303 PassRefPtr<AudioBuffer> AudioContext::createBuffer(ArrayBuffer* arrayBuffer, boo l mixToMono, ExceptionState& es) | 308 PassRefPtr<AudioBuffer> AudioContext::createBuffer(ArrayBuffer* arrayBuffer, boo l mixToMono, ExceptionState& es) |
| 304 { | 309 { |
| 305 ASSERT(arrayBuffer); | 310 ASSERT(arrayBuffer); |
| 306 if (!arrayBuffer) { | 311 if (!arrayBuffer) { |
| 307 es.throwUninformativeAndGenericDOMException(SyntaxError); | 312 es.throwDOMException( |
| 313 SyntaxError, | |
| 314 ExceptionMessages::failedToConstruct( | |
| 315 "AudioBuffer", | |
| 316 "invalid ArrayBuffer.")); | |
| 308 return 0; | 317 return 0; |
| 309 } | 318 } |
| 310 | 319 |
| 311 RefPtr<AudioBuffer> audioBuffer = AudioBuffer::createFromAudioFileData(array Buffer->data(), arrayBuffer->byteLength(), mixToMono, sampleRate()); | 320 RefPtr<AudioBuffer> audioBuffer = AudioBuffer::createFromAudioFileData(array Buffer->data(), arrayBuffer->byteLength(), mixToMono, sampleRate()); |
| 312 if (!audioBuffer.get()) { | 321 if (!audioBuffer.get()) { |
| 313 es.throwUninformativeAndGenericDOMException(SyntaxError); | 322 es.throwDOMException( |
| 323 SyntaxError, | |
| 324 ExceptionMessages::failedToConstruct( | |
| 325 "AudioBuffer", | |
| 326 "invalid audio data in ArrayBuffer.")); | |
| 314 return 0; | 327 return 0; |
| 315 } | 328 } |
| 316 | 329 |
| 317 return audioBuffer; | 330 return audioBuffer; |
| 318 } | 331 } |
| 319 | 332 |
| 320 void AudioContext::decodeAudioData(ArrayBuffer* audioData, PassRefPtr<AudioBuffe rCallback> successCallback, PassRefPtr<AudioBufferCallback> errorCallback, Excep tionState& es) | 333 void AudioContext::decodeAudioData(ArrayBuffer* audioData, PassRefPtr<AudioBuffe rCallback> successCallback, PassRefPtr<AudioBufferCallback> errorCallback, Excep tionState& es) |
| 321 { | 334 { |
| 322 if (!audioData) { | 335 if (!audioData) { |
| 323 es.throwUninformativeAndGenericDOMException(SyntaxError); | 336 es.throwDOMException( |
| 337 SyntaxError, | |
| 338 ExceptionMessages::failedToExecute( | |
| 339 "decodeAudioData", | |
| 340 "AudioContext", | |
| 341 "invalid ArrayBuffer for audioData.")); | |
| 324 return; | 342 return; |
| 325 } | 343 } |
| 326 m_audioDecoder.decodeAsync(audioData, sampleRate(), successCallback, errorCa llback); | 344 m_audioDecoder.decodeAsync(audioData, sampleRate(), successCallback, errorCa llback); |
| 327 } | 345 } |
| 328 | 346 |
| 329 PassRefPtr<AudioBufferSourceNode> AudioContext::createBufferSource() | 347 PassRefPtr<AudioBufferSourceNode> AudioContext::createBufferSource() |
| 330 { | 348 { |
| 331 ASSERT(isMainThread()); | 349 ASSERT(isMainThread()); |
| 332 lazyInitialize(); | 350 lazyInitialize(); |
| 333 RefPtr<AudioBufferSourceNode> node = AudioBufferSourceNode::create(this, m_d estinationNode->sampleRate()); | 351 RefPtr<AudioBufferSourceNode> node = AudioBufferSourceNode::create(this, m_d estinationNode->sampleRate()); |
| 334 | 352 |
| 335 // Because this is an AudioScheduledSourceNode, the context keeps a referenc e until it has finished playing. | 353 // Because this is an AudioScheduledSourceNode, the context keeps a referenc e until it has finished playing. |
| 336 // When this happens, AudioScheduledSourceNode::finish() calls AudioContext: :notifyNodeFinishedProcessing(). | 354 // When this happens, AudioScheduledSourceNode::finish() calls AudioContext: :notifyNodeFinishedProcessing(). |
| 337 refNode(node.get()); | 355 refNode(node.get()); |
| 338 | 356 |
| 339 return node; | 357 return node; |
| 340 } | 358 } |
| 341 | 359 |
| 342 PassRefPtr<MediaElementAudioSourceNode> AudioContext::createMediaElementSource(H TMLMediaElement* mediaElement, ExceptionState& es) | 360 PassRefPtr<MediaElementAudioSourceNode> AudioContext::createMediaElementSource(H TMLMediaElement* mediaElement, ExceptionState& es) |
| 343 { | 361 { |
| 344 ASSERT(mediaElement); | |
|
Mike West
2013/09/27 06:44:39
Why drop the ASSERT?
Raymond Toy (Google)
2013/09/27 16:24:10
When running the webaudio layout tests in debug mo
| |
| 345 if (!mediaElement) { | 362 if (!mediaElement) { |
| 346 es.throwUninformativeAndGenericDOMException(InvalidStateError); | 363 es.throwDOMException( |
| 364 InvalidStateError, | |
| 365 ExceptionMessages::failedToConstruct( | |
| 366 "MediaElementAudioSourceNode", | |
| 367 "invalid HTMLMedialElement.")); | |
| 347 return 0; | 368 return 0; |
| 348 } | 369 } |
| 349 | 370 |
| 350 ASSERT(isMainThread()); | 371 ASSERT(isMainThread()); |
| 351 lazyInitialize(); | 372 lazyInitialize(); |
| 352 | 373 |
| 353 // First check if this media element already has a source node. | 374 // First check if this media element already has a source node. |
| 354 if (mediaElement->audioSourceNode()) { | 375 if (mediaElement->audioSourceNode()) { |
| 355 es.throwUninformativeAndGenericDOMException(InvalidStateError); | 376 es.throwDOMException( |
| 377 InvalidStateError, | |
| 378 ExceptionMessages::failedToConstruct( | |
| 379 "MediaElementAudioSourceNode", | |
| 380 "invalid HTMLMediaElement.")); | |
| 356 return 0; | 381 return 0; |
| 357 } | 382 } |
| 358 | 383 |
| 359 RefPtr<MediaElementAudioSourceNode> node = MediaElementAudioSourceNode::crea te(this, mediaElement); | 384 RefPtr<MediaElementAudioSourceNode> node = MediaElementAudioSourceNode::crea te(this, mediaElement); |
| 360 | 385 |
| 361 mediaElement->setAudioSourceNode(node.get()); | 386 mediaElement->setAudioSourceNode(node.get()); |
| 362 | 387 |
| 363 refNode(node.get()); // context keeps reference until node is disconnected | 388 refNode(node.get()); // context keeps reference until node is disconnected |
| 364 return node; | 389 return node; |
| 365 } | 390 } |
| 366 | 391 |
| 367 PassRefPtr<MediaStreamAudioSourceNode> AudioContext::createMediaStreamSource(Med iaStream* mediaStream, ExceptionState& es) | 392 PassRefPtr<MediaStreamAudioSourceNode> AudioContext::createMediaStreamSource(Med iaStream* mediaStream, ExceptionState& es) |
| 368 { | 393 { |
| 369 ASSERT(mediaStream); | |
| 370 if (!mediaStream) { | 394 if (!mediaStream) { |
| 371 es.throwUninformativeAndGenericDOMException(InvalidStateError); | 395 es.throwDOMException( |
| 396 InvalidStateError, | |
| 397 ExceptionMessages::failedToConstruct("MediaStreamAudioSourceNode")); | |
|
Mike West
2013/09/27 06:44:39
"invalid MediaStream source"?
| |
| 372 return 0; | 398 return 0; |
| 373 } | 399 } |
| 374 | 400 |
| 375 ASSERT(isMainThread()); | 401 ASSERT(isMainThread()); |
| 376 lazyInitialize(); | 402 lazyInitialize(); |
| 377 | 403 |
| 378 AudioSourceProvider* provider = 0; | 404 AudioSourceProvider* provider = 0; |
| 379 | 405 |
| 380 MediaStreamTrackVector audioTracks = mediaStream->getAudioTracks(); | 406 MediaStreamTrackVector audioTracks = mediaStream->getAudioTracks(); |
| 381 | 407 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 416 return createScriptProcessor(bufferSize, numberOfInputChannels, 2, es); | 442 return createScriptProcessor(bufferSize, numberOfInputChannels, 2, es); |
| 417 } | 443 } |
| 418 | 444 |
| 419 PassRefPtr<ScriptProcessorNode> AudioContext::createScriptProcessor(size_t buffe rSize, size_t numberOfInputChannels, size_t numberOfOutputChannels, ExceptionSta te& es) | 445 PassRefPtr<ScriptProcessorNode> AudioContext::createScriptProcessor(size_t buffe rSize, size_t numberOfInputChannels, size_t numberOfOutputChannels, ExceptionSta te& es) |
| 420 { | 446 { |
| 421 ASSERT(isMainThread()); | 447 ASSERT(isMainThread()); |
| 422 lazyInitialize(); | 448 lazyInitialize(); |
| 423 RefPtr<ScriptProcessorNode> node = ScriptProcessorNode::create(this, m_desti nationNode->sampleRate(), bufferSize, numberOfInputChannels, numberOfOutputChann els); | 449 RefPtr<ScriptProcessorNode> node = ScriptProcessorNode::create(this, m_desti nationNode->sampleRate(), bufferSize, numberOfInputChannels, numberOfOutputChann els); |
| 424 | 450 |
| 425 if (!node.get()) { | 451 if (!node.get()) { |
| 426 es.throwUninformativeAndGenericDOMException(SyntaxError); | 452 es.throwDOMException( |
| 453 SyntaxError, | |
| 454 ExceptionMessages::failedToConstruct( | |
| 455 "ScriptProcessorNode", | |
| 456 "invalid buffer size, or number of input/outputs.")); | |
| 427 return 0; | 457 return 0; |
| 428 } | 458 } |
| 429 | 459 |
| 430 refNode(node.get()); // context keeps reference until we stop making javascr ipt rendering callbacks | 460 refNode(node.get()); // context keeps reference until we stop making javascr ipt rendering callbacks |
| 431 return node; | 461 return node; |
| 432 } | 462 } |
| 433 | 463 |
| 434 PassRefPtr<BiquadFilterNode> AudioContext::createBiquadFilter() | 464 PassRefPtr<BiquadFilterNode> AudioContext::createBiquadFilter() |
| 435 { | 465 { |
| 436 ASSERT(isMainThread()); | 466 ASSERT(isMainThread()); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 503 } | 533 } |
| 504 | 534 |
| 505 PassRefPtr<ChannelSplitterNode> AudioContext::createChannelSplitter(size_t numbe rOfOutputs, ExceptionState& es) | 535 PassRefPtr<ChannelSplitterNode> AudioContext::createChannelSplitter(size_t numbe rOfOutputs, ExceptionState& es) |
| 506 { | 536 { |
| 507 ASSERT(isMainThread()); | 537 ASSERT(isMainThread()); |
| 508 lazyInitialize(); | 538 lazyInitialize(); |
| 509 | 539 |
| 510 RefPtr<ChannelSplitterNode> node = ChannelSplitterNode::create(this, m_desti nationNode->sampleRate(), numberOfOutputs); | 540 RefPtr<ChannelSplitterNode> node = ChannelSplitterNode::create(this, m_desti nationNode->sampleRate(), numberOfOutputs); |
| 511 | 541 |
| 512 if (!node.get()) { | 542 if (!node.get()) { |
| 513 es.throwUninformativeAndGenericDOMException(SyntaxError); | 543 es.throwDOMException( |
| 544 SyntaxError, | |
| 545 ExceptionMessages::failedToConstruct( | |
| 546 "ChannelSplitterNode", | |
| 547 "invalid number of outputs.")); | |
|
Mike West
2013/09/27 06:44:39
"The number of outputs (" + String::number(numberO
| |
| 514 return 0; | 548 return 0; |
| 515 } | 549 } |
| 516 | 550 |
| 517 return node; | 551 return node; |
| 518 } | 552 } |
| 519 | 553 |
| 520 PassRefPtr<ChannelMergerNode> AudioContext::createChannelMerger(ExceptionState& es) | 554 PassRefPtr<ChannelMergerNode> AudioContext::createChannelMerger(ExceptionState& es) |
| 521 { | 555 { |
| 522 const unsigned ChannelMergerDefaultNumberOfInputs = 6; | 556 const unsigned ChannelMergerDefaultNumberOfInputs = 6; |
| 523 return createChannelMerger(ChannelMergerDefaultNumberOfInputs, es); | 557 return createChannelMerger(ChannelMergerDefaultNumberOfInputs, es); |
| 524 } | 558 } |
| 525 | 559 |
| 526 PassRefPtr<ChannelMergerNode> AudioContext::createChannelMerger(size_t numberOfI nputs, ExceptionState& es) | 560 PassRefPtr<ChannelMergerNode> AudioContext::createChannelMerger(size_t numberOfI nputs, ExceptionState& es) |
| 527 { | 561 { |
| 528 ASSERT(isMainThread()); | 562 ASSERT(isMainThread()); |
| 529 lazyInitialize(); | 563 lazyInitialize(); |
| 530 | 564 |
| 531 RefPtr<ChannelMergerNode> node = ChannelMergerNode::create(this, m_destinati onNode->sampleRate(), numberOfInputs); | 565 RefPtr<ChannelMergerNode> node = ChannelMergerNode::create(this, m_destinati onNode->sampleRate(), numberOfInputs); |
| 532 | 566 |
| 533 if (!node.get()) { | 567 if (!node.get()) { |
| 534 es.throwUninformativeAndGenericDOMException(SyntaxError); | 568 es.throwDOMException( |
| 569 SyntaxError, | |
| 570 ExceptionMessages::failedToConstruct( | |
| 571 "ChannelMergerNode", | |
| 572 "invalid number of inputs.")); | |
|
Mike West
2013/09/27 06:44:39
Same as for outputs.
| |
| 535 return 0; | 573 return 0; |
| 536 } | 574 } |
| 537 | 575 |
| 538 return node; | 576 return node; |
| 539 } | 577 } |
| 540 | 578 |
| 541 PassRefPtr<OscillatorNode> AudioContext::createOscillator() | 579 PassRefPtr<OscillatorNode> AudioContext::createOscillator() |
| 542 { | 580 { |
| 543 ASSERT(isMainThread()); | 581 ASSERT(isMainThread()); |
| 544 lazyInitialize(); | 582 lazyInitialize(); |
| 545 | 583 |
| 546 RefPtr<OscillatorNode> node = OscillatorNode::create(this, m_destinationNode ->sampleRate()); | 584 RefPtr<OscillatorNode> node = OscillatorNode::create(this, m_destinationNode ->sampleRate()); |
| 547 | 585 |
| 548 // Because this is an AudioScheduledSourceNode, the context keeps a referenc e until it has finished playing. | 586 // Because this is an AudioScheduledSourceNode, the context keeps a referenc e until it has finished playing. |
| 549 // When this happens, AudioScheduledSourceNode::finish() calls AudioContext: :notifyNodeFinishedProcessing(). | 587 // When this happens, AudioScheduledSourceNode::finish() calls AudioContext: :notifyNodeFinishedProcessing(). |
| 550 refNode(node.get()); | 588 refNode(node.get()); |
| 551 | 589 |
| 552 return node; | 590 return node; |
| 553 } | 591 } |
| 554 | 592 |
| 555 PassRefPtr<PeriodicWave> AudioContext::createPeriodicWave(Float32Array* real, Fl oat32Array* imag, ExceptionState& es) | 593 PassRefPtr<PeriodicWave> AudioContext::createPeriodicWave(Float32Array* real, Fl oat32Array* imag, ExceptionState& es) |
| 556 { | 594 { |
| 557 ASSERT(isMainThread()); | 595 ASSERT(isMainThread()); |
| 558 | 596 |
| 559 if (!real || !imag || (real->length() != imag->length())) { | 597 if (!real || !imag || (real->length() != imag->length())) { |
| 560 es.throwUninformativeAndGenericDOMException(SyntaxError); | 598 es.throwDOMException( |
| 599 SyntaxError, | |
| 600 ExceptionMessages::failedToConstruct( | |
| 601 "WaveTable", | |
| 602 "invalid real or imag arrays for wave table.")); | |
|
Mike West
2013/09/27 06:44:39
One option would be to split this up into multiple
| |
| 561 return 0; | 603 return 0; |
| 562 } | 604 } |
| 563 | 605 |
| 564 lazyInitialize(); | 606 lazyInitialize(); |
| 565 return PeriodicWave::create(sampleRate(), real, imag); | 607 return PeriodicWave::create(sampleRate(), real, imag); |
| 566 } | 608 } |
| 567 | 609 |
| 568 void AudioContext::notifyNodeFinishedProcessing(AudioNode* node) | 610 void AudioContext::notifyNodeFinishedProcessing(AudioNode* node) |
| 569 { | 611 { |
| 570 ASSERT(isAudioThread()); | 612 ASSERT(isAudioThread()); |
| (...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 951 } | 993 } |
| 952 | 994 |
| 953 void AudioContext::decrementActiveSourceCount() | 995 void AudioContext::decrementActiveSourceCount() |
| 954 { | 996 { |
| 955 atomicDecrement(&m_activeSourceCount); | 997 atomicDecrement(&m_activeSourceCount); |
| 956 } | 998 } |
| 957 | 999 |
| 958 } // namespace WebCore | 1000 } // namespace WebCore |
| 959 | 1001 |
| 960 #endif // ENABLE(WEB_AUDIO) | 1002 #endif // ENABLE(WEB_AUDIO) |
| OLD | NEW |