AudioNodeOutput.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*
  2. * Copyright (C) 2010, Google Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  15. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  16. * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  17. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  18. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  19. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  20. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  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.
  23. */
  24. #include "config.h"
  25. #if ENABLE(WEB_AUDIO)
  26. #include "AudioNodeOutput.h"
  27. #include "AudioBus.h"
  28. #include "AudioContext.h"
  29. #include "AudioNodeInput.h"
  30. #include "AudioParam.h"
  31. #include <wtf/Threading.h>
  32. namespace WebCore {
  33. AudioNodeOutput::AudioNodeOutput(AudioNode* node, unsigned numberOfChannels)
  34. : m_node(node)
  35. , m_numberOfChannels(numberOfChannels)
  36. , m_desiredNumberOfChannels(numberOfChannels)
  37. , m_isInPlace(false)
  38. , m_isEnabled(true)
  39. , m_renderingFanOutCount(0)
  40. , m_renderingParamFanOutCount(0)
  41. {
  42. ASSERT(numberOfChannels <= AudioContext::maxNumberOfChannels());
  43. m_internalBus = AudioBus::create(numberOfChannels, AudioNode::ProcessingSizeInFrames);
  44. }
  45. void AudioNodeOutput::setNumberOfChannels(unsigned numberOfChannels)
  46. {
  47. ASSERT(numberOfChannels <= AudioContext::maxNumberOfChannels());
  48. ASSERT(context()->isGraphOwner());
  49. m_desiredNumberOfChannels = numberOfChannels;
  50. if (context()->isAudioThread()) {
  51. // If we're in the audio thread then we can take care of it right away (we should be at the very start or end of a rendering quantum).
  52. updateNumberOfChannels();
  53. } else {
  54. // Let the context take care of it in the audio thread in the pre and post render tasks.
  55. context()->markAudioNodeOutputDirty(this);
  56. }
  57. }
  58. void AudioNodeOutput::updateInternalBus()
  59. {
  60. if (numberOfChannels() == m_internalBus->numberOfChannels())
  61. return;
  62. m_internalBus = AudioBus::create(numberOfChannels(), AudioNode::ProcessingSizeInFrames);
  63. }
  64. void AudioNodeOutput::updateRenderingState()
  65. {
  66. updateNumberOfChannels();
  67. m_renderingFanOutCount = fanOutCount();
  68. m_renderingParamFanOutCount = paramFanOutCount();
  69. }
  70. void AudioNodeOutput::updateNumberOfChannels()
  71. {
  72. ASSERT(context()->isAudioThread() && context()->isGraphOwner());
  73. if (m_numberOfChannels != m_desiredNumberOfChannels) {
  74. m_numberOfChannels = m_desiredNumberOfChannels;
  75. updateInternalBus();
  76. propagateChannelCount();
  77. }
  78. }
  79. void AudioNodeOutput::propagateChannelCount()
  80. {
  81. ASSERT(context()->isAudioThread() && context()->isGraphOwner());
  82. if (isChannelCountKnown()) {
  83. // Announce to any nodes we're connected to that we changed our channel count for its input.
  84. for (InputsIterator i = m_inputs.begin(); i != m_inputs.end(); ++i) {
  85. AudioNodeInput* input = *i;
  86. AudioNode* connectionNode = input->node();
  87. connectionNode->checkNumberOfChannelsForInput(input);
  88. }
  89. }
  90. }
  91. AudioBus* AudioNodeOutput::pull(AudioBus* inPlaceBus, size_t framesToProcess)
  92. {
  93. ASSERT(context()->isAudioThread());
  94. ASSERT(m_renderingFanOutCount > 0 || m_renderingParamFanOutCount > 0);
  95. // Causes our AudioNode to process if it hasn't already for this render quantum.
  96. // We try to do in-place processing (using inPlaceBus) if at all possible,
  97. // but we can't process in-place if we're connected to more than one input (fan-out > 1).
  98. // In this case pull() is called multiple times per rendering quantum, and the processIfNecessary() call below will
  99. // cause our node to process() only the first time, caching the output in m_internalOutputBus for subsequent calls.
  100. m_isInPlace = inPlaceBus && inPlaceBus->numberOfChannels() == numberOfChannels() && (m_renderingFanOutCount + m_renderingParamFanOutCount) == 1;
  101. m_inPlaceBus = m_isInPlace ? inPlaceBus : 0;
  102. node()->processIfNecessary(framesToProcess);
  103. return bus();
  104. }
  105. AudioBus* AudioNodeOutput::bus() const
  106. {
  107. ASSERT(const_cast<AudioNodeOutput*>(this)->context()->isAudioThread());
  108. return m_isInPlace ? m_inPlaceBus.get() : m_internalBus.get();
  109. }
  110. unsigned AudioNodeOutput::fanOutCount()
  111. {
  112. ASSERT(context()->isGraphOwner());
  113. return m_inputs.size();
  114. }
  115. unsigned AudioNodeOutput::paramFanOutCount()
  116. {
  117. ASSERT(context()->isGraphOwner());
  118. return m_params.size();
  119. }
  120. unsigned AudioNodeOutput::renderingFanOutCount() const
  121. {
  122. return m_renderingFanOutCount;
  123. }
  124. unsigned AudioNodeOutput::renderingParamFanOutCount() const
  125. {
  126. return m_renderingParamFanOutCount;
  127. }
  128. void AudioNodeOutput::addInput(AudioNodeInput* input)
  129. {
  130. ASSERT(context()->isGraphOwner());
  131. ASSERT(input);
  132. if (!input)
  133. return;
  134. m_inputs.add(input);
  135. }
  136. void AudioNodeOutput::removeInput(AudioNodeInput* input)
  137. {
  138. ASSERT(context()->isGraphOwner());
  139. ASSERT(input);
  140. if (!input)
  141. return;
  142. m_inputs.remove(input);
  143. }
  144. void AudioNodeOutput::disconnectAllInputs()
  145. {
  146. ASSERT(context()->isGraphOwner());
  147. // AudioNodeInput::disconnect() changes m_inputs by calling removeInput().
  148. while (!m_inputs.isEmpty()) {
  149. AudioNodeInput* input = *m_inputs.begin();
  150. input->disconnect(this);
  151. }
  152. }
  153. void AudioNodeOutput::addParam(AudioParam* param)
  154. {
  155. ASSERT(context()->isGraphOwner());
  156. ASSERT(param);
  157. if (!param)
  158. return;
  159. m_params.add(param);
  160. }
  161. void AudioNodeOutput::removeParam(AudioParam* param)
  162. {
  163. ASSERT(context()->isGraphOwner());
  164. ASSERT(param);
  165. if (!param)
  166. return;
  167. m_params.remove(param);
  168. }
  169. void AudioNodeOutput::disconnectAllParams()
  170. {
  171. ASSERT(context()->isGraphOwner());
  172. // AudioParam::disconnect() changes m_params by calling removeParam().
  173. while (!m_params.isEmpty()) {
  174. AudioParam* param = m_params.begin()->get();
  175. param->disconnect(this);
  176. }
  177. }
  178. void AudioNodeOutput::disconnectAll()
  179. {
  180. disconnectAllInputs();
  181. disconnectAllParams();
  182. }
  183. void AudioNodeOutput::disable()
  184. {
  185. ASSERT(context()->isGraphOwner());
  186. if (m_isEnabled) {
  187. for (InputsIterator i = m_inputs.begin(); i != m_inputs.end(); ++i) {
  188. AudioNodeInput* input = *i;
  189. input->disable(this);
  190. }
  191. m_isEnabled = false;
  192. }
  193. }
  194. void AudioNodeOutput::enable()
  195. {
  196. ASSERT(context()->isGraphOwner());
  197. if (!m_isEnabled) {
  198. for (InputsIterator i = m_inputs.begin(); i != m_inputs.end(); ++i) {
  199. AudioNodeInput* input = *i;
  200. input->enable(this);
  201. }
  202. m_isEnabled = true;
  203. }
  204. }
  205. } // namespace WebCore
  206. #endif // ENABLE(WEB_AUDIO)