chromium/media/audio/alsa/alsa_output.cc

// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// THREAD SAFETY
//
// AlsaPcmOutputStream object is *not* thread-safe and should only be used
// from the audio thread.  We DCHECK on this assumption whenever we can.
//
// SEMANTICS OF Close()
//
// Close() is responsible for cleaning up any resources that were acquired after
// a successful Open().  Close() will nullify any scheduled outstanding runnable
// methods.
//
//
// SEMANTICS OF ERROR STATES
//
// The object has two distinct error states: |state_| == kInError
// and |stop_stream_|.  The |stop_stream_| variable is used to indicate
// that the playback_handle should no longer be used either because of a
// hardware/low-level event.
//
// When |state_| == kInError, all public API functions will fail with an error
// (Start() will call the OnError() function on the callback immediately), or
// no-op themselves with the exception of Close().  Even if an error state has
// been entered, if Open() has previously returned successfully, Close() must be
// called to cleanup the ALSA devices and release resources.
//
// When |stop_stream_| is set, no more commands will be made against the
// ALSA device, and playback will effectively stop.  From the client's point of
// view, it will seem that the device has just clogged and stopped requesting
// data.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "media/audio/alsa/alsa_output.h"

#include <stddef.h>

#include <algorithm>
#include <memory>
#include <utility>

#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/memory/free_deleter.h"
#include "base/metrics/histogram_macros.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/default_tick_clock.h"
#include "base/trace_event/typed_macros.h"
#include "media/audio/alsa/alsa_util.h"
#include "media/audio/alsa/alsa_wrapper.h"
#include "media/audio/alsa/audio_manager_alsa.h"
#include "media/base/audio_timestamp_helper.h"
#include "media/base/channel_mixer.h"
#include "media/base/data_buffer.h"
#include "media/base/seekable_buffer.h"

namespace media {

// Set to 0 during debugging if you want error messages due to underrun
// events or other recoverable errors.
#if defined(NDEBUG)
static const int kPcmRecoverIsSilent = 1;
#else
static const int kPcmRecoverIsSilent =;
#endif

// The output channel layout if we set up downmixing for the kDefaultDevice
// device.
static const ChannelLayout kDefaultOutputChannelLayout =;

// While the "default" device may support multi-channel audio, in Alsa, only
// the device names surround40, surround41, surround50, etc, have a defined
// channel mapping according to Lennart:
//
// http://0pointer.de/blog/projects/guide-to-sound-apis.html
//
// This function makes a best guess at the specific > 2 channel device name
// based on the number of channels requested.  nullptr is returned if no device
// can be found to match the channel numbers.  In this case, using
// kDefaultDevice is probably the best bet.
//
// A five channel source is assumed to be surround50 instead of surround41
// (which is also 5 channels).
//
// TODO(ajwong): The source data should have enough info to tell us if we want
// surround41 versus surround51, etc., instead of needing us to guess based on
// channel number.  Fix API to pass that data down.
static const char* GuessSpecificDeviceName(uint32_t channels) {}

std::ostream& operator<<(std::ostream& os,
                         AlsaPcmOutputStream::InternalState state) {}

static const SampleFormat kSampleFormat =;
static const snd_pcm_format_t kAlsaSampleFormat =;

const char AlsaPcmOutputStream::kDefaultDevice[] =;
const char AlsaPcmOutputStream::kAutoSelectDevice[] =;
const char AlsaPcmOutputStream::kPlugPrefix[] =;

// We use 40ms as our minimum required latency. If it is needed, we may be able
// to get it down to 20ms.
const uint32_t AlsaPcmOutputStream::kMinLatencyMicros =;

AlsaPcmOutputStream::AlsaPcmOutputStream(const std::string& device_name,
                                         const AudioParameters& params,
                                         AlsaWrapper* wrapper,
                                         AudioManagerBase* manager)
    :{}

AlsaPcmOutputStream::~AlsaPcmOutputStream() {}

bool AlsaPcmOutputStream::Open() {}

void AlsaPcmOutputStream::Close() {}

void AlsaPcmOutputStream::Start(AudioSourceCallback* callback) {}

void AlsaPcmOutputStream::Stop() {}

// This stream is always used with sub second buffer sizes, where it's
// sufficient to simply always flush upon Start().
void AlsaPcmOutputStream::Flush() {}

void AlsaPcmOutputStream::SetVolume(double volume) {}

void AlsaPcmOutputStream::GetVolume(double* volume) {}

void AlsaPcmOutputStream::SetTickClockForTesting(
    const base::TickClock* tick_clock) {}

void AlsaPcmOutputStream::BufferPacket(bool* source_exhausted) {}

void AlsaPcmOutputStream::WritePacket() {}

void AlsaPcmOutputStream::WriteTask() {}

void AlsaPcmOutputStream::ScheduleNextWrite(bool source_exhausted) {}

std::string AlsaPcmOutputStream::FindDeviceForChannels(uint32_t channels) {}

snd_pcm_sframes_t AlsaPcmOutputStream::GetCurrentDelay() {}

snd_pcm_sframes_t AlsaPcmOutputStream::GetAvailableFrames() {}

snd_pcm_t* AlsaPcmOutputStream::AutoSelectDevice(unsigned int latency) {}

bool AlsaPcmOutputStream::CanTransitionTo(InternalState to) {}

AlsaPcmOutputStream::InternalState
AlsaPcmOutputStream::TransitionTo(InternalState to) {}

AlsaPcmOutputStream::InternalState AlsaPcmOutputStream::state() {}

int AlsaPcmOutputStream::RunDataCallback(base::TimeDelta delay,
                                         base::TimeTicks delay_timestamp,
                                         AudioBus* audio_bus) {}

void AlsaPcmOutputStream::RunErrorCallback(int code) {}

// Changes the AudioSourceCallback to proxy calls to.  Pass in nullptr to
// release ownership of the currently registered callback.
void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) {}

}  // namespace media