cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / media / audio / linux / alsa_util.cc
blob176ef6977419ae3ebd55a37f78e1f6b5094a70ad
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/audio/linux/alsa_util.h"
7 #include <string>
9 #include "base/logging.h"
10 #include "media/audio/linux/alsa_wrapper.h"
12 namespace alsa_util {
14 static snd_pcm_t* OpenDevice(media::AlsaWrapper* wrapper,
15 const char* device_name,
16 snd_pcm_stream_t type,
17 int channels,
18 int sample_rate,
19 snd_pcm_format_t pcm_format,
20 int latency_us) {
21 snd_pcm_t* handle = NULL;
22 int error = wrapper->PcmOpen(&handle, device_name, type, SND_PCM_NONBLOCK);
23 if (error < 0) {
24 LOG(WARNING) << "PcmOpen: " << device_name << ","
25 << wrapper->StrError(error);
26 return NULL;
29 error = wrapper->PcmSetParams(handle, pcm_format,
30 SND_PCM_ACCESS_RW_INTERLEAVED, channels,
31 sample_rate, 1, latency_us);
32 if (error < 0) {
33 LOG(WARNING) << "PcmSetParams: " << device_name << ", "
34 << wrapper->StrError(error) << " - Format: " << pcm_format
35 << " Channels: " << channels << " Latency: " << latency_us;
36 if (alsa_util::CloseDevice(wrapper, handle) < 0) {
37 // TODO(ajwong): Retry on certain errors?
38 LOG(WARNING) << "Unable to close audio device. Leaking handle.";
40 return NULL;
43 return handle;
46 static std::string DeviceNameToControlName(const std::string& device_name) {
47 const char kMixerPrefix[] = "hw";
48 std::string control_name;
49 size_t pos1 = device_name.find(':');
50 if (pos1 == std::string::npos) {
51 control_name = device_name;
52 } else {
53 // Examples:
54 // deviceName: "front:CARD=Intel,DEV=0", controlName: "hw:CARD=Intel".
55 // deviceName: "default:CARD=Intel", controlName: "CARD=Intel".
56 size_t pos2 = device_name.find(',');
57 control_name = (pos2 == std::string::npos) ?
58 device_name.substr(pos1) :
59 kMixerPrefix + device_name.substr(pos1, pos2 - pos1);
62 return control_name;
65 snd_pcm_format_t BitsToFormat(int bits_per_sample) {
66 switch (bits_per_sample) {
67 case 8:
68 return SND_PCM_FORMAT_U8;
70 case 16:
71 return SND_PCM_FORMAT_S16;
73 case 24:
74 return SND_PCM_FORMAT_S24;
76 case 32:
77 return SND_PCM_FORMAT_S32;
79 default:
80 return SND_PCM_FORMAT_UNKNOWN;
84 int CloseDevice(media::AlsaWrapper* wrapper, snd_pcm_t* handle) {
85 std::string device_name = wrapper->PcmName(handle);
86 int error = wrapper->PcmClose(handle);
87 if (error < 0) {
88 LOG(ERROR) << "PcmClose: " << device_name << ", "
89 << wrapper->StrError(error);
92 return error;
95 snd_pcm_t* OpenCaptureDevice(media::AlsaWrapper* wrapper,
96 const char* device_name,
97 int channels,
98 int sample_rate,
99 snd_pcm_format_t pcm_format,
100 int latency_us) {
101 return OpenDevice(wrapper, device_name, SND_PCM_STREAM_CAPTURE, channels,
102 sample_rate, pcm_format, latency_us);
105 snd_pcm_t* OpenPlaybackDevice(media::AlsaWrapper* wrapper,
106 const char* device_name,
107 int channels,
108 int sample_rate,
109 snd_pcm_format_t pcm_format,
110 int latency_us) {
111 return OpenDevice(wrapper, device_name, SND_PCM_STREAM_PLAYBACK, channels,
112 sample_rate, pcm_format, latency_us);
115 snd_mixer_t* OpenMixer(media::AlsaWrapper* wrapper,
116 const std::string& device_name) {
117 snd_mixer_t* mixer = NULL;
119 int error = wrapper->MixerOpen(&mixer, 0);
120 if (error < 0) {
121 LOG(ERROR) << "MixerOpen: " << device_name << ", "
122 << wrapper->StrError(error);
123 return NULL;
126 std::string control_name = DeviceNameToControlName(device_name);
127 error = wrapper->MixerAttach(mixer, control_name.c_str());
128 if (error < 0) {
129 LOG(ERROR) << "MixerAttach, " << control_name << ", "
130 << wrapper->StrError(error);
131 alsa_util::CloseMixer(wrapper, mixer, device_name);
132 return NULL;
135 error = wrapper->MixerElementRegister(mixer, NULL, NULL);
136 if (error < 0) {
137 LOG(ERROR) << "MixerElementRegister: " << control_name << ", "
138 << wrapper->StrError(error);
139 alsa_util::CloseMixer(wrapper, mixer, device_name);
140 return NULL;
143 return mixer;
146 void CloseMixer(media::AlsaWrapper* wrapper, snd_mixer_t* mixer,
147 const std::string& device_name) {
148 if (!mixer)
149 return;
151 wrapper->MixerFree(mixer);
153 int error = 0;
154 if (!device_name.empty()) {
155 std::string control_name = DeviceNameToControlName(device_name);
156 error = wrapper->MixerDetach(mixer, control_name.c_str());
157 if (error < 0) {
158 LOG(WARNING) << "MixerDetach: " << control_name << ", "
159 << wrapper->StrError(error);
163 error = wrapper->MixerClose(mixer);
164 if (error < 0) {
165 LOG(WARNING) << "MixerClose: " << wrapper->StrError(error);
169 snd_mixer_elem_t* LoadCaptureMixerElement(media::AlsaWrapper* wrapper,
170 snd_mixer_t* mixer) {
171 if (!mixer)
172 return NULL;
174 int error = wrapper->MixerLoad(mixer);
175 if (error < 0) {
176 LOG(ERROR) << "MixerLoad: " << wrapper->StrError(error);
177 return NULL;
180 snd_mixer_elem_t* elem = NULL;
181 snd_mixer_elem_t* mic_elem = NULL;
182 const char kCaptureElemName[] = "Capture";
183 const char kMicElemName[] = "Mic";
184 for (elem = wrapper->MixerFirstElem(mixer);
185 elem;
186 elem = wrapper->MixerNextElem(elem)) {
187 if (wrapper->MixerSelemIsActive(elem)) {
188 const char* elem_name = wrapper->MixerSelemName(elem);
189 if (strcmp(elem_name, kCaptureElemName) == 0)
190 return elem;
191 else if (strcmp(elem_name, kMicElemName) == 0)
192 mic_elem = elem;
196 // Did not find any Capture handle, use the Mic handle.
197 return mic_elem;
200 } // namespace alsa_util