Home | History | Annotate | Download | only in audio
      1 // Copyright (c) 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 "chrome/browser/extensions/api/audio/audio_service.h"
      6 
      7 #include "base/callback.h"
      8 #include "base/memory/weak_ptr.h"
      9 #include "base/strings/string_number_conversions.h"
     10 #include "chromeos/audio/audio_device.h"
     11 #include "chromeos/audio/cras_audio_handler.h"
     12 #include "content/public/browser/browser_thread.h"
     13 
     14 using content::BrowserThread;
     15 
     16 namespace extensions {
     17 
     18 using api::audio::OutputDeviceInfo;
     19 using api::audio::InputDeviceInfo;
     20 
     21 class AudioServiceImpl : public AudioService,
     22                          public chromeos::CrasAudioHandler::AudioObserver {
     23  public:
     24   AudioServiceImpl();
     25   virtual ~AudioServiceImpl();
     26 
     27   // Called by listeners to this service to add/remove themselves as observers.
     28   virtual void AddObserver(AudioService::Observer* observer) OVERRIDE;
     29   virtual void RemoveObserver(AudioService::Observer* observer) OVERRIDE;
     30 
     31   // Start to query audio device information.
     32   virtual void StartGetInfo(const GetInfoCallback& callback) OVERRIDE;
     33   virtual void SetActiveDevices(const DeviceIdList& device_list) OVERRIDE;
     34   virtual bool SetDeviceProperties(const std::string& device_id,
     35                                    bool muted,
     36                                    int volume,
     37                                    int gain) OVERRIDE;
     38 
     39  protected:
     40   // chromeos::CrasAudioHandler::AudioObserver overrides.
     41   virtual void OnOutputVolumeChanged() OVERRIDE;
     42   virtual void OnInputGainChanged() OVERRIDE;
     43   virtual void OnOutputMuteChanged() OVERRIDE;
     44   virtual void OnInputMuteChanged() OVERRIDE;
     45   virtual void OnAudioNodesChanged() OVERRIDE;
     46   virtual void OnActiveOutputNodeChanged() OVERRIDE;
     47   virtual void OnActiveInputNodeChanged() OVERRIDE;
     48 
     49  private:
     50   void NotifyDeviceChanged();
     51 
     52   bool FindDevice(uint64 id, chromeos::AudioDevice* device);
     53   uint64 GetIdFromStr(const std::string& id_str);
     54 
     55   // List of observers.
     56   ObserverList<AudioService::Observer> observer_list_;
     57 
     58   chromeos::CrasAudioHandler* cras_audio_handler_;
     59 
     60   // Note: This should remain the last member so it'll be destroyed and
     61   // invalidate the weak pointers before any other members are destroyed.
     62   base::WeakPtrFactory<AudioServiceImpl> weak_ptr_factory_;
     63 
     64   DISALLOW_COPY_AND_ASSIGN(AudioServiceImpl);
     65 };
     66 
     67 AudioServiceImpl::AudioServiceImpl()
     68     : cras_audio_handler_(NULL),
     69       weak_ptr_factory_(this) {
     70   if (chromeos::CrasAudioHandler::IsInitialized()) {
     71     cras_audio_handler_ = chromeos::CrasAudioHandler::Get();
     72     cras_audio_handler_->AddAudioObserver(this);
     73   }
     74 }
     75 
     76 AudioServiceImpl::~AudioServiceImpl() {
     77   if (cras_audio_handler_ && chromeos::CrasAudioHandler::IsInitialized()) {
     78     cras_audio_handler_->RemoveAudioObserver(this);
     79   }
     80 }
     81 
     82 void AudioServiceImpl::AddObserver(AudioService::Observer* observer) {
     83   observer_list_.AddObserver(observer);
     84 }
     85 
     86 void AudioServiceImpl::RemoveObserver(AudioService::Observer* observer) {
     87   observer_list_.RemoveObserver(observer);
     88 }
     89 
     90 void AudioServiceImpl::StartGetInfo(const GetInfoCallback& callback) {
     91   DCHECK_CURRENTLY_ON(BrowserThread::UI);
     92   DCHECK(cras_audio_handler_);
     93   DCHECK(!callback.is_null());
     94 
     95   if (callback.is_null())
     96     return;
     97 
     98   OutputInfo output_info;
     99   InputInfo input_info;
    100   if (!cras_audio_handler_) {
    101     callback.Run(output_info, input_info, false);
    102     return;
    103   }
    104 
    105   chromeos::AudioDeviceList devices;
    106   cras_audio_handler_->GetAudioDevices(&devices);
    107   for (size_t i = 0; i < devices.size(); ++i) {
    108     if (!devices[i].is_input) {
    109       linked_ptr<OutputDeviceInfo> info(new OutputDeviceInfo());
    110       info->id = base::Uint64ToString(devices[i].id);
    111       info->name = devices[i].device_name + ": " + devices[i].display_name;
    112       info->is_active = devices[i].active;
    113       info->volume =
    114           cras_audio_handler_->GetOutputVolumePercentForDevice(devices[i].id);
    115       info->is_muted =
    116           cras_audio_handler_->IsOutputMutedForDevice(devices[i].id);
    117       output_info.push_back(info);
    118     } else {
    119       linked_ptr<InputDeviceInfo> info(new InputDeviceInfo());
    120       info->id = base::Uint64ToString(devices[i].id);
    121       info->name = devices[i].device_name + ": " + devices[i].display_name;
    122       info->is_active = devices[i].active;
    123       info->gain =
    124           cras_audio_handler_->GetInputGainPercentForDevice(devices[i].id);
    125       info->is_muted =
    126           cras_audio_handler_->IsInputMutedForDevice(devices[i].id);
    127       input_info.push_back(info);
    128     }
    129   }
    130   callback.Run(output_info, input_info, true);
    131 }
    132 
    133 void AudioServiceImpl::SetActiveDevices(const DeviceIdList& device_list) {
    134   DCHECK(cras_audio_handler_);
    135   if (!cras_audio_handler_)
    136     return;
    137 
    138   chromeos::CrasAudioHandler::NodeIdList id_list;
    139   for (size_t i = 0; i < device_list.size(); ++i) {
    140     chromeos::AudioDevice device;
    141     if (FindDevice(GetIdFromStr(device_list[i]), &device))
    142       id_list.push_back(device.id);
    143   }
    144   cras_audio_handler_->ChangeActiveNodes(id_list);
    145 }
    146 
    147 bool AudioServiceImpl::SetDeviceProperties(const std::string& device_id,
    148                                            bool muted,
    149                                            int volume,
    150                                            int gain) {
    151   DCHECK(cras_audio_handler_);
    152   if (!cras_audio_handler_)
    153     return false;
    154 
    155   chromeos::AudioDevice device;
    156   bool found = FindDevice(GetIdFromStr(device_id), &device);
    157   if (!found)
    158     return false;
    159 
    160   cras_audio_handler_->SetMuteForDevice(device.id, muted);
    161 
    162   if (!device.is_input && volume != -1) {
    163     cras_audio_handler_->SetVolumeGainPercentForDevice(device.id, volume);
    164     return true;
    165   } else if (device.is_input && gain != -1) {
    166     cras_audio_handler_->SetVolumeGainPercentForDevice(device.id, gain);
    167     return true;
    168   }
    169 
    170   return false;
    171 }
    172 
    173 bool AudioServiceImpl::FindDevice(uint64 id, chromeos::AudioDevice* device) {
    174   chromeos::AudioDeviceList devices;
    175   cras_audio_handler_->GetAudioDevices(&devices);
    176 
    177   for (size_t i = 0; i < devices.size(); ++i) {
    178     if (devices[i].id == id) {
    179       *device = devices[i];
    180       return true;
    181     }
    182   }
    183   return false;
    184 }
    185 
    186 uint64 AudioServiceImpl::GetIdFromStr(const std::string& id_str) {
    187   uint64 device_id;
    188   if (!base::StringToUint64(id_str, &device_id))
    189     return 0;
    190   else
    191     return device_id;
    192 }
    193 
    194 void AudioServiceImpl::OnOutputVolumeChanged() {
    195   NotifyDeviceChanged();
    196 }
    197 
    198 void AudioServiceImpl::OnOutputMuteChanged() {
    199   NotifyDeviceChanged();
    200 }
    201 
    202 void AudioServiceImpl::OnInputGainChanged() {
    203   NotifyDeviceChanged();
    204 }
    205 
    206 void AudioServiceImpl::OnInputMuteChanged() {
    207   NotifyDeviceChanged();
    208 }
    209 
    210 void AudioServiceImpl::OnAudioNodesChanged() {
    211   NotifyDeviceChanged();
    212 }
    213 
    214 void AudioServiceImpl::OnActiveOutputNodeChanged() {
    215   NotifyDeviceChanged();
    216 }
    217 
    218 void AudioServiceImpl::OnActiveInputNodeChanged() {
    219   NotifyDeviceChanged();
    220 }
    221 
    222 void AudioServiceImpl::NotifyDeviceChanged() {
    223   FOR_EACH_OBSERVER(AudioService::Observer, observer_list_, OnDeviceChanged());
    224 }
    225 
    226 AudioService* AudioService::CreateInstance() {
    227   return new AudioServiceImpl;
    228 }
    229 
    230 }  // namespace extensions
    231