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