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/clockless_audio_sink.h" 6 7 #include "base/threading/simple_thread.h" 8 #include "base/time/time.h" 9 #include "media/base/audio_renderer_sink.h" 10 11 namespace media { 12 13 // Internal to ClocklessAudioSink. Class is used to call Render() on a seperate 14 // thread, running as fast as it can read the data. 15 class ClocklessAudioSinkThread : public base::DelegateSimpleThread::Delegate { 16 public: 17 explicit ClocklessAudioSinkThread(const AudioParameters& params, 18 AudioRendererSink::RenderCallback* callback) 19 : callback_(callback), 20 audio_bus_(AudioBus::Create(params)), 21 stop_event_(new base::WaitableEvent(false, false)) {} 22 23 void Start() { 24 stop_event_->Reset(); 25 thread_.reset(new base::DelegateSimpleThread(this, "ClocklessAudioSink")); 26 thread_->Start(); 27 } 28 29 // Generate a signal to stop calling Render(). 30 base::TimeDelta Stop() { 31 stop_event_->Signal(); 32 thread_->Join(); 33 return playback_time_; 34 } 35 36 private: 37 // Call Render() repeatedly, keeping track of the rendering time. 38 virtual void Run() OVERRIDE { 39 base::TimeTicks start; 40 while (!stop_event_->IsSignaled()) { 41 int frames_received = callback_->Render(audio_bus_.get(), 0); 42 if (frames_received <= 0) { 43 // No data received, so let other threads run to provide data. 44 base::PlatformThread::YieldCurrentThread(); 45 } else if (start.is_null()) { 46 // First time we processed some audio, so record the starting time. 47 start = base::TimeTicks::HighResNow(); 48 } else { 49 // Keep track of the last time data was rendered. 50 playback_time_ = base::TimeTicks::HighResNow() - start; 51 } 52 } 53 } 54 55 AudioRendererSink::RenderCallback* callback_; 56 scoped_ptr<AudioBus> audio_bus_; 57 scoped_ptr<base::WaitableEvent> stop_event_; 58 scoped_ptr<base::DelegateSimpleThread> thread_; 59 base::TimeDelta playback_time_; 60 }; 61 62 ClocklessAudioSink::ClocklessAudioSink() 63 : initialized_(false), 64 playing_(false) {} 65 66 ClocklessAudioSink::~ClocklessAudioSink() {} 67 68 void ClocklessAudioSink::Initialize(const AudioParameters& params, 69 RenderCallback* callback) { 70 DCHECK(!initialized_); 71 thread_.reset(new ClocklessAudioSinkThread(params, callback)); 72 initialized_ = true; 73 } 74 75 void ClocklessAudioSink::Start() { 76 DCHECK(initialized_); 77 DCHECK(!playing_); 78 } 79 80 void ClocklessAudioSink::Stop() { 81 if (initialized_) 82 Pause(); 83 } 84 85 void ClocklessAudioSink::Play() { 86 DCHECK(initialized_); 87 88 if (playing_) 89 return; 90 91 playing_ = true; 92 thread_->Start(); 93 } 94 95 void ClocklessAudioSink::Pause() { 96 DCHECK(initialized_); 97 98 if (!playing_) 99 return; 100 101 playing_ = false; 102 playback_time_ = thread_->Stop(); 103 } 104 105 bool ClocklessAudioSink::SetVolume(double volume) { 106 // Audio is always muted. 107 return volume == 0.0; 108 } 109 110 } // namespace media 111