summaryrefslogtreecommitdiffstats
path: root/media/audio/alsa/alsa_util.cc
diff options
context:
space:
mode:
authorspang@chromium.org <spang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-28 06:00:33 +0000
committerspang@chromium.org <spang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-28 06:00:33 +0000
commit8117a12e805a3243141cf3c7cb0f2cdd0538b47f (patch)
tree77ca52f1d5086608d87064fa4e500d793b528fb5 /media/audio/alsa/alsa_util.cc
parent0a72447fb90b7d8ab0ab07119098a46ba84f0c86 (diff)
downloadchromium_src-8117a12e805a3243141cf3c7cb0f2cdd0538b47f.zip
chromium_src-8117a12e805a3243141cf3c7cb0f2cdd0538b47f.tar.gz
chromium_src-8117a12e805a3243141cf3c7cb0f2cdd0538b47f.tar.bz2
Support use_alsa==0 on Linux
This moves the ALSA audio code from media/audio/linux to media/audio/alsa and splits Linux's CreateAudioManager() into a new file. This function chooses which AudioManager subclass to use on Linux. When use_alsa==0 on Linux, the fallback audio manager is changed from ALSA to a new fake implementation that always has an empty set of devices and will only return fake streams. This allows us to compile with no audio support on Linux. In particular, we can compile for targets that don't have the ALSA libraries available. Obviously, it's not (yet) possible to play audio in this configuration. BUG=318315, 318413 Review URL: https://codereview.chromium.org/89793003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@237696 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/audio/alsa/alsa_util.cc')
-rw-r--r--media/audio/alsa/alsa_util.cc200
1 files changed, 200 insertions, 0 deletions
diff --git a/media/audio/alsa/alsa_util.cc b/media/audio/alsa/alsa_util.cc
new file mode 100644
index 0000000..f26cbd3
--- /dev/null
+++ b/media/audio/alsa/alsa_util.cc
@@ -0,0 +1,200 @@
+// Copyright 2013 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/alsa/alsa_util.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "media/audio/alsa/alsa_wrapper.h"
+
+namespace alsa_util {
+
+static snd_pcm_t* OpenDevice(media::AlsaWrapper* wrapper,
+ const char* device_name,
+ snd_pcm_stream_t type,
+ int channels,
+ int sample_rate,
+ snd_pcm_format_t pcm_format,
+ int latency_us) {
+ snd_pcm_t* handle = NULL;
+ int error = wrapper->PcmOpen(&handle, device_name, type, SND_PCM_NONBLOCK);
+ if (error < 0) {
+ LOG(WARNING) << "PcmOpen: " << device_name << ","
+ << wrapper->StrError(error);
+ return NULL;
+ }
+
+ error = wrapper->PcmSetParams(handle, pcm_format,
+ SND_PCM_ACCESS_RW_INTERLEAVED, channels,
+ sample_rate, 1, latency_us);
+ if (error < 0) {
+ LOG(WARNING) << "PcmSetParams: " << device_name << ", "
+ << wrapper->StrError(error) << " - Format: " << pcm_format
+ << " Channels: " << channels << " Latency: " << latency_us;
+ if (alsa_util::CloseDevice(wrapper, handle) < 0) {
+ // TODO(ajwong): Retry on certain errors?
+ LOG(WARNING) << "Unable to close audio device. Leaking handle.";
+ }
+ return NULL;
+ }
+
+ return handle;
+}
+
+static std::string DeviceNameToControlName(const std::string& device_name) {
+ const char kMixerPrefix[] = "hw";
+ std::string control_name;
+ size_t pos1 = device_name.find(':');
+ if (pos1 == std::string::npos) {
+ control_name = device_name;
+ } else {
+ // Examples:
+ // deviceName: "front:CARD=Intel,DEV=0", controlName: "hw:CARD=Intel".
+ // deviceName: "default:CARD=Intel", controlName: "CARD=Intel".
+ size_t pos2 = device_name.find(',');
+ control_name = (pos2 == std::string::npos) ?
+ device_name.substr(pos1) :
+ kMixerPrefix + device_name.substr(pos1, pos2 - pos1);
+ }
+
+ return control_name;
+}
+
+snd_pcm_format_t BitsToFormat(int bits_per_sample) {
+ switch (bits_per_sample) {
+ case 8:
+ return SND_PCM_FORMAT_U8;
+
+ case 16:
+ return SND_PCM_FORMAT_S16;
+
+ case 24:
+ return SND_PCM_FORMAT_S24;
+
+ case 32:
+ return SND_PCM_FORMAT_S32;
+
+ default:
+ return SND_PCM_FORMAT_UNKNOWN;
+ }
+}
+
+int CloseDevice(media::AlsaWrapper* wrapper, snd_pcm_t* handle) {
+ std::string device_name = wrapper->PcmName(handle);
+ int error = wrapper->PcmClose(handle);
+ if (error < 0) {
+ LOG(ERROR) << "PcmClose: " << device_name << ", "
+ << wrapper->StrError(error);
+ }
+
+ return error;
+}
+
+snd_pcm_t* OpenCaptureDevice(media::AlsaWrapper* wrapper,
+ const char* device_name,
+ int channels,
+ int sample_rate,
+ snd_pcm_format_t pcm_format,
+ int latency_us) {
+ return OpenDevice(wrapper, device_name, SND_PCM_STREAM_CAPTURE, channels,
+ sample_rate, pcm_format, latency_us);
+}
+
+snd_pcm_t* OpenPlaybackDevice(media::AlsaWrapper* wrapper,
+ const char* device_name,
+ int channels,
+ int sample_rate,
+ snd_pcm_format_t pcm_format,
+ int latency_us) {
+ return OpenDevice(wrapper, device_name, SND_PCM_STREAM_PLAYBACK, channels,
+ sample_rate, pcm_format, latency_us);
+}
+
+snd_mixer_t* OpenMixer(media::AlsaWrapper* wrapper,
+ const std::string& device_name) {
+ snd_mixer_t* mixer = NULL;
+
+ int error = wrapper->MixerOpen(&mixer, 0);
+ if (error < 0) {
+ LOG(ERROR) << "MixerOpen: " << device_name << ", "
+ << wrapper->StrError(error);
+ return NULL;
+ }
+
+ std::string control_name = DeviceNameToControlName(device_name);
+ error = wrapper->MixerAttach(mixer, control_name.c_str());
+ if (error < 0) {
+ LOG(ERROR) << "MixerAttach, " << control_name << ", "
+ << wrapper->StrError(error);
+ alsa_util::CloseMixer(wrapper, mixer, device_name);
+ return NULL;
+ }
+
+ error = wrapper->MixerElementRegister(mixer, NULL, NULL);
+ if (error < 0) {
+ LOG(ERROR) << "MixerElementRegister: " << control_name << ", "
+ << wrapper->StrError(error);
+ alsa_util::CloseMixer(wrapper, mixer, device_name);
+ return NULL;
+ }
+
+ return mixer;
+}
+
+void CloseMixer(media::AlsaWrapper* wrapper, snd_mixer_t* mixer,
+ const std::string& device_name) {
+ if (!mixer)
+ return;
+
+ wrapper->MixerFree(mixer);
+
+ int error = 0;
+ if (!device_name.empty()) {
+ std::string control_name = DeviceNameToControlName(device_name);
+ error = wrapper->MixerDetach(mixer, control_name.c_str());
+ if (error < 0) {
+ LOG(WARNING) << "MixerDetach: " << control_name << ", "
+ << wrapper->StrError(error);
+ }
+ }
+
+ error = wrapper->MixerClose(mixer);
+ if (error < 0) {
+ LOG(WARNING) << "MixerClose: " << wrapper->StrError(error);
+ }
+}
+
+snd_mixer_elem_t* LoadCaptureMixerElement(media::AlsaWrapper* wrapper,
+ snd_mixer_t* mixer) {
+ if (!mixer)
+ return NULL;
+
+ int error = wrapper->MixerLoad(mixer);
+ if (error < 0) {
+ LOG(ERROR) << "MixerLoad: " << wrapper->StrError(error);
+ return NULL;
+ }
+
+ snd_mixer_elem_t* elem = NULL;
+ snd_mixer_elem_t* mic_elem = NULL;
+ const char kCaptureElemName[] = "Capture";
+ const char kMicElemName[] = "Mic";
+ for (elem = wrapper->MixerFirstElem(mixer);
+ elem;
+ elem = wrapper->MixerNextElem(elem)) {
+ if (wrapper->MixerSelemIsActive(elem)) {
+ const char* elem_name = wrapper->MixerSelemName(elem);
+ if (strcmp(elem_name, kCaptureElemName) == 0)
+ return elem;
+ else if (strcmp(elem_name, kMicElemName) == 0)
+ mic_elem = elem;
+ }
+ }
+
+ // Did not find any Capture handle, use the Mic handle.
+ return mic_elem;
+}
+
+} // namespace alsa_util