15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/linux/audio_manager_linux.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/environment.h" 9a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/files/file_path.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/metrics/histogram.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/nix/xdg_util.h" 13a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/process/launch.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/audio_output_dispatcher.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/audio_parameters.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/audio_util.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(USE_CRAS) 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/cras/audio_manager_cras.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/linux/alsa_input.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/linux/alsa_output.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/linux/alsa_wrapper.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_PULSEAUDIO) 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/pulse/audio_manager_pulse.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/channel_layout.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/limits.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/media_switches.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace media { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum number of output streams that can be open simultaneously. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMaxOutputStreams = 50; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Default sample rate for input and output streams. 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kDefaultSampleRate = 48000; 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Since "default", "pulse" and "dmix" devices are virtual devices mapped to 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// real devices, we remove them from the list to avoiding duplicate counting. 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In addition, note that we support no more than 2 channels for recording, 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// hence surround devices are not stored in the list. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char* kInvalidAudioInputDevices[] = { 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "default", 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "null", 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "pulse", 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "dmix", 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "surround", 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)enum LinuxAudioIO { 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kPulse, 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kAlsa, 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kCras, 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kAudioIOMax // Must always be last! 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioManagerLinux::ShowLinuxAudioInputSettings() { 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<base::Environment> env(base::Environment::Create()); 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CommandLine command_line(CommandLine::NO_PROGRAM); 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (base::nix::GetDesktopEnvironment(env.get())) { 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case base::nix::DESKTOP_ENVIRONMENT_GNOME: 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) command_line.SetProgram(base::FilePath("gnome-volume-control")); 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case base::nix::DESKTOP_ENVIRONMENT_KDE3: 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case base::nix::DESKTOP_ENVIRONMENT_KDE4: 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) command_line.SetProgram(base::FilePath("kmix")); 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case base::nix::DESKTOP_ENVIRONMENT_UNITY: 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) command_line.SetProgram(base::FilePath("gnome-control-center")); 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) command_line.AppendArg("sound"); 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) command_line.AppendArg("input"); 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default: 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Failed to show audio input settings: we don't know " 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << "what command to use for your desktop environment."; 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::LaunchProcess(command_line, base::LaunchOptions(), NULL); 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Implementation of AudioManager. 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AudioManagerLinux::HasAudioOutputDevices() { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return HasAnyAlsaAudioDevice(kStreamPlayback); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AudioManagerLinux::HasAudioInputDevices() { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return HasAnyAlsaAudioDevice(kStreamCapture); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioManagerLinux::AudioManagerLinux() 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : wrapper_(new AlsaWrapper()) { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetMaxOutputStreamsAllowed(kMaxOutputStreams); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioManagerLinux::~AudioManagerLinux() { 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Shutdown(); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioManagerLinux::ShowAudioInputSettings() { 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ShowLinuxAudioInputSettings(); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioManagerLinux::GetAudioInputDeviceNames( 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) media::AudioDeviceNames* device_names) { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(device_names->empty()); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetAlsaAudioInputDevices(device_names); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AudioParameters AudioManagerLinux::GetInputStreamParameters( 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& device_id) { 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static const int kDefaultInputBufferSize = 1024; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return AudioParameters( 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kDefaultSampleRate, 16, kDefaultInputBufferSize); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioManagerLinux::GetAlsaAudioInputDevices( 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) media::AudioDeviceNames* device_names) { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Constants specified by the ALSA API for device hints. 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kPcmInterfaceName[] = "pcm"; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int card = -1; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Loop through the sound cards to get ALSA device hints. 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (!wrapper_->CardNext(&card) && card >= 0) { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void** hints = NULL; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!error) { 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetAlsaDevicesInfo(hints, device_names); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Destroy the hints now that we're done with it. 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wrapper_->DeviceNameFreeHint(hints); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(WARNING) << "GetAudioInputDevices: unable to get device hints: " 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << wrapper_->StrError(error); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioManagerLinux::GetAlsaDevicesInfo( 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void** hints, media::AudioDeviceNames* device_names) { 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kIoHintName[] = "IOID"; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kNameHintName[] = "NAME"; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kDescriptionHintName[] = "DESC"; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kOutputDevice[] = "Output"; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) { 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only examine devices that are input capable. Valid values are 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "Input", "Output", and NULL which means both input and output. 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter, 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kIoHintName)); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (io != NULL && strcmp(kOutputDevice, io.get()) == 0) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Found an input device, prepend the default device since we always want 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // it to be on the top of the list for all platforms. And there is no 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // duplicate counting here since it is only done if the list is still empty. 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note, pulse has exclusively opened the default device, so we must open 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the device via the "default" moniker. 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (device_names->empty()) { 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_names->push_front(media::AudioDeviceName( 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioManagerBase::kDefaultDeviceName, 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioManagerBase::kDefaultDeviceId)); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the unique device name for the device. 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr_malloc<char> unique_device_name( 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName)); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Find out if the device is available. 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsAlsaDeviceAvailable(unique_device_name.get())) { 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the description for the device. 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr_malloc<char> desc(wrapper_->DeviceNameGetHint( 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *hint_iter, kDescriptionHintName)); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) media::AudioDeviceName name; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name.unique_id = unique_device_name.get(); 180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (desc) { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use the more user friendly description as name. 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Replace '\n' with '-'. 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* pret = strchr(desc.get(), '\n'); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pret) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *pret = '-'; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name.device_name = desc.get(); 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Virtual devices don't necessarily have descriptions. 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use their names instead. 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name.device_name = unique_device_name.get(); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Store the device information. 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_names->push_back(name); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AudioManagerLinux::IsAlsaDeviceAvailable(const char* device_name) { 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!device_name) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if the device is in the list of invalid devices. 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < arraysize(kInvalidAudioInputDevices); ++i) { 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (strncmp(kInvalidAudioInputDevices[i], device_name, 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strlen(kInvalidAudioInputDevices[i])) == 0) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AudioManagerLinux::HasAnyAlsaAudioDevice(StreamType stream) { 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kPcmInterfaceName[] = "pcm"; 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kIoHintName[] = "IOID"; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* kNotWantedDevice = 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (stream == kStreamPlayback ? "Input" : "Output"); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void** hints = NULL; 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool has_device = false; 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int card = -1; 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Loop through the sound cards. 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Don't use snd_device_name_hint(-1,..) since there is a access violation 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // inside this ALSA API with libasound.so.2.0.0. 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (!wrapper_->CardNext(&card) && (card >= 0) && !has_device) { 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!error) { 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) { 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only examine devices that are |stream| capable. Valid values are 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "Input", "Output", and NULL which means both input and output. 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter, 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kIoHintName)); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (io != NULL && strcmp(kNotWantedDevice, io.get()) == 0) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; // Wrong type, skip the device. 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Found an input device. 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) has_device = true; 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Destroy the hints now that we're done with it. 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wrapper_->DeviceNameFreeHint(hints); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hints = NULL; 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(WARNING) << "HasAnyAudioDevice: unable to get device hints: " 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << wrapper_->StrError(error); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return has_device; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioOutputStream* AudioManagerLinux::MakeLinearOutputStream( 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AudioParameters& params) { 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return MakeOutputStream(params); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioOutputStream* AudioManagerLinux::MakeLowLatencyOutputStream( 260868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const AudioParameters& params, 261868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const std::string& input_device_id) { 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 263868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // TODO(xians): Use input_device_id for unified IO. 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return MakeOutputStream(params); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputStream* AudioManagerLinux::MakeLinearInputStream( 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AudioParameters& params, const std::string& device_id) { 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return MakeInputStream(params, device_id); 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputStream* AudioManagerLinux::MakeLowLatencyInputStream( 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AudioParameters& params, const std::string& device_id) { 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return MakeInputStream(params, device_id); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AudioParameters AudioManagerLinux::GetPreferredOutputStreamParameters( 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const AudioParameters& input_params) { 281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) static const int kDefaultOutputBufferSize = 2048; 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int sample_rate = kDefaultSampleRate; 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int buffer_size = kDefaultOutputBufferSize; 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int bits_per_sample = 16; 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int input_channels = 0; 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (input_params.IsValid()) { 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Some clients, such as WebRTC, have a more limited use case and work 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // acceptably with a smaller buffer size. The check below allows clients 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // which want to try a smaller buffer size on Linux to do so. 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(dalecurtis): This should include bits per channel and channel layout 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // eventually. 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sample_rate = input_params.sample_rate(); 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bits_per_sample = input_params.bits_per_sample(); 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) channel_layout = input_params.channel_layout(); 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) input_channels = input_params.input_channels(); 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) buffer_size = std::min(input_params.frames_per_buffer(), buffer_size); 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int user_buffer_size = GetUserBufferSize(); 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (user_buffer_size) 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) buffer_size = user_buffer_size; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return AudioParameters( 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sample_rate, bits_per_sample, buffer_size); 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AudioOutputStream* AudioManagerLinux::MakeOutputStream( 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const AudioParameters& params) { 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string device_name = AlsaPcmOutputStream::kAutoSelectDevice; 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CommandLine::ForCurrentProcess()->HasSwitch( 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switches::kAlsaOutputDevice)) { 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_name = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switches::kAlsaOutputDevice); 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new AlsaPcmOutputStream(device_name, params, wrapper_.get(), this); 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputStream* AudioManagerLinux::MakeInputStream( 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AudioParameters& params, const std::string& device_id) { 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string device_name = (device_id == AudioManagerBase::kDefaultDeviceId) ? 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AlsaPcmInputStream::kAutoSelectDevice : device_id; 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAlsaInputDevice)) { 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_name = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switches::kAlsaInputDevice); 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new AlsaPcmInputStream(this, device_name, params, wrapper_.get()); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioManager* CreateAudioManager() { 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(USE_CRAS) 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseCras)) { 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Media.LinuxAudioIO", kCras, kAudioIOMax); 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return new AudioManagerCras(); 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(USE_PULSEAUDIO) 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AudioManager* manager = AudioManagerPulse::Create(); 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (manager) { 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Media.LinuxAudioIO", kPulse, kAudioIOMax); 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return manager; 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Media.LinuxAudioIO", kAlsa, kAudioIOMax); 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return new AudioManagerLinux(); 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace media 353