| Index: media/audio/audio_device_thread.cc
|
| diff --git a/media/audio/audio_device_thread.cc b/media/audio/audio_device_thread.cc
|
| index 5d0767a3f087b58dd6a104eced9069de4ed41a34..edbdbd89cedd42f32d83fed4999114c06b609255 100644
|
| --- a/media/audio/audio_device_thread.cc
|
| +++ b/media/audio/audio_device_thread.cc
|
| @@ -4,170 +4,67 @@
|
|
|
| #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),
|
| + shared_memory_(memory, false),
|
| + memory_length_(memory_length),
|
| + total_segments_(total_segments),
|
| + // Avoid division by zero during construction.
|
| + segment_length_(memory_length_ /
|
| + (total_segments_ ? total_segments_ : 1)) {
|
| + CHECK_GT(total_segments_, 0);
|
| + CHECK_EQ(memory_length_ % total_segments_, 0);
|
| + thread_checker_.DetachFromThread();
|
| }
|
|
|
| -// 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() {
|
| + // Normally this function is called before the thread checker is used
|
| + // elsewhere, but it's not guaranteed. DCHECK to ensure it was not used on
|
| + // another thread before we get here.
|
| + DCHECK(thread_checker_.CalledOnValidThread())
|
| + << "Thread checker was attached on the wrong thread";
|
| + DCHECK(!shared_memory_.memory());
|
| + MapSharedMemory();
|
| + CHECK(shared_memory_.memory());
|
| }
|
|
|
| -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_);
|
| }
|
|
|
| -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,69 +77,27 @@ 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;
|
| - }
|
| - }
|
| -}
|
| + if (pending_data != std::numeric_limits<uint32_t>::max())
|
| + callback_->Process(pending_data);
|
|
|
| -// AudioDeviceThread::Callback implementation
|
| -
|
| -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_;
|
| - thread_checker_.DetachFromThread();
|
| -}
|
| -
|
| -AudioDeviceThread::Callback::~Callback() {}
|
| -
|
| -void AudioDeviceThread::Callback::InitializeOnAudioThread() {
|
| - // Normally this function is called before the thread checker is used
|
| - // elsewhere, but it's not guaranteed. DCHECK to ensure it was not used on
|
| - // another thread before we get here.
|
| - DCHECK(thread_checker_.CalledOnValidThread())
|
| - << "Thread checker was attached on the wrong thread";
|
| - MapSharedMemory();
|
| - CHECK(shared_memory_.memory());
|
| + // 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;
|
| + }
|
| }
|
|
|
| } // namespace media.
|
|
|