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