blob: edbdbd89cedd42f32d83fed4999114c06b609255 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/audio/audio_device_thread.h"
#include <limits>
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
namespace media {
// AudioDeviceThread::Callback implementation
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::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";
DCHECK(!shared_memory_.memory());
MapSharedMemory();
CHECK(shared_memory_.memory());
}
// AudioDeviceThread implementation
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());
}
AudioDeviceThread::~AudioDeviceThread() {
socket_.Shutdown();
if (thread_handle_.is_null())
return;
base::PlatformThread::Join(thread_handle_);
}
void AudioDeviceThread::ThreadMain() {
base::PlatformThread::SetName(thread_name_);
base::ThreadRestrictions::SetSingletonAllowed(true);
callback_->InitializeOnAudioThread();
uint32_t buffer_index = 0;
while (true) {
uint32_t pending_data = 0;
size_t bytes_read = socket_.Receive(&pending_data, sizeof(pending_data));
if (bytes_read != sizeof(pending_data))
break;
// std::numeric_limits<uint32_t>::max() is a special signal which is
// returned after the browser stops the output device in response to a
// renderer side request.
//
// Avoid running Process() for the paused signal, we still need to update
// 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())
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().
++buffer_index;
size_t bytes_sent = socket_.Send(&buffer_index, sizeof(buffer_index));
if (bytes_sent != sizeof(buffer_index))
break;
}
}
} // namespace media.