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