summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-30 23:48:03 +0000
committertommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-30 23:48:03 +0000
commit0578a10ee761564494855ca55aa46816e6fe92ef (patch)
tree4f22b4e7f38be55b300ad408c607875cb81eddc5
parent42c7e23a6794de33750cfd8d889cfa538f1085a2 (diff)
downloadchromium_src-0578a10ee761564494855ca55aa46816e6fe92ef.zip
chromium_src-0578a10ee761564494855ca55aa46816e6fe92ef.tar.gz
chromium_src-0578a10ee761564494855ca55aa46816e6fe92ef.tar.bz2
Switch AudioDevice classes from SyncSocket to CancelableSyncSocket.
This fixes the double close issue and makes Stop() instant. Also, this addresses some issues reported by tsan (see bug reports). BUG=103711,95509 TEST=content_unittests,media_unittests Review URL: http://codereview.chromium.org/9121045 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@119769 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/browser/renderer_host/media/audio_input_sync_writer.cc7
-rw-r--r--content/browser/renderer_host/media/audio_input_sync_writer.h10
-rw-r--r--content/browser/renderer_host/media/audio_sync_reader.cc7
-rw-r--r--content/browser/renderer_host/media/audio_sync_reader.h10
-rw-r--r--content/renderer/media/audio_device.cc29
-rw-r--r--content/renderer/media/audio_device.h29
-rw-r--r--content/renderer/media/audio_input_device.cc79
-rw-r--r--content/renderer/media/audio_input_device.h6
8 files changed, 80 insertions, 97 deletions
diff --git a/content/browser/renderer_host/media/audio_input_sync_writer.cc b/content/browser/renderer_host/media/audio_input_sync_writer.cc
index 5a8870c..9524ad0 100644
--- a/content/browser/renderer_host/media/audio_input_sync_writer.cc
+++ b/content/browser/renderer_host/media/audio_input_sync_writer.cc
@@ -31,9 +31,10 @@ void AudioInputSyncWriter::Close() {
}
bool AudioInputSyncWriter::Init() {
- socket_.reset(new base::SyncSocket());
- foreign_socket_.reset(new base::SyncSocket());
- return base::SyncSocket::CreatePair(socket_.get(), foreign_socket_.get());
+ socket_.reset(new base::CancelableSyncSocket());
+ foreign_socket_.reset(new base::CancelableSyncSocket());
+ return base::CancelableSyncSocket::CreatePair(socket_.get(),
+ foreign_socket_.get());
}
#if defined(OS_WIN)
diff --git a/content/browser/renderer_host/media/audio_input_sync_writer.h b/content/browser/renderer_host/media/audio_input_sync_writer.h
index b3f69a8b..3114c35 100644
--- a/content/browser/renderer_host/media/audio_input_sync_writer.h
+++ b/content/browser/renderer_host/media/audio_input_sync_writer.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -41,12 +41,12 @@ class AudioInputSyncWriter : public media::AudioInputController::SyncWriter {
private:
base::SharedMemory* shared_memory_;
- // A pair of SyncSocket for transmitting audio data.
- scoped_ptr<base::SyncSocket> socket_;
+ // Socket for transmitting audio data.
+ scoped_ptr<base::CancelableSyncSocket> socket_;
- // SyncSocket to be used by the renderer. The reference is released after
+ // Socket to be used by the renderer. The reference is released after
// PrepareForeignSocketHandle() is called and ran successfully.
- scoped_ptr<base::SyncSocket> foreign_socket_;
+ scoped_ptr<base::CancelableSyncSocket> foreign_socket_;
DISALLOW_IMPLICIT_CONSTRUCTORS(AudioInputSyncWriter);
};
diff --git a/content/browser/renderer_host/media/audio_sync_reader.cc b/content/browser/renderer_host/media/audio_sync_reader.cc
index c06345a..7b6664b 100644
--- a/content/browser/renderer_host/media/audio_sync_reader.cc
+++ b/content/browser/renderer_host/media/audio_sync_reader.cc
@@ -92,9 +92,10 @@ void AudioSyncReader::Close() {
}
bool AudioSyncReader::Init() {
- socket_.reset(new base::SyncSocket());
- foreign_socket_.reset(new base::SyncSocket());
- return base::SyncSocket::CreatePair(socket_.get(), foreign_socket_.get());
+ socket_.reset(new base::CancelableSyncSocket());
+ foreign_socket_.reset(new base::CancelableSyncSocket());
+ return base::CancelableSyncSocket::CreatePair(socket_.get(),
+ foreign_socket_.get());
}
#if defined(OS_WIN)
diff --git a/content/browser/renderer_host/media/audio_sync_reader.h b/content/browser/renderer_host/media/audio_sync_reader.h
index 4aff8aa9..60a2879 100644
--- a/content/browser/renderer_host/media/audio_sync_reader.h
+++ b/content/browser/renderer_host/media/audio_sync_reader.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -45,12 +45,12 @@ class AudioSyncReader : public media::AudioOutputController::SyncReader {
base::SharedMemory* shared_memory_;
base::Time previous_call_time_;
- // A pair of SyncSocket for transmitting audio data.
- scoped_ptr<base::SyncSocket> socket_;
+ // Socket for transmitting audio data.
+ scoped_ptr<base::CancelableSyncSocket> socket_;
- // SyncSocket to be used by the renderer. The reference is released after
+ // Socket to be used by the renderer. The reference is released after
// PrepareForeignSocketHandle() is called and ran successfully.
- scoped_ptr<base::SyncSocket> foreign_socket_;
+ scoped_ptr<base::CancelableSyncSocket> foreign_socket_;
// Protect socket_ access by lock to prevent race condition when audio
// controller thread closes the reader and hardware audio thread is reading
diff --git a/content/renderer/media/audio_device.cc b/content/renderer/media/audio_device.cc
index b6ed566..19349c9 100644
--- a/content/renderer/media/audio_device.cc
+++ b/content/renderer/media/audio_device.cc
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/debug/trace_event.h"
#include "base/message_loop.h"
+#include "base/threading/thread_restrictions.h"
#include "base/time.h"
#include "content/common/child_process.h"
#include "content/common/media/audio_messages.h"
@@ -244,7 +245,7 @@ void AudioDevice::OnLowLatencyCreated(
shared_memory_handle_ = handle;
memory_length_ = length;
- audio_socket_ = new AudioSocket(socket_handle);
+ audio_socket_.reset(new base::CancelableSyncSocket(socket_handle));
audio_thread_.reset(
new base::DelegateSimpleThread(this, "renderer_audio_thread"));
@@ -271,20 +272,25 @@ void AudioDevice::Run() {
base::SharedMemory shared_memory(shared_memory_handle_, false);
shared_memory.Map(media::TotalSharedMemorySizeInBytes(memory_length_));
- scoped_refptr<AudioSocket> audio_socket(audio_socket_);
+ base::CancelableSyncSocket* audio_socket = audio_socket_.get();
- int pending_data;
const int samples_per_ms = static_cast<int>(sample_rate_) / 1000;
const int bytes_per_ms = channels_ * (bits_per_sample_ / 8) * samples_per_ms;
- while (sizeof(pending_data) ==
- audio_socket->socket()->Receive(&pending_data, sizeof(pending_data))) {
- if (pending_data == media::AudioOutputController::kPauseMark) {
+ while (true) {
+ uint32 pending_data = 0;
+ size_t bytes_read = audio_socket->Receive(&pending_data,
+ sizeof(pending_data));
+ if (bytes_read != sizeof(pending_data)) {
+ DCHECK_EQ(bytes_read, 0U);
+ break;
+ }
+
+ if (pending_data ==
+ static_cast<uint32>(media::AudioOutputController::kPauseMark)) {
memset(shared_memory.memory(), 0, memory_length_);
media::SetActualDataSizeInBytes(&shared_memory, memory_length_, 0);
continue;
- } else if (pending_data < 0) {
- break;
}
// Convert the number of pending bytes in the render buffer
@@ -298,7 +304,6 @@ void AudioDevice::Run() {
memory_length_,
num_frames * channels_ * sizeof(int16));
}
- audio_socket->Close();
}
size_t AudioDevice::FireRenderCallback(int16* data) {
@@ -328,9 +333,11 @@ void AudioDevice::ShutDownAudioThread() {
if (audio_thread_.get()) {
// Close the socket to terminate the main thread function in the
// audio thread.
- audio_socket_->Close();
- audio_socket_ = NULL;
+ audio_socket_->Shutdown(); // Stops blocking Receive calls.
+ // TODO(tommi): We must not do this from the IO thread. Fix.
+ base::ThreadRestrictions::ScopedAllowIO allow_wait;
audio_thread_->Join();
audio_thread_.reset(NULL);
+ audio_socket_.reset();
}
}
diff --git a/content/renderer/media/audio_device.h b/content/renderer/media/audio_device.h
index 9585ff0..de6ba3b 100644
--- a/content/renderer/media/audio_device.h
+++ b/content/renderer/media/audio_device.h
@@ -142,33 +142,6 @@ class CONTENT_EXPORT AudioDevice
virtual void OnVolume(double volume) OVERRIDE;
private:
- // Encapsulate socket into separate class to avoid double-close.
- // Class is ref-counted to avoid potential race condition if audio device
- // is deleted simultaneously with audio thread stopping.
- class AudioSocket : public base::RefCountedThreadSafe<AudioSocket> {
- public:
- explicit AudioSocket(base::SyncSocket::Handle socket_handle)
- : socket_(socket_handle) {
- }
- base::SyncSocket* socket() {
- return &socket_;
- }
- void Close() {
- // Close() should be thread-safe, obtain the lock.
- base::AutoLock auto_lock(lock_);
- socket_.Close();
- }
-
- private:
- // Magic required by ref_counted.h to avoid any code deleting the object
- // accidentally while there are references to it.
- friend class base::RefCountedThreadSafe<AudioSocket>;
- ~AudioSocket() { }
-
- base::Lock lock_;
- base::SyncSocket socket_;
- };
-
// Magic required by ref_counted.h to avoid any code deleting the object
// accidentally while there are references to it.
friend class base::RefCountedThreadSafe<AudioDevice>;
@@ -248,7 +221,7 @@ class CONTENT_EXPORT AudioDevice
// These variables must only be set on the IO thread while the audio_thread_
// is not running.
base::SharedMemoryHandle shared_memory_handle_;
- scoped_refptr<AudioSocket> audio_socket_;
+ scoped_ptr<base::CancelableSyncSocket> audio_socket_;
int memory_length_;
DISALLOW_COPY_AND_ASSIGN(AudioDevice);
diff --git a/content/renderer/media/audio_input_device.cc b/content/renderer/media/audio_input_device.cc
index 71a15f4..4a346e9 100644
--- a/content/renderer/media/audio_input_device.cc
+++ b/content/renderer/media/audio_input_device.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/message_loop.h"
+#include "base/threading/thread_restrictions.h"
#include "base/time.h"
#include "content/common/child_process.h"
#include "content/common/media/audio_messages.h"
@@ -27,7 +28,6 @@ AudioInputDevice::AudioInputDevice(size_t buffer_size,
session_id_(0),
pending_device_ready_(false),
shared_memory_handle_(base::SharedMemory::NULLHandle()),
- socket_handle_(base::SyncSocket::kInvalidHandle),
memory_length_(0) {
filter_ = RenderThreadImpl::current()->audio_input_message_filter();
audio_data_.reserve(channels);
@@ -77,13 +77,8 @@ void AudioInputDevice::SetDevice(int session_id) {
void AudioInputDevice::Stop() {
DCHECK(MessageLoop::current() != ChildProcess::current()->io_message_loop());
VLOG(1) << "Stop()";
- // Max waiting time for Stop() to complete. If this time limit is passed,
- // we will stop waiting and return false. It ensures that Stop() can't block
- // the calling thread forever.
- const base::TimeDelta kMaxTimeOut = base::TimeDelta::FromMilliseconds(1000);
base::WaitableEvent completion(false, false);
-
ChildProcess::current()->io_message_loop()->PostTask(
FROM_HERE,
base::Bind(&AudioInputDevice::ShutDownOnIOThread, this,
@@ -92,20 +87,7 @@ void AudioInputDevice::Stop() {
// We wait here for the IO task to be completed to remove race conflicts
// with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous
// function call.
- if (!completion.TimedWait(kMaxTimeOut)) {
- LOG(ERROR) << "Failed to shut down audio input on IO thread";
- }
-
- if (audio_thread_.get()) {
- // Terminate the main thread function in the audio thread.
- {
- base::SyncSocket socket(socket_handle_);
- }
- // Wait for the audio thread to exit.
- audio_thread_->Join();
- // Ensures that we can call Stop() multiple times.
- audio_thread_.reset(NULL);
- }
+ completion.Wait();
}
bool AudioInputDevice::SetVolume(double volume) {
@@ -161,6 +143,8 @@ void AudioInputDevice::ShutDownOnIOThread(base::WaitableEvent* completion) {
filter_->RemoveDelegate(stream_id_);
Send(new AudioInputHostMsg_CloseStream(stream_id_));
+ ShutDownAudioThread();
+
stream_id_ = 0;
session_id_ = 0;
pending_device_ready_ = false;
@@ -200,8 +184,7 @@ void AudioInputDevice::OnLowLatencyCreated(
shared_memory_handle_ = handle;
memory_length_ = length;
-
- socket_handle_ = socket_handle;
+ audio_socket_.reset(new base::CancelableSyncSocket(socket_handle));
audio_thread_.reset(
new base::DelegateSimpleThread(this, "RendererAudioInputThread"));
@@ -220,21 +203,15 @@ void AudioInputDevice::OnStateChanged(AudioStreamState state) {
DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
switch (state) {
case kAudioStreamPaused:
+ // TODO(xians): Should we just call ShutDownOnIOThread here instead?
+
// Do nothing if the stream has been closed.
if (!stream_id_)
return;
filter_->RemoveDelegate(stream_id_);
- // Joining the audio thread will be quite soon, since the stream has
- // been closed before.
- if (audio_thread_.get()) {
- {
- base::SyncSocket socket(socket_handle_);
- }
- audio_thread_->Join();
- audio_thread_.reset(NULL);
- }
+ ShutDownAudioThread();
if (event_handler_)
event_handler_->OnDeviceStopped();
@@ -268,8 +245,8 @@ void AudioInputDevice::OnDeviceReady(const std::string& device_id) {
filter_->RemoveDelegate(stream_id_);
stream_id_ = 0;
} else {
- Send(new AudioInputHostMsg_CreateStream(
- stream_id_, audio_parameters_, true, device_id));
+ Send(new AudioInputHostMsg_CreateStream(stream_id_, audio_parameters_,
+ true, device_id));
}
pending_device_ready_ = false;
@@ -290,17 +267,20 @@ void AudioInputDevice::Run() {
base::SharedMemory shared_memory(shared_memory_handle_, false);
shared_memory.Map(memory_length_);
- base::SyncSocket socket(socket_handle_);
+ base::CancelableSyncSocket* socket = audio_socket_.get();
- int pending_data;
const int samples_per_ms =
static_cast<int>(audio_parameters_.sample_rate) / 1000;
const int bytes_per_ms = audio_parameters_.channels *
(audio_parameters_.bits_per_sample / 8) * samples_per_ms;
- while ((sizeof(pending_data) == socket.Receive(&pending_data,
- sizeof(pending_data))) &&
- (pending_data >= 0)) {
+ while (true) {
+ uint32 pending_data = 0;
+ size_t received = socket->Receive(&pending_data, sizeof(pending_data));
+ if (received != sizeof(pending_data)) {
+ DCHECK(received == 0U);
+ break;
+ }
// TODO(henrika): investigate the provided |pending_data| value
// and ensure that it is actually an accurate delay estimation.
@@ -314,7 +294,7 @@ void AudioInputDevice::Run() {
void AudioInputDevice::FireCaptureCallback(int16* input_audio) {
if (!callback_)
- return;
+ return;
const size_t number_of_frames = audio_parameters_.samples_per_packet;
@@ -338,3 +318,22 @@ void AudioInputDevice::FireCaptureCallback(int16* input_audio) {
number_of_frames,
audio_delay_milliseconds_);
}
+
+void AudioInputDevice::ShutDownAudioThread() {
+ DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop());
+
+ // TODO(tommi): This is a copy/paste of the same method in AudioDevice.
+ // We could extract the worker thread+socket bits out to a separate
+ // class to avoid having to fix the same issues twice in these classes.
+
+ if (audio_thread_.get()) {
+ // Close the socket to terminate the main thread function in the
+ // audio thread.
+ audio_socket_->Shutdown(); // Stops blocking Receive calls.
+ // TODO(tommi): We must not do this from the IO thread. Fix.
+ base::ThreadRestrictions::ScopedAllowIO allow_wait;
+ audio_thread_->Join();
+ audio_thread_.reset(NULL);
+ audio_socket_.reset();
+ }
+}
diff --git a/content/renderer/media/audio_input_device.h b/content/renderer/media/audio_input_device.h
index ec74525..96dd2ff 100644
--- a/content/renderer/media/audio_input_device.h
+++ b/content/renderer/media/audio_input_device.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -164,6 +164,8 @@ class CONTENT_EXPORT AudioInputDevice
void StartOnIOThread();
void ShutDownOnIOThread(base::WaitableEvent* completion);
void SetVolumeOnIOThread(double volume);
+ // Closes socket and joins with the audio thread.
+ void ShutDownAudioThread();
void Send(IPC::Message* message);
@@ -209,7 +211,7 @@ class CONTENT_EXPORT AudioInputDevice
bool pending_device_ready_;
base::SharedMemoryHandle shared_memory_handle_;
- base::SyncSocket::Handle socket_handle_;
+ scoped_ptr<base::CancelableSyncSocket> audio_socket_;
int memory_length_;
DISALLOW_IMPLICIT_CONSTRUCTORS(AudioInputDevice);