OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/audio/sounds/audio_stream_handler.h" | 5 #include "media/audio/sounds/audio_stream_handler.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/single_thread_task_runner.h" | 10 #include "base/single_thread_task_runner.h" |
11 #include "base/synchronization/lock.h" | |
11 #include "media/audio/audio_manager.h" | 12 #include "media/audio/audio_manager.h" |
12 #include "media/audio/audio_manager_base.h" | 13 #include "media/audio/audio_manager_base.h" |
13 #include "media/base/channel_layout.h" | 14 #include "media/base/channel_layout.h" |
14 | 15 |
15 namespace media { | 16 namespace media { |
16 | 17 |
17 namespace { | 18 namespace { |
18 | 19 |
19 // Volume percent. | 20 // Volume percent. |
20 const double kOutputVolumePercent = 0.8; | 21 const double kOutputVolumePercent = 0.8; |
21 | 22 |
22 // The number of frames each OnMoreData() call will request. | 23 // The number of frames each OnMoreData() call will request. |
23 const int kDefaultFrameCount = 1024; | 24 const int kDefaultFrameCount = 1024; |
24 | 25 |
25 AudioStreamHandler::TestObserver* g_observer_for_testing = NULL; | 26 AudioStreamHandler::TestObserver* g_observer_for_testing = NULL; |
26 AudioOutputStream::AudioSourceCallback* g_audio_source_for_testing = NULL; | 27 AudioOutputStream::AudioSourceCallback* g_audio_source_for_testing = NULL; |
27 | 28 |
28 } // namespace | 29 } // namespace |
29 | 30 |
30 class AudioStreamHandler::AudioStreamContainer | 31 class AudioStreamHandler::AudioStreamContainer |
31 : public AudioOutputStream::AudioSourceCallback { | 32 : public AudioOutputStream::AudioSourceCallback { |
32 public: | 33 public: |
33 AudioStreamContainer(const WavAudioHandler& wav_audio, | 34 AudioStreamContainer(const WavAudioHandler& wav_audio) |
34 const AudioParameters& params) | |
35 : stream_(NULL), | 35 : stream_(NULL), |
36 wav_audio_(wav_audio), | 36 wav_audio_(wav_audio), |
37 params_(params), | 37 cursor_(0), |
38 cursor_(0) { | 38 can_start_(true) { |
39 } | 39 } |
40 | 40 |
41 virtual ~AudioStreamContainer() { | 41 virtual ~AudioStreamContainer() { |
42 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); | 42 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); |
43 } | 43 } |
44 | 44 |
45 void Play() { | 45 void Play() { |
46 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); | 46 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); |
47 | 47 |
48 if (!stream_) { | 48 if (!stream_) { |
49 stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy(params_, | 49 const AudioParameters& p = wav_audio_.params(); |
50 std::string(), | 50 const AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, |
51 std::string()); | 51 p.channel_layout(), |
52 p.sample_rate(), | |
53 p.bits_per_sample(), | |
54 kDefaultFrameCount); | |
55 stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy( | |
56 params, std::string(), std::string()); | |
52 if (!stream_ || !stream_->Open()) { | 57 if (!stream_ || !stream_->Open()) { |
53 LOG(ERROR) << "Failed to open an output stream."; | 58 LOG(ERROR) << "Failed to open an output stream."; |
54 return; | 59 return; |
55 } | 60 } |
56 stream_->SetVolume(kOutputVolumePercent); | 61 stream_->SetVolume(kOutputVolumePercent); |
57 } else { | 62 } else if (!CanStart()) { |
DaleCurtis
2014/01/09 19:58:26
You can simplify this by tracking "started_" inste
ygorshenin1
2014/01/13 10:00:55
Done.
ygorshenin1
2014/01/13 10:00:55
Done.
| |
58 // TODO (ygorshenin@): implement smart stream rewind. | 63 return; |
59 stream_->Stop(); | |
60 } | 64 } |
61 | 65 |
62 cursor_ = 0; | 66 SetCursor(0); |
67 SetCanStart(false); | |
63 if (g_audio_source_for_testing) | 68 if (g_audio_source_for_testing) |
64 stream_->Start(g_audio_source_for_testing); | 69 stream_->Start(g_audio_source_for_testing); |
65 else | 70 else |
66 stream_->Start(this); | 71 stream_->Start(this); |
67 | 72 |
68 if (g_observer_for_testing) | 73 if (g_observer_for_testing) |
69 g_observer_for_testing->OnPlay(); | 74 g_observer_for_testing->OnPlay(); |
70 } | 75 } |
71 | 76 |
72 void Stop() { | 77 void Stop() { |
73 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); | 78 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); |
74 if (!stream_) | 79 StopStream(); |
75 return; | 80 if (stream_) |
76 stream_->Stop(); | 81 stream_->Close(); |
77 stream_->Close(); | |
78 stream_ = NULL; | 82 stream_ = NULL; |
79 | |
80 if (g_observer_for_testing) | |
81 g_observer_for_testing->OnStop(cursor_); | |
82 } | 83 } |
83 | 84 |
84 private: | 85 private: |
85 // AudioOutputStream::AudioSourceCallback overrides: | 86 // AudioOutputStream::AudioSourceCallback overrides: |
86 // Following methods could be called from *ANY* thread. | 87 // Following methods could be called from *ANY* thread. |
87 virtual int OnMoreData(AudioBus* dest, | 88 virtual int OnMoreData(AudioBus* dest, |
88 AudioBuffersState /* state */) OVERRIDE { | 89 AudioBuffersState /* state */) OVERRIDE { |
89 size_t bytes_written = 0; | 90 size_t bytes_written = 0; |
90 if (wav_audio_.AtEnd(cursor_) || | 91 size_t cursor = GetCursor(); |
91 !wav_audio_.CopyTo(dest, cursor_, &bytes_written)) { | 92 if (wav_audio_.AtEnd(cursor) || |
93 !wav_audio_.CopyTo(dest, cursor, &bytes_written)) { | |
92 AudioManager::Get()->GetTaskRunner()->PostTask( | 94 AudioManager::Get()->GetTaskRunner()->PostTask( |
93 FROM_HERE, | 95 FROM_HERE, |
94 base::Bind(&AudioStreamContainer::Stop, base::Unretained(this))); | 96 base::Bind(&AudioStreamContainer::StopStream, |
97 base::Unretained(this))); | |
95 return 0; | 98 return 0; |
96 } | 99 } |
97 cursor_ += bytes_written; | 100 SetCursor(cursor + bytes_written); |
98 | 101 |
99 return dest->frames(); | 102 return dest->frames(); |
100 } | 103 } |
101 | 104 |
102 virtual int OnMoreIOData(AudioBus* /* source */, | 105 virtual int OnMoreIOData(AudioBus* /* source */, |
103 AudioBus* dest, | 106 AudioBus* dest, |
104 AudioBuffersState state) OVERRIDE { | 107 AudioBuffersState state) OVERRIDE { |
105 return OnMoreData(dest, state); | 108 return OnMoreData(dest, state); |
106 } | 109 } |
107 | 110 |
108 virtual void OnError(AudioOutputStream* /* stream */) OVERRIDE { | 111 virtual void OnError(AudioOutputStream* /* stream */) OVERRIDE { |
109 LOG(ERROR) << "Error during system sound reproduction."; | 112 LOG(ERROR) << "Error during system sound reproduction."; |
110 } | 113 } |
111 | 114 |
115 void StopStream() { | |
116 if (stream_) | |
117 stream_->Stop(); | |
118 if (g_observer_for_testing) | |
119 g_observer_for_testing->OnStop(GetCursor()); | |
120 SetCanStart(true); | |
121 } | |
122 | |
123 size_t GetCursor() { | |
124 base::AutoLock al(cursor_lock_); | |
125 return cursor_; | |
126 } | |
127 | |
128 void SetCursor(size_t cursor) { | |
129 base::AutoLock al(cursor_lock_); | |
130 cursor_ = cursor; | |
131 } | |
132 | |
133 bool CanStart() { | |
134 base::AutoLock al(can_start_lock_); | |
135 return can_start_; | |
136 } | |
137 | |
138 void SetCanStart(bool can_start) { | |
139 base::AutoLock al(can_start_lock_); | |
140 can_start_ = can_start; | |
141 } | |
142 | |
112 AudioOutputStream* stream_; | 143 AudioOutputStream* stream_; |
113 | 144 |
114 const WavAudioHandler wav_audio_; | 145 const WavAudioHandler wav_audio_; |
115 const AudioParameters params_; | |
116 | 146 |
147 base::Lock cursor_lock_; | |
117 size_t cursor_; | 148 size_t cursor_; |
118 | 149 |
150 base::Lock can_start_lock_; | |
151 bool can_start_; | |
152 | |
119 DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer); | 153 DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer); |
120 }; | 154 }; |
121 | 155 |
122 AudioStreamHandler::AudioStreamHandler(const base::StringPiece& wav_data) | 156 AudioStreamHandler::AudioStreamHandler(const base::StringPiece& wav_data) |
123 : wav_audio_(wav_data), | 157 : wav_audio_(wav_data), |
124 initialized_(false) { | 158 initialized_(false) { |
125 AudioManager* manager = AudioManager::Get(); | 159 AudioManager* manager = AudioManager::Get(); |
126 if (!manager) { | 160 if (!manager) { |
127 LOG(ERROR) << "Can't get access to audio manager."; | 161 LOG(ERROR) << "Can't get access to audio manager."; |
128 return; | 162 return; |
129 } | 163 } |
130 AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, | 164 if (!wav_audio_.params().IsValid()) { |
131 GuessChannelLayout(wav_audio_.num_channels()), | |
132 wav_audio_.sample_rate(), | |
133 wav_audio_.bits_per_sample(), | |
134 kDefaultFrameCount); | |
135 if (!params.IsValid()) { | |
136 LOG(ERROR) << "Audio params are invalid."; | 165 LOG(ERROR) << "Audio params are invalid."; |
137 return; | 166 return; |
138 } | 167 } |
139 stream_.reset(new AudioStreamContainer(wav_audio_, params)); | 168 stream_.reset(new AudioStreamContainer(wav_audio_)); |
140 initialized_ = true; | 169 initialized_ = true; |
141 } | 170 } |
142 | 171 |
143 AudioStreamHandler::~AudioStreamHandler() { | 172 AudioStreamHandler::~AudioStreamHandler() { |
144 DCHECK(CalledOnValidThread()); | 173 DCHECK(CalledOnValidThread()); |
145 AudioManager::Get()->GetTaskRunner()->PostTask( | 174 AudioManager::Get()->GetTaskRunner()->PostTask( |
146 FROM_HERE, | 175 FROM_HERE, |
147 base::Bind(&AudioStreamContainer::Stop, base::Unretained(stream_.get()))); | 176 base::Bind(&AudioStreamContainer::Stop, base::Unretained(stream_.get()))); |
148 AudioManager::Get()->GetTaskRunner()->DeleteSoon(FROM_HERE, | 177 AudioManager::Get()->GetTaskRunner()->DeleteSoon(FROM_HERE, |
149 stream_.release()); | 178 stream_.release()); |
(...skipping 29 matching lines...) Expand all Loading... | |
179 g_observer_for_testing = observer; | 208 g_observer_for_testing = observer; |
180 } | 209 } |
181 | 210 |
182 // static | 211 // static |
183 void AudioStreamHandler::SetAudioSourceForTesting( | 212 void AudioStreamHandler::SetAudioSourceForTesting( |
184 AudioOutputStream::AudioSourceCallback* source) { | 213 AudioOutputStream::AudioSourceCallback* source) { |
185 g_audio_source_for_testing = source; | 214 g_audio_source_for_testing = source; |
186 } | 215 } |
187 | 216 |
188 } // namespace media | 217 } // namespace media |
OLD | NEW |