Delete unused downloads page asset.
[chromium-blink-merge.git] / media / audio / alsa / alsa_util.cc
blobffc3a39d3de80923f8558d034c8433cf6fa254b1
1 // Copyright 2013 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/alsa/alsa_util.h"
8 #include "base/logging.h"
9 #include "media/audio/alsa/alsa_wrapper.h"
11 namespace alsa_util {
13 static snd_pcm_t* OpenDevice(media::AlsaWrapper* wrapper,
14 const char* device_name,
15 snd_pcm_stream_t type,
16 int channels,
17 int sample_rate,
18 snd_pcm_format_t pcm_format,
19 int latency_us) {
20 snd_pcm_t* handle = NULL;
21 int error = wrapper->PcmOpen(&handle, device_name, type, SND_PCM_NONBLOCK);
22 if (error < 0) {
23 LOG(WARNING) << "PcmOpen: " << device_name << ","
24 << wrapper->StrError(error);
25 return NULL;
28 error = wrapper->PcmSetParams(handle, pcm_format,
29 SND_PCM_ACCESS_RW_INTERLEAVED, channels,
30 sample_rate, 1, latency_us);
31 if (error < 0) {
32 LOG(WARNING) << "PcmSetParams: " << device_name << ", "
33 << wrapper->StrError(error) << " - Format: " << pcm_format
34 << " Channels: " << channels << " Latency: " << latency_us;
35 if (alsa_util::CloseDevice(wrapper, handle) < 0) {
36 // TODO(ajwong): Retry on certain errors?
37 LOG(WARNING) << "Unable to close audio device. Leaking handle.";
39 return NULL;
42 return handle;
45 static std::string DeviceNameToControlName(const std::string& device_name) {
46 const char kMixerPrefix[] = "hw";
47 std::string control_name;
48 size_t pos1 = device_name.find(':');
49 if (pos1 == std::string::npos) {
50 control_name = device_name;
51 } else {
52 // Examples:
53 // deviceName: "front:CARD=Intel,DEV=0", controlName: "hw:CARD=Intel".
54 // deviceName: "default:CARD=Intel", controlName: "CARD=Intel".
55 size_t pos2 = device_name.find(',');
56 control_name = (pos2 == std::string::npos) ?
57 device_name.substr(pos1) :
58 kMixerPrefix + device_name.substr(pos1, pos2 - pos1);
61 return control_name;
64 snd_pcm_format_t BitsToFormat(int bits_per_sample) {
65 switch (bits_per_sample) {
66 case 8:
67 return SND_PCM_FORMAT_U8;
69 case 16:
70 return SND_PCM_FORMAT_S16;
72 case 24:
73 return SND_PCM_FORMAT_S24;
75 case 32:
76 return SND_PCM_FORMAT_S32;
78 default:
79 return SND_PCM_FORMAT_UNKNOWN;
83 int CloseDevice(media::AlsaWrapper* wrapper, snd_pcm_t* handle) {
84 std::string device_name = wrapper->PcmName(handle);
85 int error = wrapper->PcmClose(handle);
86 if (error < 0) {
87 LOG(ERROR) << "PcmClose: " << device_name << ", "
88 << wrapper->StrError(error);
91 return error;
94 snd_pcm_t* OpenCaptureDevice(media::AlsaWrapper* wrapper,
95 const char* device_name,
96 int channels,
97 int sample_rate,
98 snd_pcm_format_t pcm_format,
99 int latency_us) {
100 return OpenDevice(wrapper, device_name, SND_PCM_STREAM_CAPTURE, channels,
101 sample_rate, pcm_format, latency_us);
104 snd_pcm_t* OpenPlaybackDevice(media::AlsaWrapper* wrapper,
105 const char* device_name,
106 int channels,
107 int sample_rate,
108 snd_pcm_format_t pcm_format,
109 int latency_us) {
110 return OpenDevice(wrapper, device_name, SND_PCM_STREAM_PLAYBACK, channels,
111 sample_rate, pcm_format, latency_us);
114 snd_mixer_t* OpenMixer(media::AlsaWrapper* wrapper,
115 const std::string& device_name) {
116 snd_mixer_t* mixer = NULL;
118 int error = wrapper->MixerOpen(&mixer, 0);
119 if (error < 0) {
120 LOG(ERROR) << "MixerOpen: " << device_name << ", "
121 << wrapper->StrError(error);
122 return NULL;
125 std::string control_name = DeviceNameToControlName(device_name);
126 error = wrapper->MixerAttach(mixer, control_name.c_str());
127 if (error < 0) {
128 LOG(ERROR) << "MixerAttach, " << control_name << ", "
129 << wrapper->StrError(error);
130 alsa_util::CloseMixer(wrapper, mixer, device_name);
131 return NULL;
134 error = wrapper->MixerElementRegister(mixer, NULL, NULL);
135 if (error < 0) {
136 LOG(ERROR) << "MixerElementRegister: " << control_name << ", "
137 << wrapper->StrError(error);
138 alsa_util::CloseMixer(wrapper, mixer, device_name);
139 return NULL;
142 return mixer;
145 void CloseMixer(media::AlsaWrapper* wrapper, snd_mixer_t* mixer,
146 const std::string& device_name) {
147 if (!mixer)
148 return;
150 wrapper->MixerFree(mixer);
152 int error = 0;
153 if (!device_name.empty()) {
154 std::string control_name = DeviceNameToControlName(device_name);
155 error = wrapper->MixerDetach(mixer, control_name.c_str());
156 if (error < 0) {
157 LOG(WARNING) << "MixerDetach: " << control_name << ", "
158 << wrapper->StrError(error);
162 error = wrapper->MixerClose(mixer);
163 if (error < 0) {
164 LOG(WARNING) << "MixerClose: " << wrapper->StrError(error);
168 snd_mixer_elem_t* LoadCaptureMixerElement(media::AlsaWrapper* wrapper,
169 snd_mixer_t* mixer) {
170 if (!mixer)
171 return NULL;
173 int error = wrapper->MixerLoad(mixer);
174 if (error < 0) {
175 LOG(ERROR) << "MixerLoad: " << wrapper->StrError(error);
176 return NULL;
179 snd_mixer_elem_t* elem = NULL;
180 snd_mixer_elem_t* mic_elem = NULL;
181 const char kCaptureElemName[] = "Capture";
182 const char kMicElemName[] = "Mic";
183 for (elem = wrapper->MixerFirstElem(mixer);
184 elem;
185 elem = wrapper->MixerNextElem(elem)) {
186 if (wrapper->MixerSelemIsActive(elem)) {
187 const char* elem_name = wrapper->MixerSelemName(elem);
188 if (strcmp(elem_name, kCaptureElemName) == 0)
189 return elem;
190 else if (strcmp(elem_name, kMicElemName) == 0)
191 mic_elem = elem;
195 // Did not find any Capture handle, use the Mic handle.
196 return mic_elem;
199 } // namespace alsa_util