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

Unified Diff: media/audio/audio_device_thread.cc

Issue 2076793002: Cleanup AudioDeviceThread to reduce locking and unused features. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 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 side-by-side diff with in-line comments
Download patch
Index: media/audio/audio_device_thread.cc
diff --git a/media/audio/audio_device_thread.cc b/media/audio/audio_device_thread.cc
index 20874599e68f5f7cfddeff0022291e64aa718b6c..03987d90d8ef7bf836d5273cee335a28cfe0b8cc 100644
--- a/media/audio/audio_device_thread.cc
+++ b/media/audio/audio_device_thread.cc
@@ -4,170 +4,68 @@
#include "media/audio/audio_device_thread.h"
-#include <stddef.h>
-#include <stdint.h>
-
-#include <algorithm>
#include <limits>
-#include "base/bind.h"
#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/aligned_memory.h"
-#include "base/message_loop/message_loop.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/threading/platform_thread.h"
#include "base/threading/thread_restrictions.h"
-#include "media/base/audio_bus.h"
-
-using base::PlatformThread;
namespace media {
-// The actual worker thread implementation. It's very bare bones and much
-// simpler than SimpleThread (no synchronization in Start, etc) and supports
-// joining the thread handle asynchronously via a provided message loop even
-// after the Thread object itself has been deleted.
-class AudioDeviceThread::Thread
- : public PlatformThread::Delegate,
- public base::RefCountedThreadSafe<AudioDeviceThread::Thread> {
- public:
- Thread(AudioDeviceThread::Callback* callback,
- base::SyncSocket::Handle socket,
- const char* thread_name,
- bool synchronized_buffers);
-
- void Start();
-
- // Stops the thread. If |loop_for_join| is non-NULL, the function posts
- // a task to join (close) the thread handle later instead of waiting for
- // the thread. If loop_for_join is NULL, then the function waits
- // synchronously for the thread to terminate.
- void Stop(base::MessageLoop* loop_for_join);
-
- private:
- friend class base::RefCountedThreadSafe<AudioDeviceThread::Thread>;
- ~Thread() override;
-
- // Overrides from PlatformThread::Delegate.
- void ThreadMain() override;
-
- // Runs the loop that reads from the socket.
- void Run();
-
- private:
- base::PlatformThreadHandle thread_;
- AudioDeviceThread::Callback* callback_;
- base::CancelableSyncSocket socket_;
- base::Lock callback_lock_;
- const char* thread_name_;
- const bool synchronized_buffers_;
-
- DISALLOW_COPY_AND_ASSIGN(Thread);
-};
-
-// AudioDeviceThread implementation
-
-AudioDeviceThread::AudioDeviceThread() {
-}
-
-AudioDeviceThread::~AudioDeviceThread() { DCHECK(!thread_.get()); }
-
-void AudioDeviceThread::Start(AudioDeviceThread::Callback* callback,
- base::SyncSocket::Handle socket,
- const char* thread_name,
- bool synchronized_buffers) {
- base::AutoLock auto_lock(thread_lock_);
- CHECK(!thread_.get());
- thread_ = new AudioDeviceThread::Thread(
- callback, socket, thread_name, synchronized_buffers);
- thread_->Start();
-}
-
-void AudioDeviceThread::Stop(base::MessageLoop* loop_for_join) {
- base::AutoLock auto_lock(thread_lock_);
- if (thread_.get()) {
- thread_->Stop(loop_for_join);
- thread_ = NULL;
- }
-}
+// AudioDeviceThread::Callback implementation
-bool AudioDeviceThread::IsStopped() {
- base::AutoLock auto_lock(thread_lock_);
- return !thread_.get();
+AudioDeviceThread::Callback::Callback(const AudioParameters& audio_parameters,
+ base::SharedMemoryHandle memory,
+ int memory_length,
+ int total_segments)
+ : audio_parameters_(audio_parameters),
+ samples_per_ms_(static_cast<double>(audio_parameters.sample_rate()) /
+ base::Time::kMillisecondsPerSecond),
+ bytes_per_ms_(audio_parameters.channels() *
+ (audio_parameters_.bits_per_sample() / 8) *
+ samples_per_ms_),
+ bytes_per_frame_(audio_parameters.GetBytesPerFrame()),
+ shared_memory_(memory, false),
+ memory_length_(memory_length),
+ total_segments_(total_segments) {
+ CHECK_NE(bytes_per_ms_, 0.0); // Catch division by zero early.
+ CHECK_NE(samples_per_ms_, 0.0);
+ CHECK_NE(bytes_per_frame_, 0u);
+ CHECK_GT(total_segments_, 0);
+ CHECK_EQ(memory_length_ % total_segments_, 0);
+ segment_length_ = memory_length_ / total_segments_;
}
-// AudioDeviceThread::Thread implementation
-AudioDeviceThread::Thread::Thread(AudioDeviceThread::Callback* callback,
- base::SyncSocket::Handle socket,
- const char* thread_name,
- bool synchronized_buffers)
- : thread_(),
- callback_(callback),
- socket_(socket),
- thread_name_(thread_name),
- synchronized_buffers_(synchronized_buffers) {
-}
+AudioDeviceThread::Callback::~Callback() {}
-AudioDeviceThread::Thread::~Thread() {
- DCHECK(thread_.is_null());
+void AudioDeviceThread::Callback::InitializeOnAudioThread() {
+ MapSharedMemory();
+ CHECK(shared_memory_.memory());
tommi (sloooow) - chröme 2016/06/16 22:19:22 should there be a [D]CHECK for memory() being null
DaleCurtis 2016/06/16 22:24:59 It's called in the ThreadMain() below so it must b
}
-void AudioDeviceThread::Thread::Start() {
- base::AutoLock auto_lock(callback_lock_);
- DCHECK(thread_.is_null());
- // This reference will be released when the thread exists.
- AddRef();
+// AudioDeviceThread implementation
- PlatformThread::CreateWithPriority(0, this, &thread_,
- base::ThreadPriority::REALTIME_AUDIO);
- CHECK(!thread_.is_null());
+AudioDeviceThread::AudioDeviceThread(Callback* callback,
+ base::SyncSocket::Handle socket,
+ const char* thread_name)
+ : callback_(callback), thread_name_(thread_name), socket_(socket) {
+ CHECK(base::PlatformThread::CreateWithPriority(
+ 0, this, &thread_handle_, base::ThreadPriority::REALTIME_AUDIO));
+ DCHECK(!thread_handle_.is_null());
}
-void AudioDeviceThread::Thread::Stop(base::MessageLoop* loop_for_join) {
+AudioDeviceThread::~AudioDeviceThread() {
socket_.Shutdown();
-
- base::PlatformThreadHandle thread = base::PlatformThreadHandle();
-
- { // NOLINT
- base::AutoLock auto_lock(callback_lock_);
- callback_ = NULL;
- std::swap(thread, thread_);
- }
-
- if (!thread.is_null()) {
- if (loop_for_join) {
- loop_for_join->PostTask(FROM_HERE,
- base::Bind(&base::PlatformThread::Join, thread));
- } else {
- base::PlatformThread::Join(thread);
- }
- }
+ if (thread_handle_.is_null())
+ return;
+ base::PlatformThread::Join(thread_handle_);
+ DCHECK(thread_handle_.is_null());
}
-void AudioDeviceThread::Thread::ThreadMain() {
- PlatformThread::SetName(thread_name_);
-
- // Singleton access is safe from this thread as long as callback is non-NULL.
- // The callback is the only point where the thread calls out to 'unknown' code
- // that might touch singletons and the lifetime of the callback is controlled
- // by another thread on which singleton access is OK as well.
+void AudioDeviceThread::ThreadMain() {
+ base::PlatformThread::SetName(thread_name_);
base::ThreadRestrictions::SetSingletonAllowed(true);
+ callback_->InitializeOnAudioThread();
- { // NOLINT
- base::AutoLock auto_lock(callback_lock_);
- if (callback_)
- callback_->InitializeOnAudioThread();
- }
-
- Run();
-
- // Release the reference for the thread. Note that after this, the Thread
- // instance will most likely be deleted.
- Release();
-}
-
-void AudioDeviceThread::Thread::Run() {
uint32_t buffer_index = 0;
while (true) {
uint32_t pending_data = 0;
@@ -180,63 +78,32 @@ void AudioDeviceThread::Thread::Run() {
// renderer side request.
//
// Avoid running Process() for the paused signal, we still need to update
- // the buffer index if |synchronized_buffers_| is true though.
+ // the buffer index for synchronized buffers though.
//
// See comments in AudioOutputController::DoPause() for details on why.
- if (pending_data != std::numeric_limits<uint32_t>::max()) {
- base::AutoLock auto_lock(callback_lock_);
- if (callback_)
- callback_->Process(pending_data);
- }
-
- // The usage of |synchronized_buffers_| differs between input and output
- // cases.
- // Input:
- // Let the other end know that we have read data, so that it can verify
- // it doesn't overwrite any data before read. The |buffer_index| value is
- // not used. For more details, see AudioInputSyncWriter::Write().
- // Output:
- // Let the other end know which buffer we just filled. The |buffer_index| is
- // used to ensure the other end is getting the buffer it expects. For more
- // details on how this works see AudioSyncReader::WaitUntilDataIsReady().
- if (synchronized_buffers_) {
- ++buffer_index;
- size_t bytes_sent = socket_.Send(&buffer_index, sizeof(buffer_index));
- if (bytes_sent != sizeof(buffer_index))
- break;
- }
- }
-}
-
-// AudioDeviceThread::Callback implementation
+ if (pending_data != std::numeric_limits<uint32_t>::max())
+ callback_->Process(pending_data);
-AudioDeviceThread::Callback::Callback(const AudioParameters& audio_parameters,
- base::SharedMemoryHandle memory,
- int memory_length,
- int total_segments)
- : audio_parameters_(audio_parameters),
- samples_per_ms_(static_cast<double>(audio_parameters.sample_rate()) /
- base::Time::kMillisecondsPerSecond),
- bytes_per_ms_(audio_parameters.channels() *
- (audio_parameters_.bits_per_sample() / 8) *
- samples_per_ms_),
- bytes_per_frame_(audio_parameters.GetBytesPerFrame()),
- shared_memory_(memory, false),
- memory_length_(memory_length),
- total_segments_(total_segments) {
- CHECK_NE(bytes_per_ms_, 0.0); // Catch division by zero early.
- CHECK_NE(samples_per_ms_, 0.0);
- CHECK_NE(bytes_per_frame_, 0u);
- CHECK_GT(total_segments_, 0);
- CHECK_EQ(memory_length_ % total_segments_, 0);
- segment_length_ = memory_length_ / total_segments_;
-}
-
-AudioDeviceThread::Callback::~Callback() {}
+ // The usage of synchronized buffers differs between input and output cases.
+ //
+ // Input: Let the other end know that we have read data, so that it can
+ // verify it doesn't overwrite any data before read. The |buffer_index|
+ // value is not used. For more details, see AudioInputSyncWriter::Write().
+ //
+ // Output: Let the other end know which buffer we just filled. The
+ // |buffer_index| is used to ensure the other end is getting the buffer it
+ // expects. For more details on how this works see
+ // AudioSyncReader::WaitUntilDataIsReady().
+ ++buffer_index;
+ size_t bytes_sent = socket_.Send(&buffer_index, sizeof(buffer_index));
+ if (bytes_sent != sizeof(buffer_index))
+ break;
+ }
-void AudioDeviceThread::Callback::InitializeOnAudioThread() {
- MapSharedMemory();
- CHECK(shared_memory_.memory());
+ // This can be racy, but we can't hold a lock here and if we don't clear this
+ // on failure, we may join the wrong thread during a later Stop().
+ // TODO(dalecurtis): Is there a better option here?
+ thread_handle_ = base::PlatformThreadHandle();
tommi (sloooow) - chröme 2016/06/16 22:19:22 I think we'll need to fix this before checkin. Id
DaleCurtis 2016/06/16 22:24:59 What do you think about changing this to a shutdow
tommi (sloooow) - chröme 2016/06/16 22:36:18 Hmm... this is both the normal and abnormal exit p
DaleCurtis 2016/06/16 22:55:16 Derp, I should actually do a bit more research bef
}
} // namespace media.

Powered by Google App Engine
This is Rietveld 408576698