blob: d000377fc55c44251aa6f47dbbc5a6da119e5cfa [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// 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 <ostream>
#include "base/check_op.h"
#include "base/system/sys_info.h"
#include "build/build_config.h"
namespace media {
// AudioDeviceThread::Callback implementation
AudioDeviceThread::Callback::Callback(const AudioParameters& audio_parameters,
uint32_t segment_length,
uint32_t total_segments)
: audio_parameters_(audio_parameters),
memory_length_(
base::CheckMul(segment_length, total_segments).ValueOrDie()),
total_segments_(total_segments),
segment_length_(segment_length) {
CHECK_GT(total_segments_, 0u);
thread_checker_.DetachFromThread();
}
AudioDeviceThread::Callback::~Callback() = default;
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";
MapSharedMemory();
}
// AudioDeviceThread implementation
AudioDeviceThread::AudioDeviceThread(Callback* callback,
base::SyncSocket::ScopedHandle socket,
const char* thread_name,
base::ThreadType thread_type)
: callback_(callback),
thread_name_(thread_name),
socket_(std::move(socket)) {
#if defined(ARCH_CPU_X86)
// Audio threads don't need a huge stack, they don't have a message loop and
// they are used exclusively for polling the next frame of audio. See
// https://crbug.com/1141563 for discussion.
constexpr size_t kStackSize = 256 * 1024;
#else
constexpr size_t kStackSize = 0; // Default.
#endif
CHECK(base::PlatformThread::CreateWithType(kStackSize, this, &thread_handle_,
thread_type));
DCHECK(!thread_handle_.is_null());
}
AudioDeviceThread::~AudioDeviceThread() {
socket_.Shutdown();
if (thread_handle_.is_null())
return;
base::PlatformThread::Join(thread_handle_);
}
#if BUILDFLAG(IS_APPLE)
base::TimeDelta AudioDeviceThread::GetRealtimePeriod() {
return callback_->buffer_duration();
}
#endif
void AudioDeviceThread::ThreadMain() {
base::PlatformThread::SetName(thread_name_);
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.