audio_device_thread.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "media/audio/audio_device_thread.h" 6 7#include <algorithm> 8 9#include "base/bind.h" 10#include "base/logging.h" 11#include "base/memory/aligned_memory.h" 12#include "base/message_loop/message_loop.h" 13#include "base/threading/platform_thread.h" 14#include "base/threading/thread_restrictions.h" 15#include "media/base/audio_bus.h" 16 17using base::PlatformThread; 18 19namespace media { 20 21// The actual worker thread implementation. It's very bare bones and much 22// simpler than SimpleThread (no synchronization in Start, etc) and supports 23// joining the thread handle asynchronously via a provided message loop even 24// after the Thread object itself has been deleted. 25class AudioDeviceThread::Thread 26 : public PlatformThread::Delegate, 27 public base::RefCountedThreadSafe<AudioDeviceThread::Thread> { 28 public: 29 Thread(AudioDeviceThread::Callback* callback, 30 base::SyncSocket::Handle socket, 31 const char* thread_name); 32 33 void Start(); 34 35 // Stops the thread. If |loop_for_join| is non-NULL, the function posts 36 // a task to join (close) the thread handle later instead of waiting for 37 // the thread. If loop_for_join is NULL, then the function waits 38 // synchronously for the thread to terminate. 39 void Stop(base::MessageLoop* loop_for_join); 40 41 private: 42 friend class base::RefCountedThreadSafe<AudioDeviceThread::Thread>; 43 virtual ~Thread(); 44 45 // Overrides from PlatformThread::Delegate. 46 virtual void ThreadMain() OVERRIDE; 47 48 // Runs the loop that reads from the socket. 49 void Run(); 50 51 private: 52 base::PlatformThreadHandle thread_; 53 AudioDeviceThread::Callback* callback_; 54 base::CancelableSyncSocket socket_; 55 base::Lock callback_lock_; 56 const char* thread_name_; 57 58 DISALLOW_COPY_AND_ASSIGN(Thread); 59}; 60 61// AudioDeviceThread implementation 62 63AudioDeviceThread::AudioDeviceThread() { 64} 65 66AudioDeviceThread::~AudioDeviceThread() { DCHECK(!thread_.get()); } 67 68void AudioDeviceThread::Start(AudioDeviceThread::Callback* callback, 69 base::SyncSocket::Handle socket, 70 const char* thread_name) { 71 base::AutoLock auto_lock(thread_lock_); 72 CHECK(thread_.get() == NULL); 73 thread_ = new AudioDeviceThread::Thread(callback, socket, thread_name); 74 thread_->Start(); 75} 76 77void AudioDeviceThread::Stop(base::MessageLoop* loop_for_join) { 78 base::AutoLock auto_lock(thread_lock_); 79 if (thread_.get()) { 80 thread_->Stop(loop_for_join); 81 thread_ = NULL; 82 } 83} 84 85bool AudioDeviceThread::IsStopped() { 86 base::AutoLock auto_lock(thread_lock_); 87 return thread_.get() == NULL; 88} 89 90// AudioDeviceThread::Thread implementation 91AudioDeviceThread::Thread::Thread(AudioDeviceThread::Callback* callback, 92 base::SyncSocket::Handle socket, 93 const char* thread_name) 94 : thread_(), 95 callback_(callback), 96 socket_(socket), 97 thread_name_(thread_name) { 98} 99 100AudioDeviceThread::Thread::~Thread() { 101 DCHECK(thread_.is_null()); 102} 103 104void AudioDeviceThread::Thread::Start() { 105 base::AutoLock auto_lock(callback_lock_); 106 DCHECK(thread_.is_null()); 107 // This reference will be released when the thread exists. 108 AddRef(); 109 110 PlatformThread::CreateWithPriority(0, this, &thread_, 111 base::kThreadPriority_RealtimeAudio); 112 CHECK(!thread_.is_null()); 113} 114 115void AudioDeviceThread::Thread::Stop(base::MessageLoop* loop_for_join) { 116 socket_.Shutdown(); 117 118 base::PlatformThreadHandle thread = base::PlatformThreadHandle(); 119 120 { // NOLINT 121 base::AutoLock auto_lock(callback_lock_); 122 callback_ = NULL; 123 std::swap(thread, thread_); 124 } 125 126 if (!thread.is_null()) { 127 if (loop_for_join) { 128 loop_for_join->PostTask(FROM_HERE, 129 base::Bind(&base::PlatformThread::Join, thread)); 130 } else { 131 base::PlatformThread::Join(thread); 132 } 133 } 134} 135 136void AudioDeviceThread::Thread::ThreadMain() { 137 PlatformThread::SetName(thread_name_); 138 139 // Singleton access is safe from this thread as long as callback is non-NULL. 140 // The callback is the only point where the thread calls out to 'unknown' code 141 // that might touch singletons and the lifetime of the callback is controlled 142 // by another thread on which singleton access is OK as well. 143 base::ThreadRestrictions::SetSingletonAllowed(true); 144 145 { // NOLINT 146 base::AutoLock auto_lock(callback_lock_); 147 if (callback_) 148 callback_->InitializeOnAudioThread(); 149 } 150 151 Run(); 152 153 // Release the reference for the thread. Note that after this, the Thread 154 // instance will most likely be deleted. 155 Release(); 156} 157 158void AudioDeviceThread::Thread::Run() { 159 while (true) { 160 int pending_data = 0; 161 size_t bytes_read = socket_.Receive(&pending_data, sizeof(pending_data)); 162 if (bytes_read != sizeof(pending_data)) { 163 DCHECK_EQ(bytes_read, 0U); 164 break; 165 } 166 167 base::AutoLock auto_lock(callback_lock_); 168 if (callback_) 169 callback_->Process(pending_data); 170 } 171} 172 173// AudioDeviceThread::Callback implementation 174 175AudioDeviceThread::Callback::Callback( 176 const AudioParameters& audio_parameters, 177 base::SharedMemoryHandle memory, 178 int memory_length, 179 int total_segments) 180 : audio_parameters_(audio_parameters), 181 samples_per_ms_(audio_parameters.sample_rate() / 1000), 182 bytes_per_ms_(audio_parameters.channels() * 183 (audio_parameters_.bits_per_sample() / 8) * 184 samples_per_ms_), 185 shared_memory_(memory, false), 186 memory_length_(memory_length), 187 total_segments_(total_segments) { 188 CHECK_NE(bytes_per_ms_, 0); // Catch division by zero early. 189 CHECK_NE(samples_per_ms_, 0); 190 CHECK_GT(total_segments_, 0); 191 CHECK_EQ(memory_length_ % total_segments_, 0); 192 segment_length_ = memory_length_ / total_segments_; 193} 194 195AudioDeviceThread::Callback::~Callback() {} 196 197void AudioDeviceThread::Callback::InitializeOnAudioThread() { 198 MapSharedMemory(); 199 CHECK(shared_memory_.memory()); 200} 201 202} // namespace media. 203