Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(81)

Unified Diff: webrtc/sound/alsasoundsystem.cc

Issue 1715043002: Remove webrtc/sound/ subdir. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@remove_devicemanager
Patch Set: rebase Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « webrtc/sound/alsasoundsystem.h ('k') | webrtc/sound/alsasymboltable.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/sound/alsasoundsystem.cc
diff --git a/webrtc/sound/alsasoundsystem.cc b/webrtc/sound/alsasoundsystem.cc
deleted file mode 100644
index 696ff1e45059aa00857a2a35705f2f7665916545..0000000000000000000000000000000000000000
--- a/webrtc/sound/alsasoundsystem.cc
+++ /dev/null
@@ -1,741 +0,0 @@
-/*
- * Copyright 2004 The WebRTC Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/sound/alsasoundsystem.h"
-
-#include <algorithm>
-#include <string>
-
-#include "webrtc/base/arraysize.h"
-#include "webrtc/base/common.h"
-#include "webrtc/base/logging.h"
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/base/stringutils.h"
-#include "webrtc/base/timeutils.h"
-#include "webrtc/base/worker.h"
-#include "webrtc/sound/sounddevicelocator.h"
-#include "webrtc/sound/soundinputstreaminterface.h"
-#include "webrtc/sound/soundoutputstreaminterface.h"
-
-namespace rtc {
-
-// Lookup table from the rtc format enum in soundsysteminterface.h to
-// ALSA's enums.
-static const snd_pcm_format_t kCricketFormatToAlsaFormatTable[] = {
- // The order here must match the order in soundsysteminterface.h
- SND_PCM_FORMAT_S16_LE,
-};
-
-// Lookup table for the size of a single sample of a given format.
-static const size_t kCricketFormatToSampleSizeTable[] = {
- // The order here must match the order in soundsysteminterface.h
- sizeof(int16_t), // 2
-};
-
-// Minimum latency we allow, in microseconds. This is more or less arbitrary,
-// but it has to be at least large enough to be able to buffer data during a
-// missed context switch, and the typical Linux scheduling quantum is 10ms.
-static const int kMinimumLatencyUsecs = 20 * 1000;
-
-// The latency we'll use for kNoLatencyRequirements (chosen arbitrarily).
-static const int kDefaultLatencyUsecs = kMinimumLatencyUsecs * 2;
-
-// We translate newlines in ALSA device descriptions to hyphens.
-static const char kAlsaDescriptionSearch[] = "\n";
-static const char kAlsaDescriptionReplace[] = " - ";
-
-class AlsaDeviceLocator : public SoundDeviceLocator {
- public:
- AlsaDeviceLocator(const std::string &name,
- const std::string &device_name)
- : SoundDeviceLocator(name, device_name) {
- // The ALSA descriptions have newlines in them, which won't show up in
- // a drop-down box. Replace them with hyphens.
- rtc::replace_substrs(kAlsaDescriptionSearch,
- sizeof(kAlsaDescriptionSearch) - 1,
- kAlsaDescriptionReplace,
- sizeof(kAlsaDescriptionReplace) - 1,
- &name_);
- }
-
- SoundDeviceLocator *Copy() const override {
- return new AlsaDeviceLocator(*this);
- }
-};
-
-// Functionality that is common to both AlsaInputStream and AlsaOutputStream.
-class AlsaStream {
- public:
- AlsaStream(AlsaSoundSystem *alsa,
- snd_pcm_t *handle,
- size_t frame_size,
- int wait_timeout_ms,
- int flags,
- int freq)
- : alsa_(alsa),
- handle_(handle),
- frame_size_(frame_size),
- wait_timeout_ms_(wait_timeout_ms),
- flags_(flags),
- freq_(freq) {
- }
-
- ~AlsaStream() {
- Close();
- }
-
- // Waits for the stream to be ready to accept/return more data, and returns
- // how much can be written/read, or 0 if we need to Wait() again.
- snd_pcm_uframes_t Wait() {
- snd_pcm_sframes_t frames;
- // Ideally we would not use snd_pcm_wait() and instead hook snd_pcm_poll_*
- // into PhysicalSocketServer, but PhysicalSocketServer is nasty enough
- // already and the current clients of SoundSystemInterface do not run
- // anything else on their worker threads, so snd_pcm_wait() is good enough.
- frames = symbol_table()->snd_pcm_avail_update()(handle_);
- if (frames < 0) {
- LOG(LS_ERROR) << "snd_pcm_avail_update(): " << GetError(frames);
- Recover(frames);
- return 0;
- } else if (frames > 0) {
- // Already ready, so no need to wait.
- return frames;
- }
- // Else no space/data available, so must wait.
- int ready = symbol_table()->snd_pcm_wait()(handle_, wait_timeout_ms_);
- if (ready < 0) {
- LOG(LS_ERROR) << "snd_pcm_wait(): " << GetError(ready);
- Recover(ready);
- return 0;
- } else if (ready == 0) {
- // Timeout, so nothing can be written/read right now.
- // We set the timeout to twice the requested latency, so continuous
- // timeouts are indicative of a problem, so log as a warning.
- LOG(LS_WARNING) << "Timeout while waiting on stream";
- return 0;
- }
- // Else ready > 0 (i.e., 1), so it's ready. Get count.
- frames = symbol_table()->snd_pcm_avail_update()(handle_);
- if (frames < 0) {
- LOG(LS_ERROR) << "snd_pcm_avail_update(): " << GetError(frames);
- Recover(frames);
- return 0;
- } else if (frames == 0) {
- // wait() said we were ready, so this ought to have been positive. Has
- // been observed to happen in practice though.
- LOG(LS_WARNING) << "Spurious wake-up";
- }
- return frames;
- }
-
- int CurrentDelayUsecs() {
- if (!(flags_ & SoundSystemInterface::FLAG_REPORT_LATENCY)) {
- return 0;
- }
-
- snd_pcm_sframes_t delay;
- int err = symbol_table()->snd_pcm_delay()(handle_, &delay);
- if (err != 0) {
- LOG(LS_ERROR) << "snd_pcm_delay(): " << GetError(err);
- Recover(err);
- // We'd rather continue playout/capture with an incorrect delay than stop
- // it altogether, so return a valid value.
- return 0;
- }
- // The delay is in frames. Convert to microseconds.
- return delay * rtc::kNumMicrosecsPerSec / freq_;
- }
-
- // Used to recover from certain recoverable errors, principally buffer overrun
- // or underrun (identified as EPIPE). Without calling this the stream stays
- // in the error state forever.
- bool Recover(int error) {
- int err;
- err = symbol_table()->snd_pcm_recover()(
- handle_,
- error,
- // Silent; i.e., no logging on stderr.
- 1);
- if (err != 0) {
- // Docs say snd_pcm_recover returns the original error if it is not one
- // of the recoverable ones, so this log message will probably contain the
- // same error twice.
- LOG(LS_ERROR) << "Unable to recover from \"" << GetError(error) << "\": "
- << GetError(err);
- return false;
- }
- if (error == -EPIPE && // Buffer underrun/overrun.
- symbol_table()->snd_pcm_stream()(handle_) == SND_PCM_STREAM_CAPTURE) {
- // For capture streams we also have to repeat the explicit start() to get
- // data flowing again.
- err = symbol_table()->snd_pcm_start()(handle_);
- if (err != 0) {
- LOG(LS_ERROR) << "snd_pcm_start(): " << GetError(err);
- return false;
- }
- }
- return true;
- }
-
- bool Close() {
- if (handle_) {
- int err;
- err = symbol_table()->snd_pcm_drop()(handle_);
- if (err != 0) {
- LOG(LS_ERROR) << "snd_pcm_drop(): " << GetError(err);
- // Continue anyways.
- }
- err = symbol_table()->snd_pcm_close()(handle_);
- if (err != 0) {
- LOG(LS_ERROR) << "snd_pcm_close(): " << GetError(err);
- // Continue anyways.
- }
- handle_ = NULL;
- }
- return true;
- }
-
- AlsaSymbolTable *symbol_table() {
- return &alsa_->symbol_table_;
- }
-
- snd_pcm_t *handle() {
- return handle_;
- }
-
- const char *GetError(int err) {
- return alsa_->GetError(err);
- }
-
- size_t frame_size() {
- return frame_size_;
- }
-
- private:
- AlsaSoundSystem *alsa_;
- snd_pcm_t *handle_;
- size_t frame_size_;
- int wait_timeout_ms_;
- int flags_;
- int freq_;
-
- RTC_DISALLOW_COPY_AND_ASSIGN(AlsaStream);
-};
-
-// Implementation of an input stream. See soundinputstreaminterface.h regarding
-// thread-safety.
-class AlsaInputStream :
- public SoundInputStreamInterface,
- private rtc::Worker {
- public:
- AlsaInputStream(AlsaSoundSystem *alsa,
- snd_pcm_t *handle,
- size_t frame_size,
- int wait_timeout_ms,
- int flags,
- int freq)
- : stream_(alsa, handle, frame_size, wait_timeout_ms, flags, freq),
- buffer_size_(0) {
- }
-
- ~AlsaInputStream() override {
- bool success = StopReading();
- // We need that to live.
- VERIFY(success);
- }
-
- bool StartReading() override {
- return StartWork();
- }
-
- bool StopReading() override {
- return StopWork();
- }
-
- bool GetVolume(int *volume) override {
- // TODO(henrika): Implement this.
- return false;
- }
-
- bool SetVolume(int volume) override {
- // TODO(henrika): Implement this.
- return false;
- }
-
- bool Close() override {
- return StopReading() && stream_.Close();
- }
-
- int LatencyUsecs() override {
- return stream_.CurrentDelayUsecs();
- }
-
- private:
- // Inherited from Worker.
- void OnStart() override {
- HaveWork();
- }
-
- // Inherited from Worker.
- void OnHaveWork() override {
- // Block waiting for data.
- snd_pcm_uframes_t avail = stream_.Wait();
- if (avail > 0) {
- // Data is available.
- size_t size = avail * stream_.frame_size();
- if (size > buffer_size_) {
- // Must increase buffer size.
- buffer_.reset(new char[size]);
- buffer_size_ = size;
- }
- // Read all the data.
- snd_pcm_sframes_t read = stream_.symbol_table()->snd_pcm_readi()(
- stream_.handle(),
- buffer_.get(),
- avail);
- if (read < 0) {
- LOG(LS_ERROR) << "snd_pcm_readi(): " << GetError(read);
- stream_.Recover(read);
- } else if (read == 0) {
- // Docs say this shouldn't happen.
- ASSERT(false);
- LOG(LS_ERROR) << "No data?";
- } else {
- // Got data. Pass it off to the app.
- SignalSamplesRead(buffer_.get(),
- read * stream_.frame_size(),
- this);
- }
- }
- // Check for more data with no delay, after any pending messages are
- // dispatched.
- HaveWork();
- }
-
- // Inherited from Worker.
- void OnStop() override {
- // Nothing to do.
- }
-
- const char *GetError(int err) {
- return stream_.GetError(err);
- }
-
- AlsaStream stream_;
- rtc::scoped_ptr<char[]> buffer_;
- size_t buffer_size_;
-
- RTC_DISALLOW_COPY_AND_ASSIGN(AlsaInputStream);
-};
-
-// Implementation of an output stream. See soundoutputstreaminterface.h
-// regarding thread-safety.
-class AlsaOutputStream : public SoundOutputStreamInterface,
- private rtc::Worker {
- public:
- AlsaOutputStream(AlsaSoundSystem *alsa,
- snd_pcm_t *handle,
- size_t frame_size,
- int wait_timeout_ms,
- int flags,
- int freq)
- : stream_(alsa, handle, frame_size, wait_timeout_ms, flags, freq) {
- }
-
- ~AlsaOutputStream() override {
- bool success = DisableBufferMonitoring();
- // We need that to live.
- VERIFY(success);
- }
-
- bool EnableBufferMonitoring() override {
- return StartWork();
- }
-
- bool DisableBufferMonitoring() override {
- return StopWork();
- }
-
- bool WriteSamples(const void *sample_data, size_t size) override {
- if (size % stream_.frame_size() != 0) {
- // No client of SoundSystemInterface does this, so let's not support it.
- // (If we wanted to support it, we'd basically just buffer the fractional
- // frame until we get more data.)
- ASSERT(false);
- LOG(LS_ERROR) << "Writes with fractional frames are not supported";
- return false;
- }
- snd_pcm_uframes_t frames = size / stream_.frame_size();
- snd_pcm_sframes_t written = stream_.symbol_table()->snd_pcm_writei()(
- stream_.handle(),
- sample_data,
- frames);
- if (written < 0) {
- LOG(LS_ERROR) << "snd_pcm_writei(): " << GetError(written);
- stream_.Recover(written);
- return false;
- } else if (static_cast<snd_pcm_uframes_t>(written) < frames) {
- // Shouldn't happen. Drop the rest of the data.
- LOG(LS_ERROR) << "Stream wrote only " << written << " of " << frames
- << " frames!";
- return false;
- }
- return true;
- }
-
- bool GetVolume(int *volume) override {
- // TODO(henrika): Implement this.
- return false;
- }
-
- bool SetVolume(int volume) override {
- // TODO(henrika): Implement this.
- return false;
- }
-
- bool Close() override {
- return DisableBufferMonitoring() && stream_.Close();
- }
-
- int LatencyUsecs() override {
- return stream_.CurrentDelayUsecs();
- }
-
- private:
- // Inherited from Worker.
- void OnStart() override {
- HaveWork();
- }
-
- // Inherited from Worker.
- void OnHaveWork() override {
- snd_pcm_uframes_t avail = stream_.Wait();
- if (avail > 0) {
- size_t space = avail * stream_.frame_size();
- SignalBufferSpace(space, this);
- }
- HaveWork();
- }
-
- // Inherited from Worker.
- void OnStop() override {
- // Nothing to do.
- }
-
- const char *GetError(int err) {
- return stream_.GetError(err);
- }
-
- AlsaStream stream_;
-
- RTC_DISALLOW_COPY_AND_ASSIGN(AlsaOutputStream);
-};
-
-AlsaSoundSystem::AlsaSoundSystem() : initialized_(false) {}
-
-AlsaSoundSystem::~AlsaSoundSystem() {
- // Not really necessary, because Terminate() doesn't really do anything.
- Terminate();
-}
-
-bool AlsaSoundSystem::Init() {
- if (IsInitialized()) {
- return true;
- }
-
- // Load libasound.
- if (!symbol_table_.Load()) {
- // Very odd for a Linux machine to not have a working libasound ...
- LOG(LS_ERROR) << "Failed to load symbol table";
- return false;
- }
-
- initialized_ = true;
-
- return true;
-}
-
-void AlsaSoundSystem::Terminate() {
- if (!IsInitialized()) {
- return;
- }
-
- initialized_ = false;
-
- // We do not unload the symbol table because we may need it again soon if
- // Init() is called again.
-}
-
-bool AlsaSoundSystem::EnumeratePlaybackDevices(
- SoundDeviceLocatorList *devices) {
- return EnumerateDevices(devices, false);
-}
-
-bool AlsaSoundSystem::EnumerateCaptureDevices(
- SoundDeviceLocatorList *devices) {
- return EnumerateDevices(devices, true);
-}
-
-bool AlsaSoundSystem::GetDefaultPlaybackDevice(SoundDeviceLocator **device) {
- return GetDefaultDevice(device);
-}
-
-bool AlsaSoundSystem::GetDefaultCaptureDevice(SoundDeviceLocator **device) {
- return GetDefaultDevice(device);
-}
-
-SoundOutputStreamInterface *AlsaSoundSystem::OpenPlaybackDevice(
- const SoundDeviceLocator *device,
- const OpenParams &params) {
- return OpenDevice<SoundOutputStreamInterface>(
- device,
- params,
- SND_PCM_STREAM_PLAYBACK,
- &AlsaSoundSystem::StartOutputStream);
-}
-
-SoundInputStreamInterface *AlsaSoundSystem::OpenCaptureDevice(
- const SoundDeviceLocator *device,
- const OpenParams &params) {
- return OpenDevice<SoundInputStreamInterface>(
- device,
- params,
- SND_PCM_STREAM_CAPTURE,
- &AlsaSoundSystem::StartInputStream);
-}
-
-const char *AlsaSoundSystem::GetName() const {
- return "ALSA";
-}
-
-bool AlsaSoundSystem::EnumerateDevices(
- SoundDeviceLocatorList *devices,
- bool capture_not_playback) {
- ClearSoundDeviceLocatorList(devices);
-
- if (!IsInitialized()) {
- return false;
- }
-
- const char *type = capture_not_playback ? "Input" : "Output";
- // dmix and dsnoop are only for playback and capture, respectively, but ALSA
- // stupidly includes them in both lists.
- const char *ignore_prefix = capture_not_playback ? "dmix:" : "dsnoop:";
- // (ALSA lists many more "devices" of questionable interest, but we show them
- // just in case the weird devices may actually be desirable for some
- // users/systems.)
- const char *ignore_default = "default";
- const char *ignore_null = "null";
- const char *ignore_pulse = "pulse";
- // The 'pulse' entry has a habit of mysteriously disappearing when you query
- // a second time. Remove it from our list. (GIPS lib did the same thing.)
- int err;
-
- void **hints;
- err = symbol_table_.snd_device_name_hint()(-1, // All cards
- "pcm", // Only PCM devices
- &hints);
- if (err != 0) {
- LOG(LS_ERROR) << "snd_device_name_hint(): " << GetError(err);
- return false;
- }
-
- for (void **list = hints; *list != NULL; ++list) {
- char *actual_type = symbol_table_.snd_device_name_get_hint()(*list, "IOID");
- if (actual_type) { // NULL means it's both.
- bool wrong_type = (strcmp(actual_type, type) != 0);
- free(actual_type);
- if (wrong_type) {
- // Wrong type of device (i.e., input vs. output).
- continue;
- }
- }
-
- char *name = symbol_table_.snd_device_name_get_hint()(*list, "NAME");
- if (!name) {
- LOG(LS_ERROR) << "Device has no name???";
- // Skip it.
- continue;
- }
-
- // Now check if we actually want to show this device.
- if (strcmp(name, ignore_default) != 0 &&
- strcmp(name, ignore_null) != 0 &&
- strcmp(name, ignore_pulse) != 0 &&
- !rtc::starts_with(name, ignore_prefix)) {
- // Yes, we do.
- char *desc = symbol_table_.snd_device_name_get_hint()(*list, "DESC");
- if (!desc) {
- // Virtual devices don't necessarily have descriptions. Use their names
- // instead (not pretty!).
- desc = name;
- }
-
- AlsaDeviceLocator *device = new AlsaDeviceLocator(desc, name);
-
- devices->push_back(device);
-
- if (desc != name) {
- free(desc);
- }
- }
-
- free(name);
- }
-
- err = symbol_table_.snd_device_name_free_hint()(hints);
- if (err != 0) {
- LOG(LS_ERROR) << "snd_device_name_free_hint(): " << GetError(err);
- // Continue and return true anyways, since we did get the whole list.
- }
-
- return true;
-}
-
-bool AlsaSoundSystem::GetDefaultDevice(SoundDeviceLocator **device) {
- if (!IsInitialized()) {
- return false;
- }
- *device = new AlsaDeviceLocator("Default device", "default");
- return true;
-}
-
-inline size_t AlsaSoundSystem::FrameSize(const OpenParams &params) {
- return kCricketFormatToSampleSizeTable[params.format] * params.channels;
-}
-
-template <typename StreamInterface>
-StreamInterface *AlsaSoundSystem::OpenDevice(
- const SoundDeviceLocator *device,
- const OpenParams &params,
- snd_pcm_stream_t type,
- StreamInterface *(AlsaSoundSystem::*start_fn)(
- snd_pcm_t *handle,
- size_t frame_size,
- int wait_timeout_ms,
- int flags,
- int freq)) {
- if (!IsInitialized()) {
- return NULL;
- }
-
- StreamInterface *stream;
- int err;
-
- const char *dev = static_cast<const AlsaDeviceLocator *>(device)->
- device_name().c_str();
-
- snd_pcm_t *handle = NULL;
- err = symbol_table_.snd_pcm_open()(
- &handle,
- dev,
- type,
- // No flags.
- 0);
- if (err != 0) {
- LOG(LS_ERROR) << "snd_pcm_open(" << dev << "): " << GetError(err);
- return NULL;
- }
- LOG(LS_VERBOSE) << "Opening " << dev;
- ASSERT(handle); // If open succeeded, handle ought to be valid
-
- // Compute requested latency in microseconds.
- int latency;
- if (params.latency == kNoLatencyRequirements) {
- latency = kDefaultLatencyUsecs;
- } else {
- // kLowLatency is 0, so we treat it the same as a request for zero latency.
- // Compute what the user asked for.
- latency = rtc::kNumMicrosecsPerSec *
- params.latency /
- params.freq /
- FrameSize(params);
- // And this is what we'll actually use.
- latency = std::max(latency, kMinimumLatencyUsecs);
- }
-
- ASSERT(params.format < arraysize(kCricketFormatToAlsaFormatTable));
-
- err = symbol_table_.snd_pcm_set_params()(
- handle,
- kCricketFormatToAlsaFormatTable[params.format],
- // SoundSystemInterface only supports interleaved audio.
- SND_PCM_ACCESS_RW_INTERLEAVED,
- params.channels,
- params.freq,
- 1, // Allow ALSA to resample.
- latency);
- if (err != 0) {
- LOG(LS_ERROR) << "snd_pcm_set_params(): " << GetError(err);
- goto fail;
- }
-
- err = symbol_table_.snd_pcm_prepare()(handle);
- if (err != 0) {
- LOG(LS_ERROR) << "snd_pcm_prepare(): " << GetError(err);
- goto fail;
- }
-
- stream = (this->*start_fn)(
- handle,
- FrameSize(params),
- // We set the wait time to twice the requested latency, so that wait
- // timeouts should be rare.
- 2 * latency / rtc::kNumMicrosecsPerMillisec,
- params.flags,
- params.freq);
- if (stream) {
- return stream;
- }
- // Else fall through.
-
- fail:
- err = symbol_table_.snd_pcm_close()(handle);
- if (err != 0) {
- LOG(LS_ERROR) << "snd_pcm_close(): " << GetError(err);
- }
- return NULL;
-}
-
-SoundOutputStreamInterface *AlsaSoundSystem::StartOutputStream(
- snd_pcm_t *handle,
- size_t frame_size,
- int wait_timeout_ms,
- int flags,
- int freq) {
- // Nothing to do here but instantiate the stream.
- return new AlsaOutputStream(
- this, handle, frame_size, wait_timeout_ms, flags, freq);
-}
-
-SoundInputStreamInterface *AlsaSoundSystem::StartInputStream(
- snd_pcm_t *handle,
- size_t frame_size,
- int wait_timeout_ms,
- int flags,
- int freq) {
- // Output streams start automatically once enough data has been written, but
- // input streams must be started manually or else snd_pcm_wait() will never
- // return true.
- int err;
- err = symbol_table_.snd_pcm_start()(handle);
- if (err != 0) {
- LOG(LS_ERROR) << "snd_pcm_start(): " << GetError(err);
- return NULL;
- }
- return new AlsaInputStream(
- this, handle, frame_size, wait_timeout_ms, flags, freq);
-}
-
-inline const char *AlsaSoundSystem::GetError(int err) {
- return symbol_table_.snd_strerror()(err);
-}
-
-} // namespace rtc
« no previous file with comments | « webrtc/sound/alsasoundsystem.h ('k') | webrtc/sound/alsasymboltable.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698