summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authormiu@chromium.org <miu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-04 09:53:29 +0000
committermiu@chromium.org <miu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-04 09:53:29 +0000
commit5ff11135bfe657fab30536b393522ba9b9b9a7bf (patch)
treefd5d16f744cc8d356e136f50c623332c2a93c818 /media
parentc97dfc681180e48f4408c8121293cd4ea64bc41c (diff)
downloadchromium_src-5ff11135bfe657fab30536b393522ba9b9b9a7bf.zip
chromium_src-5ff11135bfe657fab30536b393522ba9b9b9a7bf.tar.gz
chromium_src-5ff11135bfe657fab30536b393522ba9b9b9a7bf.tar.bz2
Associate audio streams with their source/destination RenderView.
This is a first step towards implementing three major Chromium features, all of which need to associate audio outputs with their source tabs. See BUGs referenced by this change for more details. Previous attempt/approach: https://codereview.chromium.org/11166002/ Specifics: 1. Added two new IPC messages: AudioHostMsg_AssociateStreamWithProducer and AudioInputHostMsg_AssociateStreamWithConsumer. 2. Added "associate to render_view_id" IPC calls: PepperPlatformAudioInputImpl, PepperPlatformAudioOutputImpl, RenderAudioSourceProvider, RendererWebAudioDeviceImpl, WebRtcAudioRenderer. 3. AudioOutputDevice instances re-use the same stream IDs. 4. Removed AudioDeviceFactory and replaced test-injection scheme in AudioRendererMixerManager. Not in scope: 1. Associating RenderViews with audio input to WebRTC. 2. Associating RenderViews with streams produced by the AudioRendererMixer. 3. Speech Input (implementation is in the browser process, not the render process). Testing method: Confirm correct render_view_id shows up in debug logging when engaging the various audio code paths. Some of the many test sites used: 1. PPAPI (in and out): http://www.midomi.com/index.php?action=main.mic_check 2. WebMediaPlayer (e.g., <audio> and <video>): http://html5video.org/ 3. WebAudio API: http://chromium.googlecode.com/svn/trunk/samples/audio/convolution-effects.html 4. WebRTC (output only): http://apprtc.appspot.com/ BUG=3541,64215,153392 TEST=Enabled debug logging via --vmodule=audio_renderer_host=1,audio_input_renderer_host=1 and then engaged the various Chrome audio code paths to confirm correct render_view_id shows up in browser process. Review URL: https://chromiumcodereview.appspot.com/11359196 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@170919 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/audio/audio_output_device.cc66
-rw-r--r--media/audio/audio_output_device.h25
-rw-r--r--media/audio/audio_output_device_unittest.cc44
3 files changed, 68 insertions, 67 deletions
diff --git a/media/audio/audio_output_device.cc b/media/audio/audio_output_device.cc
index d09e32c4..567c2f6 100644
--- a/media/audio/audio_output_device.cc
+++ b/media/audio/audio_output_device.cc
@@ -47,20 +47,16 @@ AudioOutputDevice::AudioOutputDevice(
input_channels_(0),
callback_(NULL),
ipc_(ipc),
- stream_id_(0),
+ state_(IDLE),
play_on_start_(true),
- is_started_(false),
stopping_hack_(false) {
CHECK(ipc_);
+ stream_id_ = ipc_->AddDelegate(this);
}
void AudioOutputDevice::Initialize(const AudioParameters& params,
RenderCallback* callback) {
- CHECK_EQ(0, stream_id_) <<
- "AudioOutputDevice::Initialize() must be called before Start()";
-
- CHECK(!callback_); // Calling Initialize() twice?
-
+ DCHECK(!callback_) << "Calling Initialize() twice?";
audio_parameters_ = params;
callback_ = callback;
}
@@ -77,7 +73,10 @@ void AudioOutputDevice::InitializeIO(const AudioParameters& params,
AudioOutputDevice::~AudioOutputDevice() {
// The current design requires that the user calls Stop() before deleting
// this class.
- CHECK_EQ(0, stream_id_);
+ DCHECK(audio_thread_.IsStopped());
+
+ if (ipc_)
+ ipc_->RemoveDelegate(stream_id_);
}
void AudioOutputDevice::Start() {
@@ -123,49 +122,44 @@ bool AudioOutputDevice::SetVolume(double volume) {
void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params,
int input_channels) {
DCHECK(message_loop()->BelongsToCurrentThread());
- // Make sure we don't create the stream more than once.
- DCHECK_EQ(0, stream_id_);
- if (stream_id_)
- return;
-
- stream_id_ = ipc_->AddDelegate(this);
- ipc_->CreateStream(stream_id_, params, input_channels);
+ if (state_ == IDLE) {
+ state_ = CREATING_STREAM;
+ ipc_->CreateStream(stream_id_, params, input_channels);
+ }
}
void AudioOutputDevice::PlayOnIOThread() {
DCHECK(message_loop()->BelongsToCurrentThread());
- if (stream_id_ && is_started_)
+ if (state_ == PAUSED) {
ipc_->PlayStream(stream_id_);
- else
+ state_ = PLAYING;
+ play_on_start_ = false;
+ } else {
play_on_start_ = true;
+ }
}
void AudioOutputDevice::PauseOnIOThread(bool flush) {
DCHECK(message_loop()->BelongsToCurrentThread());
- if (stream_id_ && is_started_) {
+ if (state_ == PLAYING) {
ipc_->PauseStream(stream_id_);
if (flush)
ipc_->FlushStream(stream_id_);
+ state_ = PAUSED;
} else {
// Note that |flush| isn't relevant here since this is the case where
// the stream is first starting.
- play_on_start_ = false;
}
+ play_on_start_ = false;
}
void AudioOutputDevice::ShutDownOnIOThread() {
DCHECK(message_loop()->BelongsToCurrentThread());
// Make sure we don't call shutdown more than once.
- if (stream_id_) {
- is_started_ = false;
-
- if (ipc_) {
- ipc_->CloseStream(stream_id_);
- ipc_->RemoveDelegate(stream_id_);
- }
-
- stream_id_ = 0;
+ if (state_ >= CREATING_STREAM) {
+ ipc_->CloseStream(stream_id_);
+ state_ = IDLE;
}
// We can run into an issue where ShutDownOnIOThread is called right after
@@ -185,7 +179,7 @@ void AudioOutputDevice::ShutDownOnIOThread() {
void AudioOutputDevice::SetVolumeOnIOThread(double volume) {
DCHECK(message_loop()->BelongsToCurrentThread());
- if (stream_id_)
+ if (state_ >= PAUSED)
ipc_->SetVolume(stream_id_, volume);
}
@@ -193,7 +187,7 @@ void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegate::State state) {
DCHECK(message_loop()->BelongsToCurrentThread());
// Do nothing if the stream has been closed.
- if (!stream_id_)
+ if (state_ < CREATING_STREAM)
return;
if (state == AudioOutputIPCDelegate::kError) {
@@ -222,12 +216,8 @@ void AudioOutputDevice::OnStreamCreated(
DCHECK_GE(socket_handle, 0);
#endif
- // We should only get this callback if stream_id_ is valid. If it is not,
- // the IPC layer should have closed the shared memory and socket handles
- // for us and not invoked the callback. The basic assertion is that when
- // stream_id_ is 0 the AudioOutputDevice instance is not registered as a
- // delegate and hence it should not receive callbacks.
- DCHECK(stream_id_);
+ if (state_ != CREATING_STREAM)
+ return;
// We can receive OnStreamCreated() on the IO thread after the client has
// called Stop() but before ShutDownOnIOThread() is processed. In such a
@@ -250,15 +240,17 @@ void AudioOutputDevice::OnStreamCreated(
audio_parameters_, input_channels_, handle, length, callback_));
audio_thread_.Start(audio_callback_.get(), socket_handle,
"AudioOutputDevice");
+ state_ = PAUSED;
// We handle the case where Play() and/or Pause() may have been called
// multiple times before OnStreamCreated() gets called.
- is_started_ = true;
if (play_on_start_)
PlayOnIOThread();
}
void AudioOutputDevice::OnIPCClosed() {
+ DCHECK(message_loop()->BelongsToCurrentThread());
+ state_ = IPC_CLOSED;
ipc_ = NULL;
}
diff --git a/media/audio/audio_output_device.h b/media/audio/audio_output_device.h
index fe4459c..6650028 100644
--- a/media/audio/audio_output_device.h
+++ b/media/audio/audio_output_device.h
@@ -99,8 +99,6 @@ class MEDIA_EXPORT AudioOutputDevice
// Creates an uninitialized AudioOutputDevice. Clients must call Initialize()
// before using.
- // TODO(tommi): When all dependencies on |content| have been removed
- // from AudioOutputDevice, move this class over to media/audio.
AudioOutputDevice(AudioOutputIPC* ipc,
const scoped_refptr<base::MessageLoopProxy>& io_loop);
@@ -110,7 +108,20 @@ class MEDIA_EXPORT AudioOutputDevice
friend class base::RefCountedThreadSafe<AudioOutputDevice>;
virtual ~AudioOutputDevice();
+ // Accessors for subclasses (via IO thread only).
+ int stream_id() const { return stream_id_; }
+ AudioOutputIPC* audio_output_ipc() const { return ipc_; }
+
private:
+ // Note: The ordering of members in this enum is critical to correct behavior!
+ enum State {
+ IPC_CLOSED, // No more IPCs can take place.
+ IDLE, // Not started.
+ CREATING_STREAM, // Waiting for OnStreamCreated() to be called back.
+ PAUSED, // Paused. OnStreamCreated() has been called. Can Play()/Stop().
+ PLAYING, // Playing back. Can Pause()/Stop().
+ };
+
// Methods called on IO thread ----------------------------------------------
// The following methods are tasks posted on the IO thread that needs to
// be executed on that thread. They interact with AudioMessageFilter and
@@ -142,15 +153,13 @@ class MEDIA_EXPORT AudioOutputDevice
// Must only be modified on the IO thread.
int stream_id_;
+ // Current state (must only be accessed from the IO thread). See comments for
+ // State enum above.
+ State state_;
+
// State of Play() / Pause() calls before OnStreamCreated() is called.
bool play_on_start_;
- // Set to |true| when OnStreamCreated() is called.
- // Set to |false| when ShutDownOnIOThread() is called.
- // This is for use with play_on_start_ to track Play() / Pause() state.
- // Must only be touched from the IO thread.
- bool is_started_;
-
// Our audio thread callback class. See source file for details.
class AudioThreadCallback;
diff --git a/media/audio/audio_output_device_unittest.cc b/media/audio/audio_output_device_unittest.cc
index 3952cf3..70e2a49 100644
--- a/media/audio/audio_output_device_unittest.cc
+++ b/media/audio/audio_output_device_unittest.cc
@@ -96,19 +96,9 @@ class AudioOutputDeviceTest
: public testing::Test,
public testing::WithParamInterface<bool> {
public:
- AudioOutputDeviceTest()
- : default_audio_parameters_(AudioParameters::AUDIO_PCM_LINEAR,
- CHANNEL_LAYOUT_STEREO,
- 48000, 16, 1024),
- audio_device_(new AudioOutputDevice(
- &audio_output_ipc_, io_loop_.message_loop_proxy())),
- synchronized_io_(GetParam()),
- input_channels_(synchronized_io_ ? 2 : 0) {
- }
-
- ~AudioOutputDeviceTest() {}
+ AudioOutputDeviceTest();
+ ~AudioOutputDeviceTest();
- void Initialize();
void StartAudioDevice();
void CreateStream();
void ExpectRenderCallback();
@@ -157,7 +147,18 @@ int AudioOutputDeviceTest::CalculateMemorySize() {
return TotalSharedMemorySizeInBytes(io_buffer_size);
}
-void AudioOutputDeviceTest::Initialize() {
+AudioOutputDeviceTest::AudioOutputDeviceTest()
+ : default_audio_parameters_(AudioParameters::AUDIO_PCM_LINEAR,
+ CHANNEL_LAYOUT_STEREO,
+ 48000, 16, 1024),
+ synchronized_io_(GetParam()),
+ input_channels_(synchronized_io_ ? 2 : 0) {
+ EXPECT_CALL(audio_output_ipc_, AddDelegate(_))
+ .WillOnce(Return(kStreamId));
+
+ audio_device_ = new AudioOutputDevice(
+ &audio_output_ipc_, io_loop_.message_loop_proxy());
+
if (synchronized_io_) {
audio_device_->InitializeIO(default_audio_parameters_,
input_channels_,
@@ -169,11 +170,15 @@ void AudioOutputDeviceTest::Initialize() {
io_loop_.RunUntilIdle();
}
+AudioOutputDeviceTest::~AudioOutputDeviceTest() {
+ EXPECT_CALL(audio_output_ipc_, RemoveDelegate(kStreamId));
+
+ audio_device_ = NULL;
+}
+
void AudioOutputDeviceTest::StartAudioDevice() {
audio_device_->Start();
- EXPECT_CALL(audio_output_ipc_, AddDelegate(audio_device_.get()))
- .WillOnce(Return(kStreamId));
EXPECT_CALL(audio_output_ipc_, CreateStream(kStreamId, _, _));
io_loop_.RunUntilIdle();
@@ -245,26 +250,24 @@ void AudioOutputDeviceTest::StopAudioDevice() {
audio_device_->Stop();
EXPECT_CALL(audio_output_ipc_, CloseStream(kStreamId));
- EXPECT_CALL(audio_output_ipc_, RemoveDelegate(kStreamId));
io_loop_.RunUntilIdle();
}
TEST_P(AudioOutputDeviceTest, Initialize) {
- Initialize();
+ // Tests that the object can be constructed, initialized and destructed
+ // without having ever been started/stopped.
}
// Calls Start() followed by an immediate Stop() and check for the basic message
// filter messages being sent in that case.
TEST_P(AudioOutputDeviceTest, StartStop) {
- Initialize();
StartAudioDevice();
StopAudioDevice();
}
// AudioOutputDevice supports multiple start/stop sequences.
TEST_P(AudioOutputDeviceTest, StartStopStartStop) {
- Initialize();
StartAudioDevice();
StopAudioDevice();
StartAudioDevice();
@@ -274,7 +277,6 @@ TEST_P(AudioOutputDeviceTest, StartStopStartStop) {
// Simulate receiving OnStreamCreated() prior to processing ShutDownOnIOThread()
// on the IO loop.
TEST_P(AudioOutputDeviceTest, StopBeforeRender) {
- Initialize();
StartAudioDevice();
// Call Stop() but don't run the IO loop yet.
@@ -283,13 +285,11 @@ TEST_P(AudioOutputDeviceTest, StopBeforeRender) {
// Expect us to shutdown IPC but not to render anything despite the stream
// getting created.
EXPECT_CALL(audio_output_ipc_, CloseStream(kStreamId));
- EXPECT_CALL(audio_output_ipc_, RemoveDelegate(kStreamId));
CreateStream();
}
// Full test with output only.
TEST_P(AudioOutputDeviceTest, CreateStream) {
- Initialize();
StartAudioDevice();
ExpectRenderCallback();
CreateStream();