Home | History | Annotate | Download | only in pulse
      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.
      4 
      5 #include "media/audio/pulse/audio_manager_pulse.h"
      6 
      7 #include "base/command_line.h"
      8 #include "base/environment.h"
      9 #include "base/files/file_path.h"
     10 #include "base/logging.h"
     11 #include "base/nix/xdg_util.h"
     12 #include "base/stl_util.h"
     13 #include "media/audio/alsa/audio_manager_alsa.h"
     14 #include "media/audio/audio_parameters.h"
     15 #include "media/audio/pulse/pulse_input.h"
     16 #include "media/audio/pulse/pulse_output.h"
     17 #include "media/audio/pulse/pulse_unified.h"
     18 #include "media/audio/pulse/pulse_util.h"
     19 #include "media/base/channel_layout.h"
     20 
     21 #if defined(DLOPEN_PULSEAUDIO)
     22 #include "media/audio/pulse/pulse_stubs.h"
     23 
     24 using media_audio_pulse::kModulePulse;
     25 using media_audio_pulse::InitializeStubs;
     26 using media_audio_pulse::StubPathMap;
     27 #endif  // defined(DLOPEN_PULSEAUDIO)
     28 
     29 namespace media {
     30 
     31 using pulse::AutoPulseLock;
     32 using pulse::WaitForOperationCompletion;
     33 
     34 // Maximum number of output streams that can be open simultaneously.
     35 static const int kMaxOutputStreams = 50;
     36 
     37 static const base::FilePath::CharType kPulseLib[] =
     38     FILE_PATH_LITERAL("libpulse.so.0");
     39 
     40 // static
     41 AudioManager* AudioManagerPulse::Create(AudioLogFactory* audio_log_factory) {
     42   scoped_ptr<AudioManagerPulse> ret(new AudioManagerPulse(audio_log_factory));
     43   if (ret->Init())
     44     return ret.release();
     45 
     46   DVLOG(1) << "PulseAudio is not available on the OS";
     47   return NULL;
     48 }
     49 
     50 AudioManagerPulse::AudioManagerPulse(AudioLogFactory* audio_log_factory)
     51     : AudioManagerBase(audio_log_factory),
     52       input_mainloop_(NULL),
     53       input_context_(NULL),
     54       devices_(NULL),
     55       native_input_sample_rate_(0) {
     56   SetMaxOutputStreamsAllowed(kMaxOutputStreams);
     57 }
     58 
     59 AudioManagerPulse::~AudioManagerPulse() {
     60   Shutdown();
     61 
     62   // The Pulse objects are the last things to be destroyed since Shutdown()
     63   // needs them.
     64   DestroyPulse();
     65 }
     66 
     67 // Implementation of AudioManager.
     68 bool AudioManagerPulse::HasAudioOutputDevices() {
     69   AudioDeviceNames devices;
     70   GetAudioOutputDeviceNames(&devices);
     71   return !devices.empty();
     72 }
     73 
     74 bool AudioManagerPulse::HasAudioInputDevices() {
     75   AudioDeviceNames devices;
     76   GetAudioInputDeviceNames(&devices);
     77   return !devices.empty();
     78 }
     79 
     80 void AudioManagerPulse::ShowAudioInputSettings() {
     81   AudioManagerAlsa::ShowLinuxAudioInputSettings();
     82 }
     83 
     84 void AudioManagerPulse::GetAudioDeviceNames(
     85     bool input, media::AudioDeviceNames* device_names) {
     86   DCHECK(device_names->empty());
     87   DCHECK(input_mainloop_);
     88   DCHECK(input_context_);
     89   AutoPulseLock auto_lock(input_mainloop_);
     90   devices_ = device_names;
     91   pa_operation* operation = NULL;
     92   if (input) {
     93     operation = pa_context_get_source_info_list(
     94       input_context_, InputDevicesInfoCallback, this);
     95   } else {
     96     operation = pa_context_get_sink_info_list(
     97         input_context_, OutputDevicesInfoCallback, this);
     98   }
     99   WaitForOperationCompletion(input_mainloop_, operation);
    100 
    101   // Prepend the default device if the list is not empty.
    102   if (!device_names->empty()) {
    103     device_names->push_front(
    104         AudioDeviceName(AudioManagerBase::kDefaultDeviceName,
    105                         AudioManagerBase::kDefaultDeviceId));
    106   }
    107 }
    108 
    109 void AudioManagerPulse::GetAudioInputDeviceNames(
    110     AudioDeviceNames* device_names) {
    111   GetAudioDeviceNames(true, device_names);
    112 }
    113 
    114 void AudioManagerPulse::GetAudioOutputDeviceNames(
    115     AudioDeviceNames* device_names) {
    116   GetAudioDeviceNames(false, device_names);
    117 }
    118 
    119 AudioParameters AudioManagerPulse::GetInputStreamParameters(
    120     const std::string& device_id) {
    121   static const int kDefaultInputBufferSize = 1024;
    122 
    123   // TODO(xians): add support for querying native channel layout for pulse.
    124   return AudioParameters(
    125       AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
    126       GetNativeSampleRate(), 16, kDefaultInputBufferSize);
    127 }
    128 
    129 AudioOutputStream* AudioManagerPulse::MakeLinearOutputStream(
    130     const AudioParameters& params) {
    131   DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
    132   return MakeOutputStream(params, std::string());
    133 }
    134 
    135 AudioOutputStream* AudioManagerPulse::MakeLowLatencyOutputStream(
    136     const AudioParameters& params,
    137     const std::string& device_id,
    138     const std::string& input_device_id) {
    139   DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
    140   DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
    141   return MakeOutputStream(params, input_device_id);
    142 }
    143 
    144 AudioInputStream* AudioManagerPulse::MakeLinearInputStream(
    145     const AudioParameters& params, const std::string& device_id) {
    146   DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
    147   return MakeInputStream(params, device_id);
    148 }
    149 
    150 AudioInputStream* AudioManagerPulse::MakeLowLatencyInputStream(
    151     const AudioParameters& params, const std::string& device_id) {
    152   DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
    153   return MakeInputStream(params, device_id);
    154 }
    155 
    156 AudioParameters AudioManagerPulse::GetPreferredOutputStreamParameters(
    157     const std::string& output_device_id,
    158     const AudioParameters& input_params) {
    159   // TODO(tommi): Support |output_device_id|.
    160   DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
    161   static const int kDefaultOutputBufferSize = 512;
    162 
    163   ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
    164   int buffer_size = kDefaultOutputBufferSize;
    165   int bits_per_sample = 16;
    166   int input_channels = 0;
    167   int sample_rate;
    168   if (input_params.IsValid()) {
    169     bits_per_sample = input_params.bits_per_sample();
    170     channel_layout = input_params.channel_layout();
    171     input_channels = input_params.input_channels();
    172     buffer_size = std::min(buffer_size, input_params.frames_per_buffer());
    173     sample_rate = input_params.sample_rate();
    174   } else {
    175     sample_rate = GetNativeSampleRate();
    176   }
    177 
    178   int user_buffer_size = GetUserBufferSize();
    179   if (user_buffer_size)
    180     buffer_size = user_buffer_size;
    181 
    182   return AudioParameters(
    183       AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels,
    184       sample_rate, bits_per_sample, buffer_size, AudioParameters::NO_EFFECTS);
    185 }
    186 
    187 AudioOutputStream* AudioManagerPulse::MakeOutputStream(
    188     const AudioParameters& params, const std::string& input_device_id) {
    189   if (params.input_channels()) {
    190     return new PulseAudioUnifiedStream(params, input_device_id, this);
    191   }
    192 
    193   return new PulseAudioOutputStream(params, this);
    194 }
    195 
    196 AudioInputStream* AudioManagerPulse::MakeInputStream(
    197     const AudioParameters& params, const std::string& device_id) {
    198   return new PulseAudioInputStream(this, device_id, params,
    199                                    input_mainloop_, input_context_);
    200 }
    201 
    202 int AudioManagerPulse::GetNativeSampleRate() {
    203   DCHECK(input_mainloop_);
    204   DCHECK(input_context_);
    205   AutoPulseLock auto_lock(input_mainloop_);
    206   pa_operation* operation = pa_context_get_server_info(
    207       input_context_, SampleRateInfoCallback, this);
    208   WaitForOperationCompletion(input_mainloop_, operation);
    209 
    210   return native_input_sample_rate_;
    211 }
    212 
    213 bool AudioManagerPulse::Init() {
    214   DCHECK(!input_mainloop_);
    215 
    216 #if defined(DLOPEN_PULSEAUDIO)
    217   StubPathMap paths;
    218 
    219   // Check if the pulse library is avialbale.
    220   paths[kModulePulse].push_back(kPulseLib);
    221   if (!InitializeStubs(paths)) {
    222     DLOG(WARNING) << "Failed on loading the Pulse library and symbols";
    223     return false;
    224   }
    225 #endif  // defined(DLOPEN_PULSEAUDIO)
    226 
    227   // Create a mainloop API and connect to the default server.
    228   // The mainloop is the internal asynchronous API event loop.
    229   input_mainloop_ = pa_threaded_mainloop_new();
    230   if (!input_mainloop_)
    231     return false;
    232 
    233   // Start the threaded mainloop.
    234   if (pa_threaded_mainloop_start(input_mainloop_))
    235     return false;
    236 
    237   // Lock the event loop object, effectively blocking the event loop thread
    238   // from processing events. This is necessary.
    239   AutoPulseLock auto_lock(input_mainloop_);
    240 
    241   pa_mainloop_api* pa_mainloop_api =
    242       pa_threaded_mainloop_get_api(input_mainloop_);
    243   input_context_ = pa_context_new(pa_mainloop_api, "Chrome input");
    244   if (!input_context_)
    245     return false;
    246 
    247   pa_context_set_state_callback(input_context_, &pulse::ContextStateCallback,
    248                                 input_mainloop_);
    249   if (pa_context_connect(input_context_, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL)) {
    250     DLOG(ERROR) << "Failed to connect to the context.  Error: "
    251                 << pa_strerror(pa_context_errno(input_context_));
    252     return false;
    253   }
    254 
    255   // Wait until |input_context_| is ready.  pa_threaded_mainloop_wait() must be
    256   // called after pa_context_get_state() in case the context is already ready,
    257   // otherwise pa_threaded_mainloop_wait() will hang indefinitely.
    258   while (true) {
    259     pa_context_state_t context_state = pa_context_get_state(input_context_);
    260     if (!PA_CONTEXT_IS_GOOD(context_state))
    261       return false;
    262     if (context_state == PA_CONTEXT_READY)
    263       break;
    264     pa_threaded_mainloop_wait(input_mainloop_);
    265   }
    266 
    267   return true;
    268 }
    269 
    270 void AudioManagerPulse::DestroyPulse() {
    271   if (!input_mainloop_) {
    272     DCHECK(!input_context_);
    273     return;
    274   }
    275 
    276   {
    277     AutoPulseLock auto_lock(input_mainloop_);
    278     if (input_context_) {
    279       // Clear our state callback.
    280       pa_context_set_state_callback(input_context_, NULL, NULL);
    281       pa_context_disconnect(input_context_);
    282       pa_context_unref(input_context_);
    283       input_context_ = NULL;
    284     }
    285   }
    286 
    287   pa_threaded_mainloop_stop(input_mainloop_);
    288   pa_threaded_mainloop_free(input_mainloop_);
    289   input_mainloop_ = NULL;
    290 }
    291 
    292 void AudioManagerPulse::InputDevicesInfoCallback(pa_context* context,
    293                                                  const pa_source_info* info,
    294                                                  int error, void *user_data) {
    295   AudioManagerPulse* manager = reinterpret_cast<AudioManagerPulse*>(user_data);
    296 
    297   if (error) {
    298     // Signal the pulse object that it is done.
    299     pa_threaded_mainloop_signal(manager->input_mainloop_, 0);
    300     return;
    301   }
    302 
    303   // Exclude the output devices.
    304   if (info->monitor_of_sink == PA_INVALID_INDEX) {
    305     manager->devices_->push_back(AudioDeviceName(info->description,
    306                                                  info->name));
    307   }
    308 }
    309 
    310 void AudioManagerPulse::OutputDevicesInfoCallback(pa_context* context,
    311                                                   const pa_sink_info* info,
    312                                                   int error, void *user_data) {
    313   AudioManagerPulse* manager = reinterpret_cast<AudioManagerPulse*>(user_data);
    314 
    315   if (error) {
    316     // Signal the pulse object that it is done.
    317     pa_threaded_mainloop_signal(manager->input_mainloop_, 0);
    318     return;
    319   }
    320 
    321   manager->devices_->push_back(AudioDeviceName(info->description,
    322                                                info->name));
    323 }
    324 
    325 void AudioManagerPulse::SampleRateInfoCallback(pa_context* context,
    326                                                const pa_server_info* info,
    327                                                void* user_data) {
    328   AudioManagerPulse* manager = reinterpret_cast<AudioManagerPulse*>(user_data);
    329 
    330   manager->native_input_sample_rate_ = info->sample_spec.rate;
    331   pa_threaded_mainloop_signal(manager->input_mainloop_, 0);
    332 }
    333 
    334 }  // namespace media
    335