| OLD | NEW | 
| (Empty) |  | 
 |    1 // Copyright (c) 2012 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/audio_output_dispatcher_impl.h" | 
 |    6  | 
 |    7 #include <algorithm> | 
 |    8  | 
 |    9 #include "base/bind.h" | 
 |   10 #include "base/compiler_specific.h" | 
 |   11 #include "base/message_loop.h" | 
 |   12 #include "base/time.h" | 
 |   13 #include "media/audio/audio_io.h" | 
 |   14 #include "media/audio/audio_output_proxy.h" | 
 |   15 #include "media/audio/audio_util.h" | 
 |   16  | 
 |   17 namespace media { | 
 |   18  | 
 |   19 AudioOutputDispatcherImpl::AudioOutputDispatcherImpl( | 
 |   20     AudioManager* audio_manager, | 
 |   21     const AudioParameters& params, | 
 |   22     const base::TimeDelta& close_delay) | 
 |   23     : AudioOutputDispatcher(audio_manager, params), | 
 |   24       pause_delay_(base::TimeDelta::FromMilliseconds( | 
 |   25           2 * params.frames_per_buffer() * | 
 |   26           base::Time::kMillisecondsPerSecond / params.sample_rate())), | 
 |   27       paused_proxies_(0), | 
 |   28       ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)), | 
 |   29       close_timer_(FROM_HERE, | 
 |   30                    close_delay, | 
 |   31                    weak_this_.GetWeakPtr(), | 
 |   32                    &AudioOutputDispatcherImpl::ClosePendingStreams) { | 
 |   33 } | 
 |   34  | 
 |   35 AudioOutputDispatcherImpl::~AudioOutputDispatcherImpl() { | 
 |   36   DCHECK(proxy_to_physical_map_.empty()); | 
 |   37   DCHECK(idle_streams_.empty()); | 
 |   38   DCHECK(pausing_streams_.empty()); | 
 |   39 } | 
 |   40  | 
 |   41 bool AudioOutputDispatcherImpl::OpenStream() { | 
 |   42   DCHECK_EQ(MessageLoop::current(), message_loop_); | 
 |   43  | 
 |   44   paused_proxies_++; | 
 |   45  | 
 |   46   // Ensure that there is at least one open stream. | 
 |   47   if (idle_streams_.empty() && !CreateAndOpenStream()) | 
 |   48     return false; | 
 |   49  | 
 |   50   close_timer_.Reset(); | 
 |   51   return true; | 
 |   52 } | 
 |   53  | 
 |   54 bool AudioOutputDispatcherImpl::StartStream( | 
 |   55     AudioOutputStream::AudioSourceCallback* callback, | 
 |   56     AudioOutputProxy* stream_proxy) { | 
 |   57   DCHECK_EQ(MessageLoop::current(), message_loop_); | 
 |   58  | 
 |   59   if (idle_streams_.empty() && !CreateAndOpenStream()) | 
 |   60     return false; | 
 |   61  | 
 |   62   AudioOutputStream* physical_stream = idle_streams_.back(); | 
 |   63   DCHECK(physical_stream); | 
 |   64   idle_streams_.pop_back(); | 
 |   65  | 
 |   66   DCHECK_GT(paused_proxies_, 0u); | 
 |   67   --paused_proxies_; | 
 |   68  | 
 |   69   close_timer_.Reset(); | 
 |   70  | 
 |   71   // Schedule task to allocate streams for other proxies if we need to. | 
 |   72   message_loop_->PostTask(FROM_HERE, base::Bind( | 
 |   73       &AudioOutputDispatcherImpl::OpenTask, weak_this_.GetWeakPtr())); | 
 |   74  | 
 |   75   double volume = 0; | 
 |   76   stream_proxy->GetVolume(&volume); | 
 |   77   physical_stream->SetVolume(volume); | 
 |   78   physical_stream->Start(callback); | 
 |   79   proxy_to_physical_map_[stream_proxy] = physical_stream; | 
 |   80   return true; | 
 |   81 } | 
 |   82  | 
 |   83 void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) { | 
 |   84   DCHECK_EQ(MessageLoop::current(), message_loop_); | 
 |   85  | 
 |   86   AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy); | 
 |   87   DCHECK(it != proxy_to_physical_map_.end()); | 
 |   88   AudioOutputStream* physical_stream = it->second; | 
 |   89   proxy_to_physical_map_.erase(it); | 
 |   90  | 
 |   91   physical_stream->Stop(); | 
 |   92  | 
 |   93   ++paused_proxies_; | 
 |   94  | 
 |   95   pausing_streams_.push_front(physical_stream); | 
 |   96  | 
 |   97   // Don't recycle stream until two buffers worth of time has elapsed. | 
 |   98   message_loop_->PostDelayedTask( | 
 |   99       FROM_HERE, | 
 |  100       base::Bind(&AudioOutputDispatcherImpl::StopStreamTask, | 
 |  101                  weak_this_.GetWeakPtr()), | 
 |  102       pause_delay_); | 
 |  103 } | 
 |  104  | 
 |  105 void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy* stream_proxy, | 
 |  106                                                 double volume) { | 
 |  107   DCHECK_EQ(MessageLoop::current(), message_loop_); | 
 |  108   AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy); | 
 |  109   if (it != proxy_to_physical_map_.end()) { | 
 |  110     AudioOutputStream* physical_stream = it->second; | 
 |  111     physical_stream->SetVolume(volume); | 
 |  112   } | 
 |  113 } | 
 |  114  | 
 |  115 void AudioOutputDispatcherImpl::StopStreamTask() { | 
 |  116   DCHECK_EQ(MessageLoop::current(), message_loop_); | 
 |  117  | 
 |  118   if (pausing_streams_.empty()) | 
 |  119     return; | 
 |  120  | 
 |  121   AudioOutputStream* stream = pausing_streams_.back(); | 
 |  122   pausing_streams_.pop_back(); | 
 |  123   idle_streams_.push_back(stream); | 
 |  124   close_timer_.Reset(); | 
 |  125 } | 
 |  126  | 
 |  127 void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy* stream_proxy) { | 
 |  128   DCHECK_EQ(MessageLoop::current(), message_loop_); | 
 |  129  | 
 |  130   while (!pausing_streams_.empty()) { | 
 |  131     idle_streams_.push_back(pausing_streams_.back()); | 
 |  132     pausing_streams_.pop_back(); | 
 |  133   } | 
 |  134  | 
 |  135   DCHECK_GT(paused_proxies_, 0u); | 
 |  136   paused_proxies_--; | 
 |  137  | 
 |  138   while (idle_streams_.size() > paused_proxies_) { | 
 |  139     idle_streams_.back()->Close(); | 
 |  140     idle_streams_.pop_back(); | 
 |  141   } | 
 |  142 } | 
 |  143  | 
 |  144 void AudioOutputDispatcherImpl::Shutdown() { | 
 |  145   DCHECK_EQ(MessageLoop::current(), message_loop_); | 
 |  146  | 
 |  147   // Cancel any pending tasks to close paused streams or create new ones. | 
 |  148   weak_this_.InvalidateWeakPtrs(); | 
 |  149  | 
 |  150   // No AudioOutputProxy objects should hold a reference to us when we get | 
 |  151   // to this stage. | 
 |  152   DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference"; | 
 |  153  | 
 |  154   AudioOutputStreamList::iterator it = idle_streams_.begin(); | 
 |  155   for (; it != idle_streams_.end(); ++it) | 
 |  156     (*it)->Close(); | 
 |  157   idle_streams_.clear(); | 
 |  158  | 
 |  159   it = pausing_streams_.begin(); | 
 |  160   for (; it != pausing_streams_.end(); ++it) | 
 |  161     (*it)->Close(); | 
 |  162   pausing_streams_.clear(); | 
 |  163 } | 
 |  164  | 
 |  165 bool AudioOutputDispatcherImpl::CreateAndOpenStream() { | 
 |  166   DCHECK_EQ(MessageLoop::current(), message_loop_); | 
 |  167   AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(params_); | 
 |  168   if (!stream) | 
 |  169     return false; | 
 |  170  | 
 |  171   if (!stream->Open()) { | 
 |  172     stream->Close(); | 
 |  173     return false; | 
 |  174   } | 
 |  175   idle_streams_.push_back(stream); | 
 |  176   return true; | 
 |  177 } | 
 |  178  | 
 |  179 void AudioOutputDispatcherImpl::OpenTask() { | 
 |  180   DCHECK_EQ(MessageLoop::current(), message_loop_); | 
 |  181   // Make sure that we have at least one stream allocated if there | 
 |  182   // are paused streams. | 
 |  183   if (paused_proxies_ > 0 && idle_streams_.empty() && | 
 |  184       pausing_streams_.empty()) { | 
 |  185     CreateAndOpenStream(); | 
 |  186   } | 
 |  187  | 
 |  188   close_timer_.Reset(); | 
 |  189 } | 
 |  190  | 
 |  191 // This method is called by |close_timer_|. | 
 |  192 void AudioOutputDispatcherImpl::ClosePendingStreams() { | 
 |  193   DCHECK_EQ(MessageLoop::current(), message_loop_); | 
 |  194   while (!idle_streams_.empty()) { | 
 |  195     idle_streams_.back()->Close(); | 
 |  196     idle_streams_.pop_back(); | 
 |  197   } | 
 |  198 } | 
 |  199  | 
 |  200 }  // namespace media | 
| OLD | NEW |