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 |