1/*
2 * Copyright (C) 2011, 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
25#include "config.h"
26
27#if ENABLE(WEB_AUDIO)
28
29#include "DefaultAudioDestinationNode.h"
30
31#include "AudioContext.h"
32#include "AudioDestination.h"
33#include "Logging.h"
34#include "ScriptExecutionContext.h"
35#include <wtf/IsoMallocInlines.h>
36#include <wtf/MainThread.h>
37
38const unsigned EnabledInputChannels = 2;
39
40namespace WebCore {
41
42WTF_MAKE_ISO_ALLOCATED_IMPL(DefaultAudioDestinationNode);
43
44DefaultAudioDestinationNode::DefaultAudioDestinationNode(AudioContext& context)
45 : AudioDestinationNode(context, AudioDestination::hardwareSampleRate())
46{
47 // Node-specific default mixing rules.
48 m_channelCount = 2;
49 m_channelCountMode = Explicit;
50 m_channelInterpretation = AudioBus::Speakers;
51}
52
53DefaultAudioDestinationNode::~DefaultAudioDestinationNode()
54{
55 uninitialize();
56}
57
58void DefaultAudioDestinationNode::initialize()
59{
60 ASSERT(isMainThread());
61 if (isInitialized())
62 return;
63 ALWAYS_LOG(LOGIDENTIFIER);
64
65 createDestination();
66 AudioNode::initialize();
67}
68
69void DefaultAudioDestinationNode::uninitialize()
70{
71 ASSERT(isMainThread());
72 if (!isInitialized())
73 return;
74
75 ALWAYS_LOG(LOGIDENTIFIER);
76 m_destination->stop();
77 m_destination = nullptr;
78 m_numberOfInputChannels = 0;
79
80 AudioNode::uninitialize();
81}
82
83void DefaultAudioDestinationNode::createDestination()
84{
85 float hardwareSampleRate = AudioDestination::hardwareSampleRate();
86 LOG(WebAudio, ">>>> hardwareSampleRate = %f\n", hardwareSampleRate);
87
88 m_destination = AudioDestination::create(*this, m_inputDeviceId, m_numberOfInputChannels, channelCount(), hardwareSampleRate);
89}
90
91void DefaultAudioDestinationNode::enableInput(const String& inputDeviceId)
92{
93 ALWAYS_LOG(LOGIDENTIFIER);
94
95 ASSERT(isMainThread());
96 if (m_numberOfInputChannels != EnabledInputChannels) {
97 m_numberOfInputChannels = EnabledInputChannels;
98 m_inputDeviceId = inputDeviceId;
99
100 if (isInitialized()) {
101 // Re-create destination.
102 m_destination->stop();
103 createDestination();
104 m_destination->start();
105 }
106 }
107}
108
109void DefaultAudioDestinationNode::startRendering()
110{
111 ASSERT(isInitialized());
112 if (isInitialized())
113 m_destination->start();
114}
115
116void DefaultAudioDestinationNode::resume(Function<void ()>&& function)
117{
118 ASSERT(isInitialized());
119 if (isInitialized())
120 m_destination->start();
121 context().postTask(WTFMove(function));
122}
123
124void DefaultAudioDestinationNode::suspend(Function<void ()>&& function)
125{
126 ASSERT(isInitialized());
127 if (isInitialized())
128 m_destination->stop();
129 context().postTask(WTFMove(function));
130}
131
132void DefaultAudioDestinationNode::close(Function<void()>&& function)
133{
134 ASSERT(isInitialized());
135 uninitialize();
136 context().postTask(WTFMove(function));
137}
138
139unsigned DefaultAudioDestinationNode::maxChannelCount() const
140{
141 return AudioDestination::maxChannelCount();
142}
143
144ExceptionOr<void> DefaultAudioDestinationNode::setChannelCount(unsigned channelCount)
145{
146 // The channelCount for the input to this node controls the actual number of channels we
147 // send to the audio hardware. It can only be set depending on the maximum number of
148 // channels supported by the hardware.
149
150 ASSERT(isMainThread());
151 ALWAYS_LOG(LOGIDENTIFIER, channelCount);
152
153 if (!maxChannelCount() || channelCount > maxChannelCount())
154 return Exception { InvalidStateError };
155
156 auto oldChannelCount = this->channelCount();
157 auto result = AudioNode::setChannelCount(channelCount);
158 if (result.hasException())
159 return result;
160
161 if (this->channelCount() != oldChannelCount && isInitialized()) {
162 // Re-create destination.
163 m_destination->stop();
164 createDestination();
165 m_destination->start();
166 }
167
168 return { };
169}
170
171bool DefaultAudioDestinationNode::isPlaying()
172{
173 return m_destination && m_destination->isPlaying();
174}
175
176} // namespace WebCore
177
178#endif // ENABLE(WEB_AUDIO)
179