| 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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 45 | 45 |
| 46 unsigned AudioNode::s_instanceCount = 0; | 46 unsigned AudioNode::s_instanceCount = 0; |
| 47 | 47 |
| 48 AudioNode::AudioNode(AudioContext* context, float sampleRate) | 48 AudioNode::AudioNode(AudioContext* context, float sampleRate) |
| 49 : m_isInitialized(false) | 49 : m_isInitialized(false) |
| 50 , m_nodeType(NodeTypeUnknown) | 50 , m_nodeType(NodeTypeUnknown) |
| 51 , m_context(context) | 51 , m_context(context) |
| 52 , m_sampleRate(sampleRate) | 52 , m_sampleRate(sampleRate) |
| 53 , m_lastProcessingTime(-1) | 53 , m_lastProcessingTime(-1) |
| 54 , m_lastNonSilentTime(-1) | 54 , m_lastNonSilentTime(-1) |
| 55 #if !ENABLE(OILPAN) | |
| 56 , m_normalRefCount(1) // start out with normal refCount == 1 (like WTF::RefC
ounted class) | |
| 57 #endif | |
| 58 , m_connectionRefCount(0) | 55 , m_connectionRefCount(0) |
| 59 , m_isDisabled(false) | 56 , m_isDisabled(false) |
| 60 , m_isDisposeCalled(false) | 57 , m_isDisposeCalled(false) |
| 61 , m_channelCount(2) | 58 , m_channelCount(2) |
| 62 , m_channelCountMode(Max) | 59 , m_channelCountMode(Max) |
| 63 , m_channelInterpretation(AudioBus::Speakers) | 60 , m_channelInterpretation(AudioBus::Speakers) |
| 64 { | 61 { |
| 65 ScriptWrappable::init(this); | 62 ScriptWrappable::init(this); |
| 66 #if ENABLE(OILPAN) | |
| 67 m_context->registerLiveNode(*this); | 63 m_context->registerLiveNode(*this); |
| 68 #endif | |
| 69 #if DEBUG_AUDIONODE_REFERENCES | 64 #if DEBUG_AUDIONODE_REFERENCES |
| 70 if (!s_isNodeCountInitialized) { | 65 if (!s_isNodeCountInitialized) { |
| 71 s_isNodeCountInitialized = true; | 66 s_isNodeCountInitialized = true; |
| 72 atexit(AudioNode::printNodeCounts); | 67 atexit(AudioNode::printNodeCounts); |
| 73 } | 68 } |
| 74 #endif | 69 #endif |
| 75 ++s_instanceCount; | 70 ++s_instanceCount; |
| 76 } | 71 } |
| 77 | 72 |
| 78 AudioNode::~AudioNode() | 73 AudioNode::~AudioNode() |
| 79 { | 74 { |
| 80 ASSERT(m_isDisposeCalled); | 75 ASSERT(m_isDisposeCalled); |
| 81 --s_instanceCount; | 76 --s_instanceCount; |
| 82 #if DEBUG_AUDIONODE_REFERENCES | 77 #if DEBUG_AUDIONODE_REFERENCES |
| 83 --s_nodeCount[nodeType()]; | 78 --s_nodeCount[nodeType()]; |
| 84 #if ENABLE(OILPAN) | |
| 85 fprintf(stderr, "%p: %d: AudioNode::~AudioNode() %d\n", this, nodeType(), m_
connectionRefCount); | 79 fprintf(stderr, "%p: %d: AudioNode::~AudioNode() %d\n", this, nodeType(), m_
connectionRefCount); |
| 86 #else | |
| 87 fprintf(stderr, "%p: %d: AudioNode::~AudioNode() %d %d\n", this, nodeType(),
m_normalRefCount, m_connectionRefCount); | |
| 88 #endif | |
| 89 #endif | 80 #endif |
| 90 } | 81 } |
| 91 | 82 |
| 92 void AudioNode::initialize() | 83 void AudioNode::initialize() |
| 93 { | 84 { |
| 94 m_isInitialized = true; | 85 m_isInitialized = true; |
| 95 } | 86 } |
| 96 | 87 |
| 97 void AudioNode::uninitialize() | 88 void AudioNode::uninitialize() |
| 98 { | 89 { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 #if DEBUG_AUDIONODE_REFERENCES | 160 #if DEBUG_AUDIONODE_REFERENCES |
| 170 ++s_nodeCount[type]; | 161 ++s_nodeCount[type]; |
| 171 #endif | 162 #endif |
| 172 } | 163 } |
| 173 | 164 |
| 174 void AudioNode::addInput() | 165 void AudioNode::addInput() |
| 175 { | 166 { |
| 176 m_inputs.append(AudioNodeInput::create(*this)); | 167 m_inputs.append(AudioNodeInput::create(*this)); |
| 177 } | 168 } |
| 178 | 169 |
| 179 void AudioNode::addOutput(PassOwnPtrWillBeRawPtr<AudioNodeOutput> output) | 170 void AudioNode::addOutput(AudioNodeOutput* output) |
| 180 { | 171 { |
| 181 m_outputs.append(output); | 172 m_outputs.append(output); |
| 182 } | 173 } |
| 183 | 174 |
| 184 AudioNodeInput* AudioNode::input(unsigned i) | 175 AudioNodeInput* AudioNode::input(unsigned i) |
| 185 { | 176 { |
| 186 if (i < m_inputs.size()) | 177 if (i < m_inputs.size()) |
| 187 return m_inputs[i].get(); | 178 return m_inputs[i].get(); |
| 188 return 0; | 179 return 0; |
| 189 } | 180 } |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 466 | 457 |
| 467 m_isDisabled = false; | 458 m_isDisabled = false; |
| 468 for (unsigned i = 0; i < m_outputs.size(); ++i) | 459 for (unsigned i = 0; i < m_outputs.size(); ++i) |
| 469 output(i)->enable(); | 460 output(i)->enable(); |
| 470 } | 461 } |
| 471 } | 462 } |
| 472 | 463 |
| 473 void AudioNode::disableOutputsIfNecessary() | 464 void AudioNode::disableOutputsIfNecessary() |
| 474 { | 465 { |
| 475 // Disable outputs if appropriate. We do this if the number of connections i
s 0 or 1. The case | 466 // Disable outputs if appropriate. We do this if the number of connections i
s 0 or 1. The case |
| 476 // of 0 is from finishDeref() where there are no connections left. The case
of 1 is from | 467 // of 0 is from deref() where there are no connections left. The case of 1 i
s from |
| 477 // AudioNodeInput::disable() where we want to disable outputs when there's o
nly one connection | 468 // AudioNodeInput::disable() where we want to disable outputs when there's o
nly one connection |
| 478 // left because we're ready to go away, but can't quite yet. | 469 // left because we're ready to go away, but can't quite yet. |
| 479 if (m_connectionRefCount <= 1 && !m_isDisabled) { | 470 if (m_connectionRefCount <= 1 && !m_isDisabled) { |
| 480 // Still may have JavaScript references, but no more "active" connection
references, so put all of our outputs in a "dormant" disabled state. | 471 // Still may have JavaScript references, but no more "active" connection
references, so put all of our outputs in a "dormant" disabled state. |
| 481 // Garbage collection may take a very long time after this time, so the
"dormant" disabled nodes should not bog down the rendering... | 472 // Garbage collection may take a very long time after this time, so the
"dormant" disabled nodes should not bog down the rendering... |
| 482 | 473 |
| 483 // As far as JavaScript is concerned, our outputs must still appear to b
e connected. | 474 // As far as JavaScript is concerned, our outputs must still appear to b
e connected. |
| 484 // But internally our outputs should be disabled from the inputs they're
connected to. | 475 // But internally our outputs should be disabled from the inputs they're
connected to. |
| 485 // disable() can recursively deref connections (and call disable()) down
a whole chain of connected nodes. | 476 // disable() can recursively deref connections (and call disable()) down
a whole chain of connected nodes. |
| 486 | 477 |
| 487 // FIXME: we special case the convolver and delay since they have a sign
ificant tail-time and shouldn't be disconnected simply | 478 // FIXME: we special case the convolver and delay since they have a sign
ificant tail-time and shouldn't be disconnected simply |
| 488 // because they no longer have any input connections. This needs to be h
andled more generally where AudioNodes have | 479 // because they no longer have any input connections. This needs to be h
andled more generally where AudioNodes have |
| 489 // a tailTime attribute. Then the AudioNode only needs to remain "active
" for tailTime seconds after there are no | 480 // a tailTime attribute. Then the AudioNode only needs to remain "active
" for tailTime seconds after there are no |
| 490 // longer any active connections. | 481 // longer any active connections. |
| 491 if (nodeType() != NodeTypeConvolver && nodeType() != NodeTypeDelay) { | 482 if (nodeType() != NodeTypeConvolver && nodeType() != NodeTypeDelay) { |
| 492 m_isDisabled = true; | 483 m_isDisabled = true; |
| 493 for (unsigned i = 0; i < m_outputs.size(); ++i) | 484 for (unsigned i = 0; i < m_outputs.size(); ++i) |
| 494 output(i)->disable(); | 485 output(i)->disable(); |
| 495 } | 486 } |
| 496 } | 487 } |
| 497 } | 488 } |
| 498 | 489 |
| 499 #if !ENABLE(OILPAN) | |
| 500 void AudioNode::ref() | |
| 501 { | |
| 502 atomicIncrement(&m_normalRefCount); | |
| 503 | |
| 504 #if DEBUG_AUDIONODE_REFERENCES | |
| 505 fprintf(stderr, "%p: %d: AudioNode::ref() %d %d\n", this, nodeType(), m_norm
alRefCount, m_connectionRefCount); | |
| 506 #endif | |
| 507 } | |
| 508 #endif | |
| 509 | |
| 510 void AudioNode::makeConnection() | 490 void AudioNode::makeConnection() |
| 511 { | 491 { |
| 512 atomicIncrement(&m_connectionRefCount); | 492 atomicIncrement(&m_connectionRefCount); |
| 513 // See the disabling code in finishDeref() below. This handles the case | 493 // See the disabling code in disableOutputsIfNecessary(). This handles |
| 514 // where a node is being re-connected after being used at least once and | 494 // the case where a node is being re-connected after being used at least |
| 515 // disconnected. In this case, we need to re-enable. | 495 // once and disconnected. In this case, we need to re-enable. |
| 516 enableOutputsIfNecessary(); | 496 enableOutputsIfNecessary(); |
| 517 } | 497 } |
| 518 | 498 |
| 519 #if !ENABLE(OILPAN) | |
| 520 void AudioNode::deref() | |
| 521 { | |
| 522 // The actual work for deref happens completely within the audio context's | |
| 523 // graph lock. In the case of the audio thread, we must use a tryLock to | |
| 524 // avoid glitches. | |
| 525 bool hasLock = false; | |
| 526 bool mustReleaseLock = false; | |
| 527 | |
| 528 if (context()->isAudioThread()) { | |
| 529 // Real-time audio thread must not contend lock (to avoid glitches). | |
| 530 hasLock = context()->tryLock(mustReleaseLock); | |
| 531 } else { | |
| 532 context()->lock(mustReleaseLock); | |
| 533 hasLock = true; | |
| 534 } | |
| 535 | |
| 536 if (hasLock) { | |
| 537 // This is where the real deref work happens. | |
| 538 finishDeref(); | |
| 539 | |
| 540 if (mustReleaseLock) | |
| 541 context()->unlock(); | |
| 542 } else { | |
| 543 // We were unable to get the lock, so put this in a list to finish up la
ter. | |
| 544 ASSERT(context()->isAudioThread()); | |
| 545 context()->addDeferredFinishDeref(this); | |
| 546 } | |
| 547 | |
| 548 // Once AudioContext::uninitialize() is called there's no more chances for d
eleteMarkedNodes() to get called, so we call here. | |
| 549 // We can't call in AudioContext::~AudioContext() since it will never be cal
led as long as any AudioNode is alive | |
| 550 // because AudioNodes keep a reference to the context. | |
| 551 if (!context()->isInitialized()) | |
| 552 context()->deleteMarkedNodes(); | |
| 553 } | |
| 554 #endif | |
| 555 | |
| 556 void AudioNode::breakConnection() | 499 void AudioNode::breakConnection() |
| 557 { | 500 { |
| 558 // The actual work for deref happens completely within the audio context's | 501 // The actual work for deref happens completely within the audio context's |
| 559 // graph lock. In the case of the audio thread, we must use a tryLock to | 502 // graph lock. In the case of the audio thread, we must use a tryLock to |
| 560 // avoid glitches. | 503 // avoid glitches. |
| 561 bool hasLock = false; | 504 bool hasLock = false; |
| 562 bool mustReleaseLock = false; | 505 bool mustReleaseLock = false; |
| 563 | 506 |
| 564 if (context()->isAudioThread()) { | 507 if (context()->isAudioThread()) { |
| 565 // Real-time audio thread must not contend lock (to avoid glitches). | 508 // Real-time audio thread must not contend lock (to avoid glitches). |
| (...skipping 12 matching lines...) Expand all Loading... |
| 578 // We were unable to get the lock, so put this in a list to finish up | 521 // We were unable to get the lock, so put this in a list to finish up |
| 579 // later. | 522 // later. |
| 580 ASSERT(context()->isAudioThread()); | 523 ASSERT(context()->isAudioThread()); |
| 581 context()->addDeferredBreakConnection(*this); | 524 context()->addDeferredBreakConnection(*this); |
| 582 } | 525 } |
| 583 } | 526 } |
| 584 | 527 |
| 585 void AudioNode::breakConnectionWithLock() | 528 void AudioNode::breakConnectionWithLock() |
| 586 { | 529 { |
| 587 atomicDecrement(&m_connectionRefCount); | 530 atomicDecrement(&m_connectionRefCount); |
| 588 #if !ENABLE(OILPAN) | |
| 589 ASSERT(m_normalRefCount > 0); | |
| 590 #endif | |
| 591 if (!m_connectionRefCount) | 531 if (!m_connectionRefCount) |
| 592 disableOutputsIfNecessary(); | 532 disableOutputsIfNecessary(); |
| 593 } | 533 } |
| 594 | 534 |
| 595 #if !ENABLE(OILPAN) | |
| 596 void AudioNode::finishDeref() | |
| 597 { | |
| 598 ASSERT(context()->isGraphOwner()); | |
| 599 | |
| 600 ASSERT(m_normalRefCount > 0); | |
| 601 atomicDecrement(&m_normalRefCount); | |
| 602 | |
| 603 #if DEBUG_AUDIONODE_REFERENCES | |
| 604 fprintf(stderr, "%p: %d: AudioNode::deref() %d %d\n", this, nodeType(), m_no
rmalRefCount, m_connectionRefCount); | |
| 605 #endif | |
| 606 | |
| 607 if (!m_normalRefCount) { | |
| 608 // Mark for deletion at end of each render quantum or when context shuts | |
| 609 // down. | |
| 610 context()->markForDeletion(this); | |
| 611 } | |
| 612 } | |
| 613 #endif | |
| 614 | |
| 615 #if DEBUG_AUDIONODE_REFERENCES | 535 #if DEBUG_AUDIONODE_REFERENCES |
| 616 | 536 |
| 617 bool AudioNode::s_isNodeCountInitialized = false; | 537 bool AudioNode::s_isNodeCountInitialized = false; |
| 618 int AudioNode::s_nodeCount[NodeTypeEnd]; | 538 int AudioNode::s_nodeCount[NodeTypeEnd]; |
| 619 | 539 |
| 620 void AudioNode::printNodeCounts() | 540 void AudioNode::printNodeCounts() |
| 621 { | 541 { |
| 622 fprintf(stderr, "\n\n"); | 542 fprintf(stderr, "\n\n"); |
| 623 fprintf(stderr, "===========================\n"); | 543 fprintf(stderr, "===========================\n"); |
| 624 fprintf(stderr, "AudioNode: reference counts\n"); | 544 fprintf(stderr, "AudioNode: reference counts\n"); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 636 { | 556 { |
| 637 visitor->trace(m_context); | 557 visitor->trace(m_context); |
| 638 visitor->trace(m_inputs); | 558 visitor->trace(m_inputs); |
| 639 visitor->trace(m_outputs); | 559 visitor->trace(m_outputs); |
| 640 EventTargetWithInlineData::trace(visitor); | 560 EventTargetWithInlineData::trace(visitor); |
| 641 } | 561 } |
| 642 | 562 |
| 643 } // namespace blink | 563 } // namespace blink |
| 644 | 564 |
| 645 #endif // ENABLE(WEB_AUDIO) | 565 #endif // ENABLE(WEB_AUDIO) |
| OLD | NEW |