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

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

Issue 8659040: There is a racing between SyncSocket::Receive in audio_thread_ and SyncSocket::Close in renderer ... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: update Created 9 years 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
« no previous file with comments | « content/renderer/media/audio_device.h ('k') | content/renderer/media/audio_input_device.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_device.h" 5 #include "content/renderer/media/audio_device.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/debug/trace_event.h" 8 #include "base/debug/trace_event.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/time.h" 10 #include "base/time.h"
11 #include "content/common/child_process.h" 11 #include "content/common/child_process.h"
12 #include "content/common/media/audio_messages.h" 12 #include "content/common/media/audio_messages.h"
13 #include "content/common/view_messages.h" 13 #include "content/common/view_messages.h"
14 #include "content/renderer/render_thread_impl.h" 14 #include "content/renderer/render_thread_impl.h"
15 #include "media/audio/audio_util.h" 15 #include "media/audio/audio_util.h"
16 16
17 AudioDevice::AudioDevice(size_t buffer_size, 17 AudioDevice::AudioDevice(size_t buffer_size,
18 int channels, 18 int channels,
19 double sample_rate, 19 double sample_rate,
20 RenderCallback* callback) 20 RenderCallback* callback)
21 : buffer_size_(buffer_size), 21 : buffer_size_(buffer_size),
22 channels_(channels), 22 channels_(channels),
23 bits_per_sample_(16), 23 bits_per_sample_(16),
24 sample_rate_(sample_rate), 24 sample_rate_(sample_rate),
25 callback_(callback), 25 callback_(callback),
26 audio_delay_milliseconds_(0), 26 audio_delay_milliseconds_(0),
27 volume_(1.0), 27 volume_(1.0),
28 stream_id_(0) { 28 stream_id_(0),
29 memory_length_(0) {
29 filter_ = RenderThreadImpl::current()->audio_message_filter(); 30 filter_ = RenderThreadImpl::current()->audio_message_filter();
30 audio_data_.reserve(channels); 31 audio_data_.reserve(channels);
31 for (int i = 0; i < channels; ++i) { 32 for (int i = 0; i < channels; ++i) {
32 float* channel_data = new float[buffer_size]; 33 float* channel_data = new float[buffer_size];
33 audio_data_.push_back(channel_data); 34 audio_data_.push_back(channel_data);
34 } 35 }
35 } 36 }
36 37
37 AudioDevice::~AudioDevice() { 38 AudioDevice::~AudioDevice() {
38 // The current design requires that the user calls Stop() before deleting 39 // The current design requires that the user calls Stop() before deleting
39 // this class. 40 // this class.
40 CHECK_EQ(0, stream_id_); 41 CHECK_EQ(0, stream_id_);
41 for (int i = 0; i < channels_; ++i) 42 for (int i = 0; i < channels_; ++i)
42 delete [] audio_data_[i]; 43 delete [] audio_data_[i];
43 } 44 }
44 45
45 void AudioDevice::Start() { 46 void AudioDevice::Start() {
46 AudioParameters params; 47 AudioParameters params;
47 params.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; 48 params.format = AudioParameters::AUDIO_PCM_LOW_LATENCY;
48 params.channels = channels_; 49 params.channels = channels_;
49 params.sample_rate = static_cast<int>(sample_rate_); 50 params.sample_rate = static_cast<int>(sample_rate_);
50 params.bits_per_sample = bits_per_sample_; 51 params.bits_per_sample = bits_per_sample_;
51 params.samples_per_packet = buffer_size_; 52 params.samples_per_packet = buffer_size_;
52 53
53 ChildProcess::current()->io_message_loop()->PostTask( 54 ChildProcess::current()->io_message_loop()->PostTask(
54 FROM_HERE, 55 FROM_HERE,
55 base::Bind(&AudioDevice::InitializeOnIOThread, this, params)); 56 base::Bind(&AudioDevice::InitializeOnIOThread, this, params));
56 } 57 }
57 58
58 bool AudioDevice::Stop() { 59 void AudioDevice::Stop() {
60 DCHECK(MessageLoop::current() != ChildProcess::current()->io_message_loop());
59 // Max waiting time for Stop() to complete. If this time limit is passed, 61 // Max waiting time for Stop() to complete. If this time limit is passed,
60 // we will stop waiting and return false. It ensures that Stop() can't block 62 // we will stop waiting and return false. It ensures that Stop() can't block
61 // the calling thread forever. 63 // the calling thread forever.
62 const base::TimeDelta kMaxTimeOut = base::TimeDelta::FromMilliseconds(1000); 64 const base::TimeDelta kMaxTimeOut = base::TimeDelta::FromMilliseconds(1000);
63 65
64 base::WaitableEvent completion(false, false); 66 base::WaitableEvent completion(false, false);
65 67
66 ChildProcess::current()->io_message_loop()->PostTask( 68 ChildProcess::current()->io_message_loop()->PostTask(
67 FROM_HERE, 69 FROM_HERE,
68 base::Bind(&AudioDevice::ShutDownOnIOThread, this, &completion)); 70 base::Bind(&AudioDevice::ShutDownOnIOThread, this, &completion));
69 71
70 // We wait here for the IO task to be completed to remove race conflicts 72 // We wait here for the IO task to be completed to remove race conflicts
71 // with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous 73 // with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous
72 // function call. 74 // function call.
73 if (completion.TimedWait(kMaxTimeOut)) { 75 if (!completion.TimedWait(kMaxTimeOut)) {
74 if (audio_thread_.get()) {
75 socket_->Close();
76 audio_thread_->Join();
77 audio_thread_.reset(NULL);
78 }
79 } else {
80 LOG(ERROR) << "Failed to shut down audio output on IO thread"; 76 LOG(ERROR) << "Failed to shut down audio output on IO thread";
81 return false;
82 } 77 }
83 78
84 return true; 79 if (audio_thread_.get()) {
80 // Close the socket handler to terminate the main thread function in the
81 // audio thread.
82 {
83 base::SyncSocket socket(socket_handle_);
84 }
85 audio_thread_->Join();
86 audio_thread_.reset(NULL);
87 }
85 } 88 }
86 89
87 bool AudioDevice::SetVolume(double volume) { 90 bool AudioDevice::SetVolume(double volume) {
88 if (volume < 0 || volume > 1.0) 91 if (volume < 0 || volume > 1.0)
89 return false; 92 return false;
90 93
91 ChildProcess::current()->io_message_loop()->PostTask( 94 ChildProcess::current()->io_message_loop()->PostTask(
92 FROM_HERE, 95 FROM_HERE,
93 base::Bind(&AudioDevice::SetVolumeOnIOThread, this, volume)); 96 base::Bind(&AudioDevice::SetVolumeOnIOThread, this, volume));
94 97
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 uint32 length) { 163 uint32 length) {
161 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 164 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
162 #if defined(OS_WIN) 165 #if defined(OS_WIN)
163 DCHECK(handle); 166 DCHECK(handle);
164 DCHECK(socket_handle); 167 DCHECK(socket_handle);
165 #else 168 #else
166 DCHECK_GE(handle.fd, 0); 169 DCHECK_GE(handle.fd, 0);
167 DCHECK_GE(socket_handle, 0); 170 DCHECK_GE(socket_handle, 0);
168 #endif 171 #endif
169 DCHECK(length); 172 DCHECK(length);
173 DCHECK(!audio_thread_.get());
170 174
171 // Takes care of the case when Stop() is called before OnLowLatencyCreated(). 175 // Takes care of the case when Stop() is called before OnLowLatencyCreated().
172 if (!stream_id_) { 176 if (!stream_id_) {
173 base::SharedMemory::CloseHandle(handle); 177 base::SharedMemory::CloseHandle(handle);
174 // Close the socket handler. 178 // Close the socket handler.
175 base::SyncSocket socket(socket_handle); 179 base::SyncSocket socket(socket_handle);
176 return; 180 return;
177 } 181 }
178 182
179 shared_memory_.reset(new base::SharedMemory(handle, false)); 183 shared_memory_handle_ = handle;
180 shared_memory_->Map(length); 184 memory_length_ = length;
181 185
182 DCHECK_GE(length, buffer_size_ * sizeof(int16) * channels_); 186 DCHECK_GE(length, buffer_size_ * sizeof(int16) * channels_);
183 187
184 socket_.reset(new base::SyncSocket(socket_handle)); 188 socket_handle_ = socket_handle;
185 // Allow the client to pre-populate the buffer.
186 FireRenderCallback();
187 189
188 audio_thread_.reset( 190 audio_thread_.reset(
189 new base::DelegateSimpleThread(this, "renderer_audio_thread")); 191 new base::DelegateSimpleThread(this, "renderer_audio_thread"));
190 audio_thread_->Start(); 192 audio_thread_->Start();
191 193
192 MessageLoop::current()->PostTask( 194 MessageLoop::current()->PostTask(
193 FROM_HERE, 195 FROM_HERE,
194 base::Bind(&AudioDevice::StartOnIOThread, this)); 196 base::Bind(&AudioDevice::StartOnIOThread, this));
195 } 197 }
196 198
197 void AudioDevice::OnVolume(double volume) { 199 void AudioDevice::OnVolume(double volume) {
198 NOTIMPLEMENTED(); 200 NOTIMPLEMENTED();
199 } 201 }
200 202
201 void AudioDevice::Send(IPC::Message* message) { 203 void AudioDevice::Send(IPC::Message* message) {
202 filter_->Send(message); 204 filter_->Send(message);
203 } 205 }
204 206
205 // Our audio thread runs here. 207 // Our audio thread runs here.
206 void AudioDevice::Run() { 208 void AudioDevice::Run() {
207 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio); 209 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio);
208 210
211 base::SharedMemory shared_memory(shared_memory_handle_, false);
212 shared_memory.Map(memory_length_);
213 // Allow the client to pre-populate the buffer.
214 FireRenderCallback(reinterpret_cast<int16*>(shared_memory.memory()));
215
216 base::SyncSocket socket(socket_handle_);
217
209 int pending_data; 218 int pending_data;
210 const int samples_per_ms = static_cast<int>(sample_rate_) / 1000; 219 const int samples_per_ms = static_cast<int>(sample_rate_) / 1000;
211 const int bytes_per_ms = channels_ * (bits_per_sample_ / 8) * samples_per_ms; 220 const int bytes_per_ms = channels_ * (bits_per_sample_ / 8) * samples_per_ms;
212 221
213 while ((sizeof(pending_data) == socket_->Receive(&pending_data, 222 while ((sizeof(pending_data) == socket.Receive(&pending_data,
214 sizeof(pending_data))) && 223 sizeof(pending_data))) &&
215 (pending_data >= 0)) { 224 (pending_data >= 0)) {
216 // Convert the number of pending bytes in the render buffer 225 // Convert the number of pending bytes in the render buffer
217 // into milliseconds. 226 // into milliseconds.
218 audio_delay_milliseconds_ = pending_data / bytes_per_ms; 227 audio_delay_milliseconds_ = pending_data / bytes_per_ms;
219 FireRenderCallback(); 228 FireRenderCallback(reinterpret_cast<int16*>(shared_memory.memory()));
220 } 229 }
221 } 230 }
222 231
223 void AudioDevice::FireRenderCallback() { 232 void AudioDevice::FireRenderCallback(int16* data) {
224 TRACE_EVENT0("audio", "AudioDevice::FireRenderCallback"); 233 TRACE_EVENT0("audio", "AudioDevice::FireRenderCallback");
225 234
226 if (callback_) { 235 if (callback_) {
227 // Update the audio-delay measurement then ask client to render audio. 236 // Update the audio-delay measurement then ask client to render audio.
228 callback_->Render(audio_data_, buffer_size_, audio_delay_milliseconds_); 237 callback_->Render(audio_data_, buffer_size_, audio_delay_milliseconds_);
229 238
230 // Interleave, scale, and clip to int16. 239 // Interleave, scale, and clip to int16.
231 media::InterleaveFloatToInt16(audio_data_, 240 media::InterleaveFloatToInt16(audio_data_,
232 static_cast<int16*>(shared_memory_data()), 241 data,
233 buffer_size_); 242 buffer_size_);
234 } 243 }
235 } 244 }
OLDNEW
« no previous file with comments | « content/renderer/media/audio_device.h ('k') | content/renderer/media/audio_input_device.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698