summaryrefslogtreecommitdiffstats
path: root/media/audio/audio_output_controller.cc
diff options
context:
space:
mode:
authorenal@chromium.org <enal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-16 00:45:22 +0000
committerenal@chromium.org <enal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-16 00:45:22 +0000
commit6aa4a70d4ba67d84c2b00cf744371702f64d3a41 (patch)
tree6e24a882f5e69953807fb6749d90d8a25dc43c78 /media/audio/audio_output_controller.cc
parent619c5dba728763d3b6e1fbaa7537a4262810cb99 (diff)
downloadchromium_src-6aa4a70d4ba67d84c2b00cf744371702f64d3a41.zip
chromium_src-6aa4a70d4ba67d84c2b00cf744371702f64d3a41.tar.gz
chromium_src-6aa4a70d4ba67d84c2b00cf744371702f64d3a41.tar.bz2
Workaround for OS/X crash when stop/starting stream too quickly.
We have much better fix in audio mixer, but we need some fix in M20. On Mac do not allow starting of audio stream within 50ms of stopping. BUG=128128 TEST=Crash should go away, or at least become much less frequent. Review URL: https://chromiumcodereview.appspot.com/10387137 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@137324 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/audio/audio_output_controller.cc')
-rw-r--r--media/audio/audio_output_controller.cc43
1 files changed, 32 insertions, 11 deletions
diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc
index da90f10..13966d1 100644
--- a/media/audio/audio_output_controller.cc
+++ b/media/audio/audio_output_controller.cc
@@ -13,8 +13,13 @@
#include "base/time.h"
using base::Time;
+using base::TimeDelta;
using base::WaitableEvent;
+// Workaround for crbug.com/128128.
+// Minimal delay between stream->Stop() and stream->Start().
+const int kMacWorkaroundInMilliseconds = 50;
+
namespace media {
// Signal a pause in low-latency mode.
@@ -33,7 +38,10 @@ AudioOutputController::AudioOutputController(EventHandler* handler,
sync_reader_(sync_reader),
message_loop_(NULL),
number_polling_attempts_left_(0),
- ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) {
+ ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)),
+ previous_stop_time_(
+ Time::Now() -
+ TimeDelta::FromMilliseconds(kMacWorkaroundInMilliseconds + 1)) {
}
AudioOutputController::~AudioOutputController() {
@@ -170,7 +178,7 @@ void AudioOutputController::DoPlay() {
FROM_HERE,
base::Bind(&AudioOutputController::PollAndStartIfDataReady,
weak_this_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(kPollPauseInMilliseconds));
+ TimeDelta::FromMilliseconds(kPollPauseInMilliseconds));
}
void AudioOutputController::PollAndStartIfDataReady() {
@@ -195,12 +203,25 @@ void AudioOutputController::PollAndStartIfDataReady() {
FROM_HERE,
base::Bind(&AudioOutputController::PollAndStartIfDataReady,
weak_this_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(kPollPauseInMilliseconds));
+ TimeDelta::FromMilliseconds(kPollPauseInMilliseconds));
}
}
void AudioOutputController::StartStream() {
DCHECK(message_loop_->BelongsToCurrentThread());
+#if defined(OS_MACOSX)
+ // HACK: workaround for crbug.com/128128.
+ // Mac OS crashes if we start playback too soon after previous ended.
+ // Audio mixer contains better fix, it keeps physical stream opened for
+ // some time after logical one is closed, so sequence of play / pause / play /
+ // pause / ... would reuse the same stream, but we need fix for M20.
+ // TODO(enal): Remove after turning on mixer by default.
+ while ((Time::Now() - previous_stop_time_).InMilliseconds() <
+ kMacWorkaroundInMilliseconds) {
+ base::PlatformThread::YieldCurrentThread();
+ }
+#endif
+
state_ = kPlaying;
// We start the AudioOutputStream lazily.
@@ -213,8 +234,13 @@ void AudioOutputController::StartStream() {
void AudioOutputController::DoPause() {
DCHECK(message_loop_->BelongsToCurrentThread());
- if (stream_)
+ if (stream_) {
+ // Then we stop the audio device. This is not the perfect solution
+ // because it discards all the internal buffer in the audio device.
+ // TODO(hclam): Actually pause the audio device.
stream_->Stop();
+ previous_stop_time_ = Time::Now();
+ }
switch (state_) {
case kStarting:
@@ -227,11 +253,6 @@ void AudioOutputController::DoPause() {
case kPlaying:
state_ = kPaused;
- // Then we stop the audio device. This is not the perfect solution
- // because it discards all the internal buffer in the audio device.
- // TODO(hclam): Actually pause the audio device.
- stream_->Stop();
-
// Send a special pause mark to the low-latency audio thread.
sync_reader_->UpdatePendingBytes(kPauseMark);
@@ -306,11 +327,11 @@ void AudioOutputController::WaitTillDataReady() {
if (!sync_reader_->DataReady()) {
// In the different place we use different mechanism to poll, get max
// polling delay from constants used there.
- const base::TimeDelta kMaxPollingDelay = base::TimeDelta::FromMilliseconds(
+ const base::TimeDelta kMaxPollingDelay = TimeDelta::FromMilliseconds(
kPollNumAttempts * kPollPauseInMilliseconds);
Time start_time = Time::Now();
do {
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
+ base::PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
} while (!sync_reader_->DataReady() &&
Time::Now() - start_time < kMaxPollingDelay);
}