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

Side by Side Diff: media/audio/audio_output_dispatcher.cc

Issue 6822019: Fix erratic HTML5 audio playback (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix nit Created 9 years, 8 months 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
« no previous file with comments | « media/audio/audio_output_dispatcher.h ('k') | media/base/pipeline_impl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/audio_output_dispatcher.h" 5 #include "media/audio/audio_output_dispatcher.h"
6 6
7 #include "base/compiler_specific.h" 7 #include "base/compiler_specific.h"
8 #include "base/message_loop.h" 8 #include "base/message_loop.h"
9 #include "base/time.h"
9 #include "media/audio/audio_io.h" 10 #include "media/audio/audio_io.h"
10 11
11 AudioOutputDispatcher::AudioOutputDispatcher( 12 AudioOutputDispatcher::AudioOutputDispatcher(
12 AudioManager* audio_manager, const AudioParameters& params, 13 AudioManager* audio_manager, const AudioParameters& params,
13 int close_delay_ms) 14 int close_delay_ms)
14 : audio_manager_(audio_manager), 15 : audio_manager_(audio_manager),
15 message_loop_(audio_manager->GetMessageLoop()), 16 message_loop_(audio_manager->GetMessageLoop()),
16 params_(params), 17 params_(params),
18 pause_delay_milliseconds_(2 * params.samples_per_packet *
19 base::Time::kMillisecondsPerSecond / params.sample_rate),
17 paused_proxies_(0), 20 paused_proxies_(0),
18 ALLOW_THIS_IN_INITIALIZER_LIST(close_timer_( 21 ALLOW_THIS_IN_INITIALIZER_LIST(close_timer_(
19 base::TimeDelta::FromMilliseconds(close_delay_ms), 22 base::TimeDelta::FromMilliseconds(close_delay_ms),
20 this, &AudioOutputDispatcher::ClosePendingStreams)) { 23 this, &AudioOutputDispatcher::ClosePendingStreams)) {
21 } 24 }
22 25
23 AudioOutputDispatcher::~AudioOutputDispatcher() { 26 AudioOutputDispatcher::~AudioOutputDispatcher() {
24 } 27 }
25 28
26 bool AudioOutputDispatcher::StreamOpened() { 29 bool AudioOutputDispatcher::StreamOpened() {
27 DCHECK_EQ(MessageLoop::current(), message_loop_); 30 DCHECK_EQ(MessageLoop::current(), message_loop_);
28 paused_proxies_++; 31 paused_proxies_++;
29 32
30 // Ensure that there is at least one open stream. 33 // Ensure that there is at least one open stream.
31 if (streams_.empty() && !CreateAndOpenStream()) { 34 if (idle_streams_.empty() && !CreateAndOpenStream()) {
32 return false; 35 return false;
33 } 36 }
34 37
35 close_timer_.Reset(); 38 close_timer_.Reset();
36 39
37 return true; 40 return true;
38 } 41 }
39 42
40 AudioOutputStream* AudioOutputDispatcher::StreamStarted() { 43 AudioOutputStream* AudioOutputDispatcher::StreamStarted() {
41 DCHECK_EQ(MessageLoop::current(), message_loop_); 44 DCHECK_EQ(MessageLoop::current(), message_loop_);
42 45
43 if (streams_.empty() && !CreateAndOpenStream()) { 46 if (idle_streams_.empty() && !CreateAndOpenStream()) {
44 return NULL; 47 return NULL;
45 } 48 }
46 49
47 AudioOutputStream* stream = streams_.back(); 50 AudioOutputStream* stream = idle_streams_.back();
48 streams_.pop_back(); 51 idle_streams_.pop_back();
49 52
50 DCHECK_GT(paused_proxies_, 0u); 53 DCHECK_GT(paused_proxies_, 0u);
51 paused_proxies_--; 54 paused_proxies_--;
52 55
53 close_timer_.Reset(); 56 close_timer_.Reset();
54 57
55 // Schedule task to allocate streams for other proxies if we need to. 58 // Schedule task to allocate streams for other proxies if we need to.
56 message_loop_->PostTask(FROM_HERE, NewRunnableMethod( 59 message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
57 this, &AudioOutputDispatcher::OpenTask)); 60 this, &AudioOutputDispatcher::OpenTask));
58 61
59 return stream; 62 return stream;
60 } 63 }
61 64
62 void AudioOutputDispatcher::StreamStopped(AudioOutputStream* stream) { 65 void AudioOutputDispatcher::StreamStopped(AudioOutputStream* stream) {
63 DCHECK_EQ(MessageLoop::current(), message_loop_); 66 DCHECK_EQ(MessageLoop::current(), message_loop_);
67
64 paused_proxies_++; 68 paused_proxies_++;
65 streams_.push_back(stream); 69
70 pausing_streams_.push_front(stream);
66 close_timer_.Reset(); 71 close_timer_.Reset();
72
73 // Don't recycle stream until two buffers worth of time has elapsed.
74 message_loop_->PostDelayedTask(
75 FROM_HERE,
76 NewRunnableMethod(this, &AudioOutputDispatcher::StopStreamTask),
77 pause_delay_milliseconds_);
78 }
79
80 void AudioOutputDispatcher::StopStreamTask() {
81 if (pausing_streams_.empty())
82 return;
83 AudioOutputStream* stream = pausing_streams_.back();
84 pausing_streams_.pop_back();
85 idle_streams_.push_back(stream);
67 } 86 }
68 87
69 void AudioOutputDispatcher::StreamClosed() { 88 void AudioOutputDispatcher::StreamClosed() {
70 DCHECK_EQ(MessageLoop::current(), message_loop_); 89 DCHECK_EQ(MessageLoop::current(), message_loop_);
71 90
91 while (!pausing_streams_.empty()) {
92 idle_streams_.push_back(pausing_streams_.back());
93 pausing_streams_.pop_back();
94 }
95
72 DCHECK_GT(paused_proxies_, 0u); 96 DCHECK_GT(paused_proxies_, 0u);
73 paused_proxies_--; 97 paused_proxies_--;
74 98
75 while (streams_.size() > paused_proxies_) { 99 while (idle_streams_.size() > paused_proxies_) {
76 streams_.back()->Close(); 100 idle_streams_.back()->Close();
77 streams_.pop_back(); 101 idle_streams_.pop_back();
78 } 102 }
79 } 103 }
80 104
81 MessageLoop* AudioOutputDispatcher::message_loop() { 105 MessageLoop* AudioOutputDispatcher::message_loop() {
82 return message_loop_; 106 return message_loop_;
83 } 107 }
84 108
85 bool AudioOutputDispatcher::CreateAndOpenStream() { 109 bool AudioOutputDispatcher::CreateAndOpenStream() {
86 AudioOutputStream* stream = 110 AudioOutputStream* stream =
87 audio_manager_->MakeAudioOutputStream(params_); 111 audio_manager_->MakeAudioOutputStream(params_);
88 if (!stream) { 112 if (!stream) {
89 return false; 113 return false;
90 } 114 }
91 if (!stream->Open()) { 115 if (!stream->Open()) {
92 stream->Close(); 116 stream->Close();
93 return false; 117 return false;
94 } 118 }
95 streams_.push_back(stream); 119 idle_streams_.push_back(stream);
96 return true; 120 return true;
97 } 121 }
98 122
99 void AudioOutputDispatcher::OpenTask() { 123 void AudioOutputDispatcher::OpenTask() {
100 // Make sure that we have at least one stream allocated if there 124 // Make sure that we have at least one stream allocated if there
101 // are paused streams. 125 // are paused streams.
102 if (paused_proxies_ > 0 && streams_.empty()) { 126 if (paused_proxies_ > 0 && idle_streams_.empty() &&
127 pausing_streams_.empty()) {
103 CreateAndOpenStream(); 128 CreateAndOpenStream();
104 } 129 }
105 130
106 close_timer_.Reset(); 131 close_timer_.Reset();
107 } 132 }
108 133
109 // This method is called by |close_timer_|. 134 // This method is called by |close_timer_|.
110 void AudioOutputDispatcher::ClosePendingStreams() { 135 void AudioOutputDispatcher::ClosePendingStreams() {
111 while (!streams_.empty()) { 136 while (!idle_streams_.empty()) {
112 streams_.back()->Close(); 137 idle_streams_.back()->Close();
113 streams_.pop_back(); 138 idle_streams_.pop_back();
114 } 139 }
115 } 140 }
OLDNEW
« no previous file with comments | « media/audio/audio_output_dispatcher.h ('k') | media/base/pipeline_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698