audio_device_thread.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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_.get());
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_.get();
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      break;
171
172    {
173      base::AutoLock auto_lock(callback_lock_);
174      if (callback_)
175        callback_->Process(pending_data);
176    }
177
178    // Let the other end know which buffer we just filled.  The buffer index is
179    // used to ensure the other end is getting the buffer it expects.  For more
180    // details on how this works see AudioSyncReader::WaitUntilDataIsReady().
181    if (synchronized_buffers_) {
182      ++buffer_index;
183      size_t bytes_sent = socket_.Send(&buffer_index, sizeof(buffer_index));
184      if (bytes_sent != sizeof(buffer_index))
185        break;
186    }
187  }
188}
189
190// AudioDeviceThread::Callback implementation
191
192AudioDeviceThread::Callback::Callback(
193    const AudioParameters& audio_parameters,
194    base::SharedMemoryHandle memory,
195    int memory_length,
196    int total_segments)
197    : audio_parameters_(audio_parameters),
198      samples_per_ms_(audio_parameters.sample_rate() / 1000),
199      bytes_per_ms_(audio_parameters.channels() *
200                    (audio_parameters_.bits_per_sample() / 8) *
201                    samples_per_ms_),
202      shared_memory_(memory, false),
203      memory_length_(memory_length),
204      total_segments_(total_segments) {
205  CHECK_NE(bytes_per_ms_, 0);  // Catch division by zero early.
206  CHECK_NE(samples_per_ms_, 0);
207  CHECK_GT(total_segments_, 0);
208  CHECK_EQ(memory_length_ % total_segments_, 0);
209  segment_length_ = memory_length_ / total_segments_;
210}
211
212AudioDeviceThread::Callback::~Callback() {}
213
214void AudioDeviceThread::Callback::InitializeOnAudioThread() {
215  MapSharedMemory();
216  CHECK(shared_memory_.memory());
217}
218
219}  // namespace media.
220