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

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

Issue 7157001: Implements AudioMessageFilter as member in RenderThread (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Fixed nits in AudioRenderImpl unit test Created 9 years, 5 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
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/media/audio_input_device.h" 5 #include "content/renderer/media/audio_input_device.h"
6 6
7 #include "base/memory/singleton.h"
8 #include "base/message_loop.h" 7 #include "base/message_loop.h"
9 #include "content/common/child_process.h" 8 #include "content/common/child_process.h"
10 #include "content/common/media/audio_messages.h" 9 #include "content/common/media/audio_messages.h"
11 #include "content/common/view_messages.h" 10 #include "content/common/view_messages.h"
12 #include "content/renderer/render_thread.h" 11 #include "content/renderer/render_thread.h"
13 #include "media/audio/audio_util.h" 12 #include "media/audio/audio_util.h"
14 13
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, 14 AudioInputDevice::AudioInputDevice(size_t buffer_size,
50 int channels, 15 int channels,
51 double sample_rate, 16 double sample_rate,
52 CaptureCallback* callback) 17 CaptureCallback* callback)
53 : buffer_size_(buffer_size), 18 : buffer_size_(buffer_size),
54 channels_(channels), 19 channels_(channels),
55 bits_per_sample_(16), 20 bits_per_sample_(16),
56 sample_rate_(sample_rate), 21 sample_rate_(sample_rate),
57 callback_(callback), 22 callback_(callback),
58 audio_delay_milliseconds_(0), 23 audio_delay_milliseconds_(0),
59 volume_(1.0), 24 volume_(1.0),
60 stream_id_(0) { 25 stream_id_(0) {
26 filter_ = RenderThread::current()->audio_input_message_filter();
61 audio_data_.reserve(channels); 27 audio_data_.reserve(channels);
62 for (int i = 0; i < channels; ++i) { 28 for (int i = 0; i < channels; ++i) {
63 float* channel_data = new float[buffer_size]; 29 float* channel_data = new float[buffer_size];
64 audio_data_.push_back(channel_data); 30 audio_data_.push_back(channel_data);
65 } 31 }
66 // Lazily create the message filter and share across AudioInputDevice
67 // instances.
68 filter_ = AudioInputMessageFilterCreator::SharedFilter();
69 } 32 }
70 33
71 AudioInputDevice::~AudioInputDevice() { 34 AudioInputDevice::~AudioInputDevice() {
72 // Make sure we have been shut down. 35 // Make sure we have been shut down.
73 DCHECK_EQ(0, stream_id_); 36 DCHECK_EQ(0, stream_id_);
74 Stop(); 37 Stop();
75 for (int i = 0; i < channels_; ++i) 38 for (int i = 0; i < channels_; ++i)
76 delete [] audio_data_[i]; 39 delete [] audio_data_[i];
77 } 40 }
78 41
79 bool AudioInputDevice::Start() { 42 bool AudioInputDevice::Start() {
80 // Make sure we don't call Start() more than once. 43 // Make sure we don't call Start() more than once.
81 DCHECK_EQ(0, stream_id_); 44 DCHECK_EQ(0, stream_id_);
82 if (stream_id_) 45 if (stream_id_)
83 return false; 46 return false;
84 47
85 AudioParameters params; 48 AudioParameters params;
86 // TODO(henrika): add support for low-latency mode? 49 // TODO(henrika): add support for low-latency mode?
87 params.format = AudioParameters::AUDIO_PCM_LINEAR; 50 params.format = AudioParameters::AUDIO_PCM_LINEAR;
88 params.channels = channels_; 51 params.channels = channels_;
89 params.sample_rate = static_cast<int>(sample_rate_); 52 params.sample_rate = static_cast<int>(sample_rate_);
90 params.bits_per_sample = bits_per_sample_; 53 params.bits_per_sample = bits_per_sample_;
91 params.samples_per_packet = buffer_size_; 54 params.samples_per_packet = buffer_size_;
92 55
93 // Ensure that the initialization task is posted on the I/O thread by 56 ChildProcess::current()->io_message_loop()->PostTask(
94 // accessing the I/O message loop directly. This approach avoids a race 57 FROM_HERE,
95 // condition which could exist if the message loop of the filter was 58 NewRunnableMethod(this, &AudioInputDevice::InitializeOnIOThread, params));
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 59
105 return true; 60 return true;
106 } 61 }
107 62
108 bool AudioInputDevice::Stop() { 63 bool AudioInputDevice::Stop() {
109 if (!stream_id_) 64 if (!stream_id_)
110 return false; 65 return false;
111 66
112 filter_->message_loop()->PostTask(FROM_HERE, 67 ChildProcess::current()->io_message_loop()->PostTask(
68 FROM_HERE,
113 NewRunnableMethod(this, &AudioInputDevice::ShutDownOnIOThread)); 69 NewRunnableMethod(this, &AudioInputDevice::ShutDownOnIOThread));
114 70
115 if (audio_thread_.get()) { 71 if (audio_thread_.get()) {
116 socket_->Close(); 72 socket_->Close();
117 audio_thread_->Join(); 73 audio_thread_->Join();
118 } 74 }
119 75
120 return true; 76 return true;
121 } 77 }
122 78
123 bool AudioInputDevice::SetVolume(double volume) { 79 bool AudioInputDevice::SetVolume(double volume) {
124 NOTIMPLEMENTED(); 80 NOTIMPLEMENTED();
125 return false; 81 return false;
126 } 82 }
127 83
128 bool AudioInputDevice::GetVolume(double* volume) { 84 bool AudioInputDevice::GetVolume(double* volume) {
129 NOTIMPLEMENTED(); 85 NOTIMPLEMENTED();
130 return false; 86 return false;
131 } 87 }
132 88
133 void AudioInputDevice::InitializeOnIOThread(const AudioParameters& params) { 89 void AudioInputDevice::InitializeOnIOThread(const AudioParameters& params) {
134 stream_id_ = filter_->AddDelegate(this); 90 stream_id_ = filter_->AddDelegate(this);
135 filter_->Send( 91 Send(new AudioInputHostMsg_CreateStream(stream_id_, params, true));
136 new AudioInputHostMsg_CreateStream(0, stream_id_, params, true));
137 } 92 }
138 93
139 void AudioInputDevice::StartOnIOThread() { 94 void AudioInputDevice::StartOnIOThread() {
140 if (stream_id_) 95 if (stream_id_)
141 filter_->Send(new AudioInputHostMsg_RecordStream(0, stream_id_)); 96 Send(new AudioInputHostMsg_RecordStream(stream_id_));
142 } 97 }
143 98
144 void AudioInputDevice::ShutDownOnIOThread() { 99 void AudioInputDevice::ShutDownOnIOThread() {
145 // Make sure we don't call shutdown more than once. 100 // Make sure we don't call shutdown more than once.
146 if (!stream_id_) 101 if (!stream_id_)
147 return; 102 return;
148 103
149 filter_->Send(new AudioInputHostMsg_CloseStream(0, stream_id_));
150 filter_->RemoveDelegate(stream_id_); 104 filter_->RemoveDelegate(stream_id_);
105 Send(new AudioInputHostMsg_CloseStream(stream_id_));
151 stream_id_ = 0; 106 stream_id_ = 0;
152 } 107 }
153 108
154 void AudioInputDevice::SetVolumeOnIOThread(double volume) { 109 void AudioInputDevice::SetVolumeOnIOThread(double volume) {
155 if (stream_id_) 110 if (stream_id_)
156 filter_->Send(new AudioInputHostMsg_SetVolume(0, stream_id_, volume)); 111 Send(new AudioInputHostMsg_SetVolume(stream_id_, volume));
157 } 112 }
158 113
159 void AudioInputDevice::OnLowLatencyCreated( 114 void AudioInputDevice::OnLowLatencyCreated(
160 base::SharedMemoryHandle handle, 115 base::SharedMemoryHandle handle,
161 base::SyncSocket::Handle socket_handle, 116 base::SyncSocket::Handle socket_handle,
162 uint32 length) { 117 uint32 length) {
118 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
163 #if defined(OS_WIN) 119 #if defined(OS_WIN)
164 DCHECK(handle); 120 DCHECK(handle);
165 DCHECK(socket_handle); 121 DCHECK(socket_handle);
166 #else 122 #else
167 DCHECK_GE(handle.fd, 0); 123 DCHECK_GE(handle.fd, 0);
168 DCHECK_GE(socket_handle, 0); 124 DCHECK_GE(socket_handle, 0);
169 #endif 125 #endif
170 DCHECK(length); 126 DCHECK(length);
171 127
172 // TODO(henrika) : check that length is big enough for buffer_size_
173
174 shared_memory_.reset(new base::SharedMemory(handle, false)); 128 shared_memory_.reset(new base::SharedMemory(handle, false));
175 shared_memory_->Map(length); 129 shared_memory_->Map(length);
176 130
177 socket_.reset(new base::SyncSocket(socket_handle)); 131 socket_.reset(new base::SyncSocket(socket_handle));
178 132
179 // TODO(henrika): we could optionally set the thread to high-priority
180 audio_thread_.reset( 133 audio_thread_.reset(
181 new base::DelegateSimpleThread(this, "renderer_audio_input_thread")); 134 new base::DelegateSimpleThread(this, "renderer_audio_input_thread"));
182 audio_thread_->Start(); 135 audio_thread_->Start();
183 136
184 if (filter_) { 137 MessageLoop::current()->PostTask(
185 filter_->message_loop()->PostTask(FROM_HERE, 138 FROM_HERE,
186 NewRunnableMethod(this, &AudioInputDevice::StartOnIOThread)); 139 NewRunnableMethod(this, &AudioInputDevice::StartOnIOThread));
187 }
188 } 140 }
189 141
190 void AudioInputDevice::OnVolume(double volume) { 142 void AudioInputDevice::OnVolume(double volume) {
191 NOTIMPLEMENTED(); 143 NOTIMPLEMENTED();
192 } 144 }
193 145
146 void AudioInputDevice::Send(IPC::Message* message) {
147 filter_->Send(message);
148 }
149
194 // Our audio thread runs here. We receive captured audio samples on 150 // Our audio thread runs here. We receive captured audio samples on
195 // this thread. 151 // this thread.
196 void AudioInputDevice::Run() { 152 void AudioInputDevice::Run() {
153 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio);
154
197 int pending_data; 155 int pending_data;
198 const int samples_per_ms = static_cast<int>(sample_rate_) / 1000; 156 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; 157 const int bytes_per_ms = channels_ * (bits_per_sample_ / 8) * samples_per_ms;
200 158
201 while (sizeof(pending_data) == socket_->Receive(&pending_data, 159 while (sizeof(pending_data) == socket_->Receive(&pending_data,
202 sizeof(pending_data)) && 160 sizeof(pending_data)) &&
203 pending_data >= 0) { 161 pending_data >= 0) {
204 // TODO(henrika): investigate the provided |pending_data| value 162 // TODO(henrika): investigate the provided |pending_data| value
205 // and ensure that it is actually an accurate delay estimation. 163 // and ensure that it is actually an accurate delay estimation.
206 164
(...skipping 25 matching lines...) Expand all
232 bytes_per_sample, 190 bytes_per_sample,
233 number_of_frames); 191 number_of_frames);
234 } 192 }
235 193
236 // Deliver captured data to the client in floating point format 194 // Deliver captured data to the client in floating point format
237 // and update the audio-delay measurement. 195 // and update the audio-delay measurement.
238 callback_->Capture(audio_data_, 196 callback_->Capture(audio_data_,
239 number_of_frames, 197 number_of_frames,
240 audio_delay_milliseconds_); 198 audio_delay_milliseconds_);
241 } 199 }
OLDNEW
« no previous file with comments | « content/renderer/media/audio_input_device.h ('k') | content/renderer/media/audio_input_message_filter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698