blob: 9f35ff25d423d8debf4c3869c1a4430750160257 [file] [log] [blame]
// Copyright 2018 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 "services/audio/public/cpp/output_device.h"
#include <utility>
#include "base/bind.h"
#include "base/threading/thread_restrictions.h"
#include "media/audio/audio_output_device_thread_callback.h"
#include "media/mojo/mojom/audio_data_pipe.mojom.h"
#include "media/mojo/mojom/audio_logging.mojom.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace audio {
OutputDevice::OutputDevice(
mojo::PendingRemote<media::mojom::AudioStreamFactory> stream_factory,
const media::AudioParameters& params,
media::AudioRendererSink::RenderCallback* render_callback,
const std::string& device_id)
: audio_parameters_(params),
render_callback_(render_callback),
stream_factory_(std::move(stream_factory)) {
DETACH_FROM_SEQUENCE(sequence_checker_);
DCHECK(params.IsValid());
stream_factory_->CreateOutputStream(
stream_.BindNewPipeAndPassReceiver(), mojo::NullAssociatedRemote(),
mojo::NullRemote(), device_id, params, base::UnguessableToken::Create(),
base::BindOnce(&OutputDevice::StreamCreated, weak_factory_.GetWeakPtr()));
stream_.set_disconnect_handler(base::BindOnce(
&OutputDevice::OnConnectionError, weak_factory_.GetWeakPtr()));
}
OutputDevice::~OutputDevice() {
CleanUp();
}
void OutputDevice::Play() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
stream_->Play();
}
void OutputDevice::Pause() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
stream_->Pause();
}
void OutputDevice::SetVolume(double volume) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
stream_->SetVolume(volume);
}
void OutputDevice::StreamCreated(
media::mojom::ReadWriteAudioDataPipePtr data_pipe) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!data_pipe)
return;
DCHECK(data_pipe->socket.is_valid_platform_file());
base::ScopedPlatformFile socket_handle = data_pipe->socket.TakePlatformFile();
base::UnsafeSharedMemoryRegion& shared_memory_region =
data_pipe->shared_memory;
DCHECK(shared_memory_region.IsValid());
DCHECK(!audio_callback_);
DCHECK(!audio_thread_);
audio_callback_ = std::make_unique<media::AudioOutputDeviceThreadCallback>(
audio_parameters_, std::move(shared_memory_region), render_callback_);
audio_thread_ = std::make_unique<media::AudioDeviceThread>(
audio_callback_.get(), std::move(socket_handle), "audio::OutputDevice",
base::ThreadPriority::REALTIME_AUDIO);
}
void OutputDevice::OnConnectionError() {
// Connection errors should be rare and handling them synchronously is
// simpler.
base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_thread_join;
CleanUp();
}
void OutputDevice::CleanUp() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
audio_thread_.reset(); // Blocking call.
audio_callback_.reset();
stream_.reset();
stream_factory_.reset();
}
} // namespace audio