Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(114)

Side by Side Diff: media/audio/sounds/audio_stream_handler.cc

Issue 115693004: Added volume adjust sound behind the flag. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed creation of AudioParameters. Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/cancelable_callback.h"
9 #include "base/logging.h" 10 #include "base/logging.h"
10 #include "base/message_loop/message_loop_proxy.h" 11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/synchronization/lock.h"
13 #include "base/time/time.h"
11 #include "media/audio/audio_manager.h" 14 #include "media/audio/audio_manager.h"
12 #include "media/audio/audio_manager_base.h" 15 #include "media/audio/audio_manager_base.h"
13 #include "media/base/channel_layout.h" 16 #include "media/base/channel_layout.h"
14 17
15 namespace media { 18 namespace media {
16 19
17 namespace { 20 namespace {
18 21
19 // Volume percent. 22 // Volume percent.
20 const double kOutputVolumePercent = 0.8; 23 const double kOutputVolumePercent = 0.8;
21 24
25 // Delay between end of sound and call to AudioOutputStream::Stop().
26 const int kStopStreamDelaySec = 3;
27
22 // The number of frames each OnMoreData() call will request. 28 // The number of frames each OnMoreData() call will request.
23 const int kDefaultFrameCount = 1024; 29 const int kDefaultFrameCount = 1024;
24 30
25 AudioStreamHandler::TestObserver* g_observer_for_testing = NULL; 31 AudioStreamHandler::TestObserver* g_observer_for_testing = NULL;
26 AudioOutputStream::AudioSourceCallback* g_audio_source_for_testing = NULL; 32 AudioOutputStream::AudioSourceCallback* g_audio_source_for_testing = NULL;
27 33
28 } // namespace 34 } // namespace
29 35
30 class AudioStreamHandler::AudioStreamContainer 36 class AudioStreamHandler::AudioStreamContainer
31 : public AudioOutputStream::AudioSourceCallback { 37 : public AudioOutputStream::AudioSourceCallback {
32 public: 38 public:
33 AudioStreamContainer(const WavAudioHandler& wav_audio, 39 AudioStreamContainer(const WavAudioHandler& wav_audio)
34 const AudioParameters& params)
35 : stream_(NULL), 40 : stream_(NULL),
36 wav_audio_(wav_audio), 41 wav_audio_(wav_audio),
37 params_(params), 42 cursor_(0),
38 cursor_(0) { 43 replay_scheduled_(false),
39 } 44 is_stream_stopped_(true),
45 schedule_replay_request_for_testing_(0) {}
40 46
41 virtual ~AudioStreamContainer() { 47 virtual ~AudioStreamContainer() {
42 DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread()); 48 DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread());
49 stop_stream_closure_.Cancel();
50
51 if (stream_) {
52 stream_->Stop();
53 stream_->Close();
54 }
43 } 55 }
44 56
45 void Play() { 57 void Play() {
46 DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread()); 58 DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread());
47 59
48 if (!stream_) { 60 {
49 stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy(params_, 61 base::AutoLock sl(state_lock_);
50 std::string(), 62
51 std::string()); 63 if (!stream_) {
52 if (!stream_ || !stream_->Open()) { 64 const AudioParameters& p = wav_audio_.params();
53 LOG(ERROR) << "Failed to open an output stream."; 65 const AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
66 p.channel_layout(),
67 p.sample_rate(),
68 p.bits_per_sample(),
69 kDefaultFrameCount);
70 stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy(
71 params, std::string(), std::string());
72 if (!stream_ || !stream_->Open()) {
73 LOG(ERROR) << "Failed to open an output stream.";
74 return;
75 }
76 cursor_ = 0;
77 stream_->SetVolume(kOutputVolumePercent);
78 } else if (is_stream_stopped_) {
79 // If stream exists and idle, just stop the stream and start again.
80 cursor_ = 0;
81 StopStreamWithoutLock();
DaleCurtis 2014/01/02 20:11:17 Method says WithoutLock but in under state_lock_.
ygorshenin1 2014/01/09 19:26:57 Removed.
82 } else {
83 // Stream exists and not idle, so let the current sound to
84 // finish playing. If less than |wav_audio_.duration()| / 2
85 // until the end (including all replay requests), then replay is
86 // sheduled. The main purpose of this strategy is to smooth
87 // sound reproduction when multiple requests are made, for
88 // instance, when user presses volume(up|down) button for a long
89 // time.
90 if (ReplayRequestCouldBeScheduled())
91 replay_scheduled_ = true;
54 return; 92 return;
55 } 93 }
56 stream_->SetVolume(kOutputVolumePercent); 94
57 } else { 95 last_play_start_time_ = base::TimeTicks::Now();
58 // TODO (ygorshenin@): implement smart stream rewind. 96 replay_scheduled_ = false;
59 stream_->Stop(); 97 is_stream_stopped_ = false;
60 } 98 }
61 99
62 cursor_ = 0;
63 if (g_audio_source_for_testing) 100 if (g_audio_source_for_testing)
64 stream_->Start(g_audio_source_for_testing); 101 stream_->Start(g_audio_source_for_testing);
65 else 102 else
66 stream_->Start(this); 103 stream_->Start(this);
67 104
68 if (g_observer_for_testing) 105 if (g_observer_for_testing)
69 g_observer_for_testing->OnPlay(); 106 g_observer_for_testing->OnPlay();
70 } 107 }
71 108
72 void Stop() { 109 void Stop() {
73 DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread()); 110 DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread());
74 if (!stream_) 111 StopStream();
75 return;
76 stream_->Stop();
77 stream_->Close();
78 stream_ = NULL;
79
80 if (g_observer_for_testing)
81 g_observer_for_testing->OnStop(cursor_);
82 } 112 }
83 113
84 private: 114 private:
115 friend class AudioStreamHandler;
116
85 // AudioOutputStream::AudioSourceCallback overrides: 117 // AudioOutputStream::AudioSourceCallback overrides:
86 // Following methods could be called from *ANY* thread. 118 // Following methods could be called from *ANY* thread.
87 virtual int OnMoreData(AudioBus* dest, 119 virtual int OnMoreData(AudioBus* dest,
88 AudioBuffersState /* state */) OVERRIDE { 120 AudioBuffersState /* state */) OVERRIDE {
121 base::AutoLock sl(state_lock_);
122
123 if (is_stream_stopped_)
124 return 0;
125
89 size_t bytes_written = 0; 126 size_t bytes_written = 0;
90 if (wav_audio_.AtEnd(cursor_) || 127 if (wav_audio_.AtEnd(cursor_) ||
91 !wav_audio_.CopyTo(dest, cursor_, &bytes_written)) { 128 !wav_audio_.CopyTo(dest, cursor_, &bytes_written)) {
92 AudioManager::Get()->GetMessageLoop()->PostTask( 129 // If there are replay requests, |cursor_| is reset and will
93 FROM_HERE, 130 // continue to play from the start. Otherwise, stream will be
94 base::Bind(&AudioStreamContainer::Stop, base::Unretained(this))); 131 // stopped (not closed!) in |kStopStreamDelaySec| seconds,
132 // unless new Play() requests arrive during this time period.
133 if (replay_scheduled_) {
134 cursor_ = 0;
135 last_play_start_time_ = base::TimeTicks::Now();
136 replay_scheduled_ = false;
137 if (g_observer_for_testing)
138 g_observer_for_testing->OnReplay();
139 } else {
140 is_stream_stopped_ = true;
141 stop_stream_closure_.Reset(base::Bind(&AudioStreamContainer::StopStream,
142 base::Unretained(this)));
143 AudioManager::Get()->GetMessageLoop()->PostDelayedTask(
144 FROM_HERE,
145 stop_stream_closure_.callback(),
146 base::TimeDelta::FromSeconds(kStopStreamDelaySec));
147 }
95 return 0; 148 return 0;
96 } 149 }
97 cursor_ += bytes_written; 150 cursor_ += bytes_written;
98 151
99 return dest->frames(); 152 return dest->frames();
100 } 153 }
101 154
102 virtual int OnMoreIOData(AudioBus* /* source */, 155 virtual int OnMoreIOData(AudioBus* /* source */,
103 AudioBus* dest, 156 AudioBus* dest,
104 AudioBuffersState state) OVERRIDE { 157 AudioBuffersState state) OVERRIDE {
105 return OnMoreData(dest, state); 158 return OnMoreData(dest, state);
106 } 159 }
107 160
108 virtual void OnError(AudioOutputStream* /* stream */) OVERRIDE { 161 virtual void OnError(AudioOutputStream* /* stream */) OVERRIDE {
109 LOG(ERROR) << "Error during system sound reproduction."; 162 LOG(ERROR) << "Error during system sound reproduction.";
110 } 163 }
111 164
165 void StopStreamWithoutLock() {
166 stop_stream_closure_.Cancel();
167 replay_scheduled_ = false;
168 if (stream_)
169 stream_->Stop();
170 if (g_observer_for_testing)
171 g_observer_for_testing->OnStop(cursor_);
172 }
173
174 void StopStream() {
175 base::AutoLock sl(state_lock_);
176 StopStreamWithoutLock();
177 }
178
179 bool ReplayRequestCouldBeScheduled() {
180 if (schedule_replay_request_for_testing_) {
181 --schedule_replay_request_for_testing_;
182 return true;
183 }
184 const base::TimeDelta delta =
185 base::TimeTicks::Now() - last_play_start_time_;
186 return 2 * delta > wav_audio_.params().GetBufferDuration() &&
187 !replay_scheduled_;
188 }
189
190 void AllowReplayOnceForTesting() {
191 base::AutoLock st(state_lock_);
192 ++schedule_replay_request_for_testing_;
193 }
194
112 AudioOutputStream* stream_; 195 AudioOutputStream* stream_;
113 196
114 const WavAudioHandler wav_audio_; 197 WavAudioHandler wav_audio_;
115 const AudioParameters params_;
116 198
117 size_t cursor_; 199 size_t cursor_;
118 200
201 // True if replay of the current sound is scheduled.
202 bool replay_scheduled_;
203
204 base::CancelableClosure stop_stream_closure_;
205 bool is_stream_stopped_;
206
207 // Last time sound started to play from the start.
208 base::TimeTicks last_play_start_time_;
209
210 int schedule_replay_request_for_testing_;
211
212 // State lock for all fields except stream_ and wav_audio_.
213 base::Lock state_lock_;
214
119 DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer); 215 DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer);
120 }; 216 };
121 217
122 AudioStreamHandler::AudioStreamHandler(const base::StringPiece& wav_data) 218 AudioStreamHandler::AudioStreamHandler(const base::StringPiece& wav_data)
123 : wav_audio_(wav_data), 219 : wav_audio_(wav_data),
124 initialized_(false) { 220 initialized_(false) {
125 AudioManager* manager = AudioManager::Get(); 221 AudioManager* manager = AudioManager::Get();
126 if (!manager) { 222 if (!manager) {
127 LOG(ERROR) << "Can't get access to audio manager."; 223 LOG(ERROR) << "Can't get access to audio manager.";
128 return; 224 return;
129 } 225 }
130 AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, 226 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."; 227 LOG(ERROR) << "Audio params are invalid.";
137 return; 228 return;
138 } 229 }
139 stream_.reset(new AudioStreamContainer(wav_audio_, params)); 230 stream_.reset(new AudioStreamContainer(wav_audio_));
140 initialized_ = true; 231 initialized_ = true;
141 } 232 }
142 233
143 AudioStreamHandler::~AudioStreamHandler() { 234 AudioStreamHandler::~AudioStreamHandler() {
144 DCHECK(CalledOnValidThread()); 235 DCHECK(CalledOnValidThread());
145 AudioManager::Get()->GetMessageLoop()->PostTask( 236 AudioManager::Get()->GetMessageLoop()->PostTask(
146 FROM_HERE, 237 FROM_HERE,
147 base::Bind(&AudioStreamContainer::Stop, base::Unretained(stream_.get()))); 238 base::Bind(&AudioStreamContainer::Stop, base::Unretained(stream_.get())));
148 AudioManager::Get()->GetMessageLoop()->DeleteSoon(FROM_HERE, 239 AudioManager::Get()->GetMessageLoop()->DeleteSoon(FROM_HERE,
149 stream_.release()); 240 stream_.release());
(...skipping 28 matching lines...) Expand all
178 void AudioStreamHandler::SetObserverForTesting(TestObserver* observer) { 269 void AudioStreamHandler::SetObserverForTesting(TestObserver* observer) {
179 g_observer_for_testing = observer; 270 g_observer_for_testing = observer;
180 } 271 }
181 272
182 // static 273 // static
183 void AudioStreamHandler::SetAudioSourceForTesting( 274 void AudioStreamHandler::SetAudioSourceForTesting(
184 AudioOutputStream::AudioSourceCallback* source) { 275 AudioOutputStream::AudioSourceCallback* source) {
185 g_audio_source_for_testing = source; 276 g_audio_source_for_testing = source;
186 } 277 }
187 278
279 void AudioStreamHandler::AllowReplayOnceForTesting() {
280 AudioManager::Get()->GetMessageLoop()->PostTask(
281 FROM_HERE,
282 base::Bind(&AudioStreamContainer::AllowReplayOnceForTesting,
283 base::Unretained(stream_.get())));
284 }
285
188 } // namespace media 286 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698