audio_device_thread.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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 bool synchronized_buffers); 33 34 void Start(); 35 36 // Stops the thread. If |loop_for_join| is non-NULL, the function posts 37 // a task to join (close) the thread handle later instead of waiting for 38 // the thread. If loop_for_join is NULL, then the function waits 39 // synchronously for the thread to terminate. 40 void Stop(base::MessageLoop* loop_for_join); 41 42 private: 43 friend class base::RefCountedThreadSafe<AudioDeviceThread::Thread>; 44 virtual ~Thread(); 45 46 // Overrides from PlatformThread::Delegate. 47 virtual void ThreadMain() OVERRIDE; 48 49 // Runs the loop that reads from the socket. 50 void Run(); 51 52 private: 53 base::PlatformThreadHandle thread_; 54 AudioDeviceThread::Callback* callback_; 55 base::CancelableSyncSocket socket_; 56 base::Lock callback_lock_; 57 const char* thread_name_; 58 const bool synchronized_buffers_; 59 60 DISALLOW_COPY_AND_ASSIGN(Thread); 61}; 62 63// AudioDeviceThread implementation 64 65AudioDeviceThread::AudioDeviceThread() { 66} 67 68AudioDeviceThread::~AudioDeviceThread() { DCHECK(!thread_.get()); } 69 70void AudioDeviceThread::Start(AudioDeviceThread::Callback* callback, 71 base::SyncSocket::Handle socket, 72 const char* thread_name, 73 bool synchronized_buffers) { 74 base::AutoLock auto_lock(thread_lock_); 75 CHECK(!thread_); 76 thread_ = new AudioDeviceThread::Thread( 77 callback, socket, thread_name, synchronized_buffers); 78 thread_->Start(); 79} 80 81void AudioDeviceThread::Stop(base::MessageLoop* loop_for_join) { 82 base::AutoLock auto_lock(thread_lock_); 83 if (thread_.get()) { 84 thread_->Stop(loop_for_join); 85 thread_ = NULL; 86 } 87} 88 89bool AudioDeviceThread::IsStopped() { 90 base::AutoLock auto_lock(thread_lock_); 91 return !thread_; 92} 93 94// AudioDeviceThread::Thread implementation 95AudioDeviceThread::Thread::Thread(AudioDeviceThread::Callback* callback, 96 base::SyncSocket::Handle socket, 97 const char* thread_name, 98 bool synchronized_buffers) 99 : thread_(), 100 callback_(callback), 101 socket_(socket), 102 thread_name_(thread_name), 103 synchronized_buffers_(synchronized_buffers) { 104} 105 106AudioDeviceThread::Thread::~Thread() { 107 DCHECK(thread_.is_null()); 108} 109 110void AudioDeviceThread::Thread::Start() { 111 base::AutoLock auto_lock(callback_lock_); 112 DCHECK(thread_.is_null()); 113 // This reference will be released when the thread exists. 114 AddRef(); 115 116 PlatformThread::CreateWithPriority(0, this, &thread_, 117 base::kThreadPriority_RealtimeAudio); 118 CHECK(!thread_.is_null()); 119} 120 121void AudioDeviceThread::Thread::Stop(base::MessageLoop* loop_for_join) { 122 socket_.Shutdown(); 123 124 base::PlatformThreadHandle thread = base::PlatformThreadHandle(); 125 126 { // NOLINT 127 base::AutoLock auto_lock(callback_lock_); 128 callback_ = NULL; 129 std::swap(thread, thread_); 130 } 131 132 if (!thread.is_null()) { 133 if (loop_for_join) { 134 loop_for_join->PostTask(FROM_HERE, 135 base::Bind(&base::PlatformThread::Join, thread)); 136 } else { 137 base::PlatformThread::Join(thread); 138 } 139 } 140} 141 142void AudioDeviceThread::Thread::ThreadMain() { 143 PlatformThread::SetName(thread_name_); 144 145 // Singleton access is safe from this thread as long as callback is non-NULL. 146 // The callback is the only point where the thread calls out to 'unknown' code 147 // that might touch singletons and the lifetime of the callback is controlled 148 // by another thread on which singleton access is OK as well. 149 base::ThreadRestrictions::SetSingletonAllowed(true); 150 151 { // NOLINT 152 base::AutoLock auto_lock(callback_lock_); 153 if (callback_) 154 callback_->InitializeOnAudioThread(); 155 } 156 157 Run(); 158 159 // Release the reference for the thread. Note that after this, the Thread 160 // instance will most likely be deleted. 161 Release(); 162} 163 164void AudioDeviceThread::Thread::Run() { 165 uint32 buffer_index = 0; 166 while (true) { 167 int pending_data = 0; 168 size_t bytes_read = socket_.Receive(&pending_data, sizeof(pending_data)); 169 if (bytes_read != sizeof(pending_data)) { 170 DCHECK_EQ(bytes_read, 0U); 171 break; 172 } 173 174 { 175 base::AutoLock auto_lock(callback_lock_); 176 if (callback_) 177 callback_->Process(pending_data); 178 } 179 180 // Let the other end know which buffer we just filled. The buffer index is 181 // used to ensure the other end is getting the buffer it expects. For more 182 // details on how this works see AudioSyncReader::WaitUntilDataIsReady(). 183 if (synchronized_buffers_) { 184 ++buffer_index; 185 size_t bytes_sent = socket_.Send(&buffer_index, sizeof(buffer_index)); 186 if (bytes_sent != sizeof(buffer_index)) 187 break; 188 } 189 } 190} 191 192// AudioDeviceThread::Callback implementation 193 194AudioDeviceThread::Callback::Callback( 195 const AudioParameters& audio_parameters, 196 base::SharedMemoryHandle memory, 197 int memory_length, 198 int total_segments) 199 : audio_parameters_(audio_parameters), 200 samples_per_ms_(audio_parameters.sample_rate() / 1000), 201 bytes_per_ms_(audio_parameters.channels() * 202 (audio_parameters_.bits_per_sample() / 8) * 203 samples_per_ms_), 204 shared_memory_(memory, false), 205 memory_length_(memory_length), 206 total_segments_(total_segments) { 207 CHECK_NE(bytes_per_ms_, 0); // Catch division by zero early. 208 CHECK_NE(samples_per_ms_, 0); 209 CHECK_GT(total_segments_, 0); 210 CHECK_EQ(memory_length_ % total_segments_, 0); 211 segment_length_ = memory_length_ / total_segments_; 212} 213 214AudioDeviceThread::Callback::~Callback() {} 215 216void AudioDeviceThread::Callback::InitializeOnAudioThread() { 217 MapSharedMemory(); 218 CHECK(shared_memory_.memory()); 219} 220 221} // namespace media. 222