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.
5 #include "media/audio/clockless_audio_sink.h"
8 #include "base/location.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/threading/simple_thread.h"
11 #include "media/base/audio_hash.h"
15 // Internal to ClocklessAudioSink. Class is used to call Render() on a seperate
16 // thread, running as fast as it can read the data.
17 class ClocklessAudioSinkThread
: public base::DelegateSimpleThread::Delegate
{
19 ClocklessAudioSinkThread(const AudioParameters
& params
,
20 AudioRendererSink::RenderCallback
* callback
,
22 : callback_(callback
),
23 audio_bus_(AudioBus::Create(params
)),
24 stop_event_(new base::WaitableEvent(false, false)) {
26 audio_hash_
.reset(new AudioHash());
31 thread_
.reset(new base::DelegateSimpleThread(this, "ClocklessAudioSink"));
35 // Generate a signal to stop calling Render().
36 base::TimeDelta
Stop() {
37 stop_event_
->Signal();
39 return playback_time_
;
42 std::string
GetAudioHash() {
44 return audio_hash_
->ToString();
48 // Call Render() repeatedly, keeping track of the rendering time.
50 base::TimeTicks start
;
51 while (!stop_event_
->IsSignaled()) {
52 const int frames_received
= callback_
->Render(audio_bus_
.get(), 0);
53 DCHECK_GE(frames_received
, 0);
55 audio_hash_
->Update(audio_bus_
.get(), frames_received
);
56 if (!frames_received
) {
57 // No data received, so let other threads run to provide data.
58 base::PlatformThread::YieldCurrentThread();
59 } else if (start
.is_null()) {
60 // First time we processed some audio, so record the starting time.
61 start
= base::TimeTicks::Now();
63 // Keep track of the last time data was rendered.
64 playback_time_
= base::TimeTicks::Now() - start
;
69 AudioRendererSink::RenderCallback
* callback_
;
70 scoped_ptr
<AudioBus
> audio_bus_
;
71 scoped_ptr
<base::WaitableEvent
> stop_event_
;
72 scoped_ptr
<base::DelegateSimpleThread
> thread_
;
73 base::TimeDelta playback_time_
;
74 scoped_ptr
<AudioHash
> audio_hash_
;
77 ClocklessAudioSink::ClocklessAudioSink()
78 : initialized_(false), playing_(false), hashing_(false) {}
80 ClocklessAudioSink::~ClocklessAudioSink() {}
82 void ClocklessAudioSink::Initialize(const AudioParameters
& params
,
83 RenderCallback
* callback
) {
84 DCHECK(!initialized_
);
85 thread_
.reset(new ClocklessAudioSinkThread(params
, callback
, hashing_
));
89 void ClocklessAudioSink::Start() {
94 void ClocklessAudioSink::Stop() {
99 void ClocklessAudioSink::Play() {
100 DCHECK(initialized_
);
109 void ClocklessAudioSink::Pause() {
110 DCHECK(initialized_
);
116 playback_time_
= thread_
->Stop();
119 bool ClocklessAudioSink::SetVolume(double volume
) {
120 // Audio is always muted.
121 return volume
== 0.0;
124 OutputDevice
* ClocklessAudioSink::GetOutputDevice() {
128 void ClocklessAudioSink::StartAudioHashForTesting() {
129 DCHECK(!initialized_
);
133 std::string
ClocklessAudioSink::GetAudioHashForTesting() {
134 return thread_
&& hashing_
? thread_
->GetAudioHash() : std::string();