| 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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 , m_nodeType(NodeTypeUnknown) | 48 , m_nodeType(NodeTypeUnknown) |
| 49 , m_context(context) | 49 , m_context(context) |
| 50 , m_sampleRate(sampleRate) | 50 , m_sampleRate(sampleRate) |
| 51 #if ENABLE(OILPAN) | 51 #if ENABLE(OILPAN) |
| 52 , m_keepAlive(adoptPtr(new Persistent<AudioNode>(this))) | 52 , m_keepAlive(adoptPtr(new Persistent<AudioNode>(this))) |
| 53 #endif | 53 #endif |
| 54 , m_lastProcessingTime(-1) | 54 , m_lastProcessingTime(-1) |
| 55 , m_lastNonSilentTime(-1) | 55 , m_lastNonSilentTime(-1) |
| 56 , m_normalRefCount(1) // start out with normal refCount == 1 (like WTF::RefC
ounted class) | 56 , m_normalRefCount(1) // start out with normal refCount == 1 (like WTF::RefC
ounted class) |
| 57 , m_connectionRefCount(0) | 57 , m_connectionRefCount(0) |
| 58 , m_wasDisconnected(false) |
| 58 , m_isMarkedForDeletion(false) | 59 , m_isMarkedForDeletion(false) |
| 59 , m_isDisabled(false) | 60 , m_isDisabled(false) |
| 60 , m_channelCount(2) | 61 , m_channelCount(2) |
| 61 , m_channelCountMode(Max) | 62 , m_channelCountMode(Max) |
| 62 , m_channelInterpretation(AudioBus::Speakers) | 63 , m_channelInterpretation(AudioBus::Speakers) |
| 63 { | 64 { |
| 64 ScriptWrappable::init(this); | 65 ScriptWrappable::init(this); |
| 65 #if DEBUG_AUDIONODE_REFERENCES | 66 #if DEBUG_AUDIONODE_REFERENCES |
| 66 if (!s_isNodeCountInitialized) { | 67 if (!s_isNodeCountInitialized) { |
| 67 s_isNodeCountInitialized = true; | 68 s_isNodeCountInitialized = true; |
| (...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 462 // a tailTime attribute. Then the AudioNode only needs to remain "active
" for tailTime seconds after there are no | 463 // a tailTime attribute. Then the AudioNode only needs to remain "active
" for tailTime seconds after there are no |
| 463 // longer any active connections. | 464 // longer any active connections. |
| 464 if (nodeType() != NodeTypeConvolver && nodeType() != NodeTypeDelay) { | 465 if (nodeType() != NodeTypeConvolver && nodeType() != NodeTypeDelay) { |
| 465 m_isDisabled = true; | 466 m_isDisabled = true; |
| 466 for (unsigned i = 0; i < m_outputs.size(); ++i) | 467 for (unsigned i = 0; i < m_outputs.size(); ++i) |
| 467 output(i)->disable(); | 468 output(i)->disable(); |
| 468 } | 469 } |
| 469 } | 470 } |
| 470 } | 471 } |
| 471 | 472 |
| 472 void AudioNode::ref(RefType refType) | 473 void AudioNode::ref() |
| 473 { | 474 { |
| 474 #if ENABLE(OILPAN) | 475 #if ENABLE(OILPAN) |
| 475 ASSERT(m_keepAlive); | 476 ASSERT(m_keepAlive); |
| 476 #endif | 477 #endif |
| 477 switch (refType) { | 478 atomicIncrement(&m_normalRefCount); |
| 478 case RefTypeNormal: | |
| 479 atomicIncrement(&m_normalRefCount); | |
| 480 break; | |
| 481 case RefTypeConnection: | |
| 482 atomicIncrement(&m_connectionRefCount); | |
| 483 break; | |
| 484 default: | |
| 485 ASSERT_NOT_REACHED(); | |
| 486 } | |
| 487 | 479 |
| 488 #if DEBUG_AUDIONODE_REFERENCES | 480 #if DEBUG_AUDIONODE_REFERENCES |
| 489 fprintf(stderr, "%p: %d: AudioNode::ref(%d) %d %d\n", this, nodeType(), refT
ype, m_normalRefCount, m_connectionRefCount); | 481 fprintf(stderr, "%p: %d: AudioNode::ref() %d %d\n", this, nodeType(), m_norm
alRefCount, m_connectionRefCount); |
| 490 #endif | 482 #endif |
| 491 | |
| 492 // See the disabling code in finishDeref() below. This handles the case wher
e a node | |
| 493 // is being re-connected after being used at least once and disconnected. | |
| 494 // In this case, we need to re-enable. | |
| 495 if (refType == RefTypeConnection) | |
| 496 enableOutputsIfNecessary(); | |
| 497 } | 483 } |
| 498 | 484 |
| 499 void AudioNode::deref(RefType refType) | 485 void AudioNode::makeConnection() |
| 486 { |
| 487 atomicIncrement(&m_connectionRefCount); |
| 488 // See the disabling code in finishDeref() below. This handles the case |
| 489 // where a node is being re-connected after being used at least once and |
| 490 // disconnected. In this case, we need to re-enable. |
| 491 enableOutputsIfNecessary(); |
| 492 } |
| 493 |
| 494 void AudioNode::deref() |
| 500 { | 495 { |
| 501 // The actually work for deref happens completely within the audio context's
graph lock. | 496 // The actually work for deref happens completely within the audio context's
graph lock. |
| 502 // In the case of the audio thread, we must use a tryLock to avoid glitches. | 497 // In the case of the audio thread, we must use a tryLock to avoid glitches. |
| 503 bool hasLock = false; | 498 bool hasLock = false; |
| 504 bool mustReleaseLock = false; | 499 bool mustReleaseLock = false; |
| 505 | 500 |
| 506 if (context()->isAudioThread()) { | 501 if (context()->isAudioThread()) { |
| 507 // Real-time audio thread must not contend lock (to avoid glitches). | 502 // Real-time audio thread must not contend lock (to avoid glitches). |
| 508 hasLock = context()->tryLock(mustReleaseLock); | 503 hasLock = context()->tryLock(mustReleaseLock); |
| 509 } else { | 504 } else { |
| 510 context()->lock(mustReleaseLock); | 505 context()->lock(mustReleaseLock); |
| 511 hasLock = true; | 506 hasLock = true; |
| 512 } | 507 } |
| 513 | 508 |
| 514 if (hasLock) { | 509 if (hasLock) { |
| 515 // This is where the real deref work happens. | 510 // This is where the real deref work happens. |
| 516 finishDeref(refType); | 511 finishDeref(); |
| 517 | 512 |
| 518 if (mustReleaseLock) | 513 if (mustReleaseLock) |
| 519 context()->unlock(); | 514 context()->unlock(); |
| 520 } else { | 515 } else { |
| 521 // We were unable to get the lock, so put this in a list to finish up la
ter. | 516 // We were unable to get the lock, so put this in a list to finish up la
ter. |
| 522 ASSERT(context()->isAudioThread()); | 517 ASSERT(context()->isAudioThread()); |
| 523 ASSERT(refType == RefTypeConnection); | |
| 524 context()->addDeferredFinishDeref(this); | 518 context()->addDeferredFinishDeref(this); |
| 525 } | 519 } |
| 526 | 520 |
| 527 // Once AudioContext::uninitialize() is called there's no more chances for d
eleteMarkedNodes() to get called, so we call here. | 521 // Once AudioContext::uninitialize() is called there's no more chances for d
eleteMarkedNodes() to get called, so we call here. |
| 528 // We can't call in AudioContext::~AudioContext() since it will never be cal
led as long as any AudioNode is alive | 522 // We can't call in AudioContext::~AudioContext() since it will never be cal
led as long as any AudioNode is alive |
| 529 // because AudioNodes keep a reference to the context. | 523 // because AudioNodes keep a reference to the context. |
| 530 if (!context()->isInitialized()) | 524 if (!context()->isInitialized()) |
| 531 context()->deleteMarkedNodes(); | 525 context()->deleteMarkedNodes(); |
| 532 } | 526 } |
| 533 | 527 |
| 534 void AudioNode::finishDeref(RefType refType) | 528 void AudioNode::breakConnection() |
| 529 { |
| 530 ASSERT(m_normalRefCount > 0); |
| 531 atomicDecrement(&m_connectionRefCount); |
| 532 m_wasDisconnected = true; |
| 533 } |
| 534 |
| 535 void AudioNode::finishDeref() |
| 535 { | 536 { |
| 536 ASSERT(context()->isGraphOwner()); | 537 ASSERT(context()->isGraphOwner()); |
| 537 | 538 |
| 538 switch (refType) { | 539 ASSERT(m_normalRefCount > 0); |
| 539 case RefTypeNormal: | 540 atomicDecrement(&m_normalRefCount); |
| 540 ASSERT(m_normalRefCount > 0); | 541 |
| 541 atomicDecrement(&m_normalRefCount); | 542 #if DEBUG_AUDIONODE_REFERENCES |
| 542 break; | 543 fprintf(stderr, "%p: %d: AudioNode::deref() %d %d\n", this, nodeType(), m_no
rmalRefCount, m_connectionRefCount); |
| 543 case RefTypeConnection: | 544 #endif |
| 544 ASSERT(m_connectionRefCount > 0); | 545 |
| 545 atomicDecrement(&m_connectionRefCount); | 546 if (m_wasDisconnected) { |
| 546 break; | 547 if (m_connectionRefCount == 0 && m_normalRefCount > 0) |
| 547 default: | 548 disableOutputsIfNecessary(); |
| 548 ASSERT_NOT_REACHED(); | 549 m_wasDisconnected = false; |
| 549 } | 550 } |
| 550 | 551 |
| 551 #if DEBUG_AUDIONODE_REFERENCES | 552 if (!m_normalRefCount && !m_isMarkedForDeletion) { |
| 552 fprintf(stderr, "%p: %d: AudioNode::deref(%d) %d %d\n", this, nodeType(), re
fType, m_normalRefCount, m_connectionRefCount); | 553 // All references are gone - we need to go away. |
| 553 #endif | 554 for (unsigned i = 0; i < m_outputs.size(); ++i) |
| 555 output(i)->disconnectAll(); // This will deref() nodes we're connect
ed to. |
| 554 | 556 |
| 555 if (!m_connectionRefCount) { | 557 // Mark for deletion at end of each render quantum or when context shuts |
| 556 if (!m_normalRefCount) { | 558 // down. |
| 557 if (!m_isMarkedForDeletion) { | 559 context()->markForDeletion(this); |
| 558 // All references are gone - we need to go away. | 560 m_isMarkedForDeletion = true; |
| 559 for (unsigned i = 0; i < m_outputs.size(); ++i) | |
| 560 output(i)->disconnectAll(); // This will deref() nodes we're
connected to. | |
| 561 | |
| 562 // Mark for deletion at end of each render quantum or when conte
xt shuts down. | |
| 563 context()->markForDeletion(this); | |
| 564 m_isMarkedForDeletion = true; | |
| 565 } | |
| 566 } else if (refType == RefTypeConnection) | |
| 567 disableOutputsIfNecessary(); | |
| 568 } | 561 } |
| 569 } | 562 } |
| 570 | 563 |
| 571 #if DEBUG_AUDIONODE_REFERENCES | 564 #if DEBUG_AUDIONODE_REFERENCES |
| 572 | 565 |
| 573 bool AudioNode::s_isNodeCountInitialized = false; | 566 bool AudioNode::s_isNodeCountInitialized = false; |
| 574 int AudioNode::s_nodeCount[NodeTypeEnd]; | 567 int AudioNode::s_nodeCount[NodeTypeEnd]; |
| 575 | 568 |
| 576 void AudioNode::printNodeCounts() | 569 void AudioNode::printNodeCounts() |
| 577 { | 570 { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 603 // it cannot be reattached. Therefore, the reference count | 596 // it cannot be reattached. Therefore, the reference count |
| 604 // will not go above zero again. | 597 // will not go above zero again. |
| 605 ASSERT(m_keepAlive); | 598 ASSERT(m_keepAlive); |
| 606 m_keepAlive = nullptr; | 599 m_keepAlive = nullptr; |
| 607 } | 600 } |
| 608 #endif | 601 #endif |
| 609 | 602 |
| 610 } // namespace WebCore | 603 } // namespace WebCore |
| 611 | 604 |
| 612 #endif // ENABLE(WEB_AUDIO) | 605 #endif // ENABLE(WEB_AUDIO) |
| OLD | NEW |