Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(210)

Side by Side Diff: content/renderer/audio_input_device.cc

Issue 7003053: Moves audio files from content\renderer\ to content\renderer\media. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/renderer/audio_input_device.h"
6
7 #include "base/memory/singleton.h"
8 #include "base/message_loop.h"
9 #include "content/common/audio_messages.h"
10 #include "content/common/child_process.h"
11 #include "content/common/view_messages.h"
12 #include "content/renderer/render_thread.h"
13 #include "media/audio/audio_util.h"
14
15 scoped_refptr<AudioInputMessageFilter> AudioInputDevice::filter_;
16
17 namespace {
18
19 // AudioMessageFilterCreator is intended to be used as a singleton so we can
20 // get access to a shared AudioInputMessageFilter.
21 // Example usage:
22 // AudioInputMessageFilter* filter =
23 // AudioInputMessageFilterCreator::SharedFilter();
24
25 class AudioInputMessageFilterCreator {
26 public:
27 AudioInputMessageFilterCreator() {
28 int routing_id;
29 RenderThread::current()->Send(
30 new ViewHostMsg_GenerateRoutingID(&routing_id));
31 filter_ = new AudioInputMessageFilter(routing_id);
32 RenderThread::current()->AddFilter(filter_);
33 }
34
35 static AudioInputMessageFilter* SharedFilter() {
36 return GetInstance()->filter_.get();
37 }
38
39 static AudioInputMessageFilterCreator* GetInstance() {
40 return Singleton<AudioInputMessageFilterCreator>::get();
41 }
42
43 private:
44 scoped_refptr<AudioInputMessageFilter> filter_;
45 };
46
47 } // namespace
48
49 AudioInputDevice::AudioInputDevice(size_t buffer_size,
50 int channels,
51 double sample_rate,
52 CaptureCallback* callback)
53 : buffer_size_(buffer_size),
54 channels_(channels),
55 bits_per_sample_(16),
56 sample_rate_(sample_rate),
57 callback_(callback),
58 audio_delay_milliseconds_(0),
59 volume_(1.0),
60 stream_id_(0) {
61 audio_data_.reserve(channels);
62 for (int i = 0; i < channels; ++i) {
63 float* channel_data = new float[buffer_size];
64 audio_data_.push_back(channel_data);
65 }
66 // Lazily create the message filter and share across AudioInputDevice
67 // instances.
68 filter_ = AudioInputMessageFilterCreator::SharedFilter();
69 }
70
71 AudioInputDevice::~AudioInputDevice() {
72 // Make sure we have been shut down.
73 DCHECK_EQ(0, stream_id_);
74 Stop();
75 for (int i = 0; i < channels_; ++i)
76 delete [] audio_data_[i];
77 }
78
79 bool AudioInputDevice::Start() {
80 // Make sure we don't call Start() more than once.
81 DCHECK_EQ(0, stream_id_);
82 if (stream_id_)
83 return false;
84
85 AudioParameters params;
86 // TODO(henrika): add support for low-latency mode?
87 params.format = AudioParameters::AUDIO_PCM_LINEAR;
88 params.channels = channels_;
89 params.sample_rate = static_cast<int>(sample_rate_);
90 params.bits_per_sample = bits_per_sample_;
91 params.samples_per_packet = buffer_size_;
92
93 // Ensure that the initialization task is posted on the I/O thread by
94 // accessing the I/O message loop directly. This approach avoids a race
95 // condition which could exist if the message loop of the filter was
96 // used instead.
97 DCHECK(ChildProcess::current()) << "Must be in the renderer";
98 MessageLoop* message_loop = ChildProcess::current()->io_message_loop();
99 if (!message_loop)
100 return false;
101
102 message_loop->PostTask(FROM_HERE,
103 NewRunnableMethod(this, &AudioInputDevice::InitializeOnIOThread, params));
104
105 return true;
106 }
107
108 bool AudioInputDevice::Stop() {
109 if (!stream_id_)
110 return false;
111
112 filter_->message_loop()->PostTask(FROM_HERE,
113 NewRunnableMethod(this, &AudioInputDevice::ShutDownOnIOThread));
114
115 if (audio_thread_.get()) {
116 socket_->Close();
117 audio_thread_->Join();
118 }
119
120 return true;
121 }
122
123 bool AudioInputDevice::SetVolume(double volume) {
124 NOTIMPLEMENTED();
125 return false;
126 }
127
128 bool AudioInputDevice::GetVolume(double* volume) {
129 NOTIMPLEMENTED();
130 return false;
131 }
132
133 void AudioInputDevice::InitializeOnIOThread(const AudioParameters& params) {
134 stream_id_ = filter_->AddDelegate(this);
135 filter_->Send(
136 new AudioInputHostMsg_CreateStream(0, stream_id_, params, true));
137 }
138
139 void AudioInputDevice::StartOnIOThread() {
140 if (stream_id_)
141 filter_->Send(new AudioInputHostMsg_RecordStream(0, stream_id_));
142 }
143
144 void AudioInputDevice::ShutDownOnIOThread() {
145 // Make sure we don't call shutdown more than once.
146 if (!stream_id_)
147 return;
148
149 filter_->Send(new AudioInputHostMsg_CloseStream(0, stream_id_));
150 filter_->RemoveDelegate(stream_id_);
151 stream_id_ = 0;
152 }
153
154 void AudioInputDevice::SetVolumeOnIOThread(double volume) {
155 if (stream_id_)
156 filter_->Send(new AudioInputHostMsg_SetVolume(0, stream_id_, volume));
157 }
158
159 void AudioInputDevice::OnLowLatencyCreated(
160 base::SharedMemoryHandle handle,
161 base::SyncSocket::Handle socket_handle,
162 uint32 length) {
163 #if defined(OS_WIN)
164 DCHECK(handle);
165 DCHECK(socket_handle);
166 #else
167 DCHECK_GE(handle.fd, 0);
168 DCHECK_GE(socket_handle, 0);
169 #endif
170 DCHECK(length);
171
172 // TODO(henrika) : check that length is big enough for buffer_size_
173
174 shared_memory_.reset(new base::SharedMemory(handle, false));
175 shared_memory_->Map(length);
176
177 socket_.reset(new base::SyncSocket(socket_handle));
178
179 // TODO(henrika): we could optionally set the thread to high-priority
180 audio_thread_.reset(
181 new base::DelegateSimpleThread(this, "renderer_audio_input_thread"));
182 audio_thread_->Start();
183
184 if (filter_) {
185 filter_->message_loop()->PostTask(FROM_HERE,
186 NewRunnableMethod(this, &AudioInputDevice::StartOnIOThread));
187 }
188 }
189
190 void AudioInputDevice::OnVolume(double volume) {
191 NOTIMPLEMENTED();
192 }
193
194 // Our audio thread runs here. We receive captured audio samples on
195 // this thread.
196 void AudioInputDevice::Run() {
197 int pending_data;
198 const int samples_per_ms = static_cast<int>(sample_rate_) / 1000;
199 const int bytes_per_ms = channels_ * (bits_per_sample_ / 8) * samples_per_ms;
200
201 while (sizeof(pending_data) == socket_->Receive(&pending_data,
202 sizeof(pending_data)) &&
203 pending_data >= 0) {
204 // TODO(henrika): investigate the provided |pending_data| value
205 // and ensure that it is actually an accurate delay estimation.
206
207 // Convert the number of pending bytes in the capture buffer
208 // into milliseconds.
209 audio_delay_milliseconds_ = pending_data / bytes_per_ms;
210
211 FireCaptureCallback();
212 }
213 }
214
215 void AudioInputDevice::FireCaptureCallback() {
216 if (!callback_)
217 return;
218
219 const size_t number_of_frames = buffer_size_;
220
221 // Read 16-bit samples from shared memory (browser writes to it).
222 int16* input_audio = static_cast<int16*>(shared_memory_data());
223 const int bytes_per_sample = sizeof(input_audio[0]);
224
225 // Deinterleave each channel and convert to 32-bit floating-point
226 // with nominal range -1.0 -> +1.0.
227 for (int channel_index = 0; channel_index < channels_; ++channel_index) {
228 media::DeinterleaveAudioChannel(input_audio,
229 audio_data_[channel_index],
230 channels_,
231 channel_index,
232 bytes_per_sample,
233 number_of_frames);
234 }
235
236 // Deliver captured data to the client in floating point format
237 // and update the audio-delay measurement.
238 callback_->Capture(audio_data_,
239 number_of_frames,
240 audio_delay_milliseconds_);
241 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698