summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorxians@chromium.org <xians@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-20 17:28:44 +0000
committerxians@chromium.org <xians@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-20 17:28:44 +0000
commit855cb828e518efd40ac97d08107ad58d996698be (patch)
tree1a28a6429c873ac637362ebcc8000011095c5779 /content
parenta42a7ee454165d73e161448383cdf3dc3b1f164a (diff)
downloadchromium_src-855cb828e518efd40ac97d08107ad58d996698be.zip
chromium_src-855cb828e518efd40ac97d08107ad58d996698be.tar.gz
chromium_src-855cb828e518efd40ac97d08107ad58d996698be.tar.bz2
Hooking up AudioInputDeviceManager to AudioInputRendererHost and MediaStreamManager.
Review URL: http://codereview.chromium.org/7462012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@101975 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r--content/browser/renderer_host/media/audio_input_device_manager.cc14
-rw-r--r--content/browser/renderer_host/media/audio_input_device_manager_event_handler.h14
-rw-r--r--content/browser/renderer_host/media/audio_input_device_manager_unittest.cc14
-rw-r--r--content/browser/renderer_host/media/audio_input_renderer_host.cc87
-rw-r--r--content/browser/renderer_host/media/audio_input_renderer_host.h62
-rw-r--r--content/browser/renderer_host/media/media_stream_manager.cc20
-rw-r--r--content/browser/renderer_host/media/media_stream_manager.h5
-rw-r--r--content/common/media/audio_messages.h15
-rw-r--r--content/renderer/media/audio_input_device.cc130
-rw-r--r--content/renderer/media/audio_input_device.h62
-rw-r--r--content/renderer/media/audio_input_message_filter.cc25
-rw-r--r--content/renderer/media/audio_input_message_filter.h15
-rw-r--r--content/renderer/media/webrtc_audio_device_impl.cc38
-rw-r--r--content/renderer/media/webrtc_audio_device_impl.h30
14 files changed, 461 insertions, 70 deletions
diff --git a/content/browser/renderer_host/media/audio_input_device_manager.cc b/content/browser/renderer_host/media/audio_input_device_manager.cc
index 8fafb01..e1970c1 100644
--- a/content/browser/renderer_host/media/audio_input_device_manager.cc
+++ b/content/browser/renderer_host/media/audio_input_device_manager.cc
@@ -11,8 +11,8 @@
namespace media_stream {
-const int AudioInputDeviceManager::kFakeOpenSessionId = 0;
-const int AudioInputDeviceManager::kInvalidSessionId = -1;
+const int AudioInputDeviceManager::kFakeOpenSessionId = 1;
+const int AudioInputDeviceManager::kInvalidSessionId = 0;
const int AudioInputDeviceManager::kInvalidDevice = -1;
const int AudioInputDeviceManager::kDefaultDeviceIndex = 0;
@@ -111,14 +111,14 @@ void AudioInputDeviceManager::Start(
// And we do not store the info for the kFakeOpenSessionId but return
// the callback immediately.
if (session_id == kFakeOpenSessionId) {
- event_handler->OnStartDevice(session_id, kDefaultDeviceIndex);
+ event_handler->OnDeviceStarted(session_id, kDefaultDeviceIndex);
return;
}
// If session has been started, post a callback with an error.
if (event_handlers_.find(session_id) != event_handlers_.end()) {
// Session has been started, post a callback with error.
- event_handler->OnStartDevice(session_id, kInvalidDevice);
+ event_handler->OnDeviceStarted(session_id, kInvalidDevice);
return;
}
@@ -265,7 +265,7 @@ void AudioInputDeviceManager::ClosedOnIOThread(int session_id) {
EventHandlerMap::iterator it = event_handlers_.find(session_id);
if (it != event_handlers_.end()) {
// The device hasn't been stopped, send stop signal.
- it->second->OnStopDevice(session_id);
+ it->second->OnDeviceStopped(session_id);
event_handlers_.erase(session_id);
}
listener_->Closed(kAudioCapture, session_id);
@@ -286,8 +286,8 @@ void AudioInputDeviceManager::StartedOnIOThread(int session_id, int index) {
if (it == event_handlers_.end())
return;
- // Post a callback through the event handler to start the device.
- it->second->OnStartDevice(session_id, index);
+ // Post a callback through the event handler to create an audio stream.
+ it->second->OnDeviceStarted(session_id, index);
}
void AudioInputDeviceManager::StoppedOnIOThread(int session_id) {
diff --git a/content/browser/renderer_host/media/audio_input_device_manager_event_handler.h b/content/browser/renderer_host/media/audio_input_device_manager_event_handler.h
index 75cb984..3790e4e 100644
--- a/content/browser/renderer_host/media/audio_input_device_manager_event_handler.h
+++ b/content/browser/renderer_host/media/audio_input_device_manager_event_handler.h
@@ -12,12 +12,14 @@ namespace media_stream {
class AudioInputDeviceManagerEventHandler {
public:
- // Used to start the device referenced by session id and index.
- virtual void OnStartDevice(int session_id, int index) = 0;
-
- // Used to stop the device referenced by session id. This method is used
- // only when users call Close() without calling Stop() on a started device.
- virtual void OnStopDevice(int session_id) = 0;
+ // Called by AudioInputDeviceManager to create an audio stream using the
+ // device index when the device has been started.
+ virtual void OnDeviceStarted(int session_id, int index) = 0;
+
+ // Called by AudioInputDeviceManager to stop the audio stream when a device
+ // has been stopped. This method is used only when users call Close() without
+ // calling Stop() on a started device.
+ virtual void OnDeviceStopped(int session_id) = 0;
virtual ~AudioInputDeviceManagerEventHandler() {}
};
diff --git a/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc b/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc
index de27d5d..f7cc6ff 100644
--- a/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc
+++ b/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc
@@ -52,8 +52,8 @@ class MockAudioInputDeviceManagerEventHandler
MockAudioInputDeviceManagerEventHandler() {}
virtual ~MockAudioInputDeviceManagerEventHandler() {}
- MOCK_METHOD2(OnStartDevice, void(int, int));
- MOCK_METHOD1(OnStopDevice, void(int));
+ MOCK_METHOD2(OnDeviceStarted, void(int, int));
+ MOCK_METHOD1(OnDeviceStopped, void(int));
private:
DISALLOW_COPY_AND_ASSIGN(MockAudioInputDeviceManagerEventHandler);
@@ -294,7 +294,7 @@ TEST_F(AudioInputDeviceManagerTest, StartAndStopDevice) {
session_id[index]))
.Times(1);
EXPECT_CALL(*audio_input_event_handler,
- OnStartDevice(session_id[index], index))
+ OnDeviceStarted(session_id[index], index))
.Times(1);
EXPECT_CALL(*audio_input_listener_, Closed(kAudioCapture,
session_id[index]))
@@ -332,12 +332,12 @@ TEST_F(AudioInputDeviceManagerTest, CloseWithoutStopDevice) {
session_id[index]))
.Times(1);
EXPECT_CALL(*audio_input_event_handler,
- OnStartDevice(session_id[index], index))
+ OnDeviceStarted(session_id[index], index))
.Times(1);
// Event Handler should get a stop device notification as no stop is called
// before closing the device.
EXPECT_CALL(*audio_input_event_handler,
- OnStopDevice(session_id[index]))
+ OnDeviceStopped(session_id[index]))
.Times(1);
EXPECT_CALL(*audio_input_listener_, Closed(kAudioCapture,
session_id[index]))
@@ -381,10 +381,10 @@ TEST_F(AudioInputDeviceManagerTest, StartDeviceTwice) {
EXPECT_CALL(*audio_input_listener_, Opened(kAudioCapture, second_session_id))
.Times(1);
EXPECT_CALL(*first_audio_input_event_handler,
- OnStartDevice(first_session_id, 0))
+ OnDeviceStarted(first_session_id, 0))
.Times(1);
EXPECT_CALL(*second_audio_input_event_handler,
- OnStartDevice(second_session_id, 0))
+ OnDeviceStarted(second_session_id, 0))
.Times(1);
EXPECT_CALL(*audio_input_listener_, Closed(kAudioCapture, first_session_id))
.Times(1);
diff --git a/content/browser/renderer_host/media/audio_input_renderer_host.cc b/content/browser/renderer_host/media/audio_input_renderer_host.cc
index f8b92db..84532ba 100644
--- a/content/browser/renderer_host/media/audio_input_renderer_host.cc
+++ b/content/browser/renderer_host/media/audio_input_renderer_host.cc
@@ -8,7 +8,9 @@
#include "base/process.h"
#include "base/shared_memory.h"
#include "content/browser/renderer_host/media/audio_common.h"
+#include "content/browser/renderer_host/media/audio_input_device_manager.h"
#include "content/browser/renderer_host/media/audio_input_sync_writer.h"
+#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/common/media/audio_messages.h"
#include "ipc/ipc_logging.h"
@@ -167,6 +169,7 @@ bool AudioInputRendererHost::OnMessageReceived(const IPC::Message& message,
bool* message_was_ok) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP_EX(AudioInputRendererHost, message, *message_was_ok)
+ IPC_MESSAGE_HANDLER(AudioInputHostMsg_StartDevice, OnStartDevice)
IPC_MESSAGE_HANDLER(AudioInputHostMsg_CreateStream, OnCreateStream)
IPC_MESSAGE_HANDLER(AudioInputHostMsg_RecordStream, OnRecordStream)
IPC_MESSAGE_HANDLER(AudioInputHostMsg_CloseStream, OnCloseStream)
@@ -177,6 +180,25 @@ bool AudioInputRendererHost::OnMessageReceived(const IPC::Message& message,
return handled;
}
+void AudioInputRendererHost::OnStartDevice(int stream_id, int session_id) {
+ VLOG(1) << "AudioInputRendererHost::OnStartDevice(stream_id="
+ << stream_id << ", session_id = " << session_id << ")";
+
+ // Get access to the AudioInputDeviceManager to start the device.
+ // TODO(mflodman): Get AudioInputDeviceManager from MediaStreamManager.
+ media_stream::AudioInputDeviceManager* audio_input_man = NULL;
+ if (!audio_input_man) {
+ SendErrorMessage(stream_id);
+ return;
+ }
+
+ // Add the session entry to the map.
+ session_entries_[session_id] = stream_id;
+
+ // Start the device with the session_id. If the device is started
+ // successfully, OnDeviceStarted() callback will be triggered.
+ audio_input_man->Start(session_id, this);
+}
void AudioInputRendererHost::OnCreateStream(
int stream_id, const AudioParameters& params, bool low_latency) {
@@ -257,6 +279,11 @@ void AudioInputRendererHost::OnCloseStream(int stream_id) {
if (entry)
CloseAndDeleteStream(entry);
+
+ int session_id = LookupSessionById(stream_id);
+
+ if (session_id)
+ StopAndDeleteDevice(session_id);
}
void AudioInputRendererHost::OnSetVolume(int stream_id, double volume) {
@@ -300,6 +327,54 @@ void AudioInputRendererHost::DeleteEntries() {
}
}
+void AudioInputRendererHost::OnDeviceStarted(int session_id, int index) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ SessionEntryMap::iterator it = session_entries_.find(session_id);
+ if (it == session_entries_.end()) {
+ DLOG(WARNING) << "AudioInputRendererHost::OnDeviceStarted()"
+ " session does not exist.";
+ return;
+ }
+
+ // Notify the renderer that the device has been started.
+ Send(new AudioInputMsg_NotifyDeviceStarted(it->second, index));
+}
+
+void AudioInputRendererHost::OnDeviceStopped(int session_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ SessionEntryMap::iterator it = session_entries_.find(session_id);
+ // Return if the stream has been closed.
+ if (it == session_entries_.end())
+ return;
+
+ int stream_id = it->second;
+ AudioEntry* entry = LookupById(stream_id);
+
+ if (entry) {
+ // Device has been stopped, close the input stream.
+ CloseAndDeleteStream(entry);
+ // Notify the renderer that the state of the input stream has changed.
+ Send(new AudioInputMsg_NotifyStreamStateChanged(stream_id,
+ kAudioStreamPaused));
+ }
+
+ // Delete the session entry.
+ session_entries_.erase(it);
+}
+
+void AudioInputRendererHost::StopAndDeleteDevice(int session_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ // TODO(mflodman): Get AudioInputDeviceManager from MediaStreamManager.
+ media_stream::AudioInputDeviceManager* audio_input_man = NULL;
+ if (audio_input_man)
+ audio_input_man->Stop(session_id);
+
+ // Delete the session entry.
+ session_entries_.erase(session_id);
+}
+
void AudioInputRendererHost::CloseAndDeleteStream(AudioEntry* entry) {
if (!entry->pending_close) {
entry->pending_close = true;
@@ -360,3 +435,15 @@ AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupByController(
}
return NULL;
}
+
+int AudioInputRendererHost::LookupSessionById(int stream_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ for (SessionEntryMap::iterator it = session_entries_.begin();
+ it != session_entries_.end(); ++it) {
+ if (stream_id == it->second) {
+ return it->first;
+ }
+ }
+ return 0;
+}
diff --git a/content/browser/renderer_host/media/audio_input_renderer_host.h b/content/browser/renderer_host/media/audio_input_renderer_host.h
index 5fde275..94ef85e 100644
--- a/content/browser/renderer_host/media/audio_input_renderer_host.h
+++ b/content/browser/renderer_host/media/audio_input_renderer_host.h
@@ -5,6 +5,42 @@
// AudioInputRendererHost serves audio related requests from audio capturer
// which lives inside the render process and provide access to audio hardware.
//
+// OnCreateStream() request is only available in the low latency mode. It will
+// creates a shared memory, a SyncWriter and a AudioInputController for the
+// input stream.
+
+// OnCloseStream() will close the input stream.
+//
+// Create stream sequence:
+//
+// OnCreateStream -> AudioInputController::CreateLowLatency() ->
+// DoCompleteCreation -> AudioInputMsg_NotifyLowLatencyStreamCreated
+//
+// Close stream sequence:
+// OnCloseStream -> AudioInputController::Close
+//
+// For the OnStartDevice() request, AudioInputRendererHost starts the device
+// referenced by the session id, and a OnDeviceStarted() callback with the
+// index of the opened device will be received later. Then it will send a IPC
+// message to notify the renderer that the device is ready, so that renderer
+// can continue with the OnCreateStream() request.
+//
+// OnDeviceStopped() is called when the user closes the device through
+// AudioInputDeviceManager without calling Stop() before. What
+// AudioInputRenderHost::OnDeviceStopped() does is to send a IPC mesaage to
+// notify the renderer in order to stop the stream.
+//
+// Start device sequence:
+//
+// OnStartDevice -> AudioInputDeviceManager::Start ->
+// AudioInputDeviceManagerEventHandler::OnDeviceStarted ->
+// AudioInputMsg_NotifyDeviceStarted
+//
+// Shutdown device sequence:
+//
+// OnDeviceStopped -> CloseAndDeleteStream
+// AudioInputMsg_NotifyStreamStateChanged
+//
// This class is owned by BrowserRenderProcessHost and instantiated on UI
// thread. All other operations and method calls happen on IO thread, so we
// need to be extra careful about the lifetime of this object. AudioManager is a
@@ -28,6 +64,7 @@
#include "base/shared_memory.h"
#include "content/browser/browser_message_filter.h"
#include "content/browser/browser_thread.h"
+#include "content/browser/renderer_host/media/audio_input_device_manager_event_handler.h"
#include "media/audio/audio_input_controller.h"
#include "media/audio/audio_io.h"
#include "media/audio/simple_sources.h"
@@ -37,7 +74,8 @@ struct AudioParameters;
class AudioInputRendererHost
: public BrowserMessageFilter,
- public media::AudioInputController::EventHandler {
+ public media::AudioInputController::EventHandler,
+ public media_stream::AudioInputDeviceManagerEventHandler {
public:
struct AudioEntry {
AudioEntry();
@@ -60,8 +98,6 @@ class AudioInputRendererHost
bool pending_close;
};
- typedef std::map<int, AudioEntry*> AudioEntryMap;
-
// Called from UI thread from the owner of this object.
AudioInputRendererHost();
@@ -80,6 +116,10 @@ class AudioInputRendererHost
const uint8* data,
uint32 size);
+ // media_stream::AudioInputDeviceManagerEventHandler implementation.
+ virtual void OnDeviceStarted(int session_id, int index);
+ virtual void OnDeviceStopped(int session_id);
+
private:
// TODO(henrika): extend test suite (compare AudioRenderHost)
friend class BrowserThread;
@@ -89,6 +129,10 @@ class AudioInputRendererHost
// Methods called on IO thread ----------------------------------------------
+ // Start the audio input device with the session id. If the device
+ // starts successfully, it will trigger OnDeviceStarted() callback.
+ void OnStartDevice(int stream_id, int session_id);
+
// Audio related IPC message handlers.
// Creates an audio input stream with the specified format. If this call is
// successful this object would keep an internal entry of the stream for the
@@ -139,6 +183,9 @@ class AudioInputRendererHost
// Delete audio entry and close the related audio input stream.
void DeleteEntryOnError(AudioEntry* entry);
+ // Stop the device and delete its audio session entry.
+ void StopAndDeleteDevice(int stream_id);
+
// A helper method to look up a AudioEntry identified by |stream_id|.
// Returns NULL if not found.
AudioEntry* LookupById(int stream_id);
@@ -148,9 +195,18 @@ class AudioInputRendererHost
// event is received.
AudioEntry* LookupByController(media::AudioInputController* controller);
+ // A helper method to look up a session identified by |stream_id|.
+ // Returns 0 if not found.
+ int LookupSessionById(int stream_id);
+
// A map of stream IDs to audio sources.
+ typedef std::map<int, AudioEntry*> AudioEntryMap;
AudioEntryMap audio_entries_;
+ // A map of session IDs to audio session sources.
+ typedef std::map<int, int> SessionEntryMap;
+ SessionEntryMap session_entries_;
+
DISALLOW_COPY_AND_ASSIGN(AudioInputRendererHost);
};
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 786cb26..3348a1b9 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -17,7 +17,7 @@
namespace media_stream {
-// TODO(mflodman) Find out who should own MediaStreamManager.
+// TODO(mflodman): Find out who should own MediaStreamManager.
base::LazyInstance<MediaStreamManager> g_media_stream_manager(
base::LINKER_INITIALIZED);
@@ -63,6 +63,12 @@ VideoCaptureManager* MediaStreamManager::video_capture_manager() {
return video_capture_manager_;
}
+AudioInputDeviceManager* MediaStreamManager::audio_input_device_manager() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // TODO(mflodman): Add when audio input manager is available.
+ return NULL;
+}
+
void MediaStreamManager::GenerateStream(MediaStreamRequester* requester,
int render_process_id,
int render_view_id,
@@ -71,7 +77,7 @@ void MediaStreamManager::GenerateStream(MediaStreamRequester* requester,
std::string* label) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- // TODO(mflodman) Remove next line when audio is supported.
+ // TODO(mflodman): Remove next line when audio is supported.
(const_cast<StreamOptions&>(options)).audio = false;
// Create a new request based on options.
@@ -111,7 +117,7 @@ void MediaStreamManager::CancelRequests(MediaStreamRequester* requester) {
request->audio_devices.begin(); it != request->audio_devices.end();
++it) {
if (it->in_use == true) {
- // TODO(mflodman) Add when audio input device manager is available.
+ // TODO(mflodman): Add when audio input device manager is available.
}
}
}
@@ -139,7 +145,7 @@ void MediaStreamManager::StopGeneratedStream(const std::string& label) {
for (StreamDeviceInfoArray::iterator audio_it =
it->second.audio_devices.begin();
audio_it != it->second.audio_devices.end(); ++audio_it) {
- // TODO(mflodman) Add code when audio input manager exists.
+ // TODO(mflodman): Add code when audio input manager exists.
NOTREACHED();
}
for (StreamDeviceInfoArray::iterator video_it =
@@ -356,7 +362,7 @@ void MediaStreamManager::UseFakeDevice() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
video_capture_manager_->UseFakeDevice();
device_settings_->UseFakeUI();
- // TODO(mflodman) Add audio manager when available.
+ // TODO(mflodman): Add audio manager when available.
}
bool MediaStreamManager::RequestDone(const DeviceRequest& request) const {
@@ -389,7 +395,7 @@ MediaStreamProvider* MediaStreamManager::GetDeviceManager(
if (stream_type == kVideoCapture) {
return video_capture_manager_;
} else if (stream_type == kAudioCapture) {
- // TODO(mflodman) Add support when audio input manager is available.
+ // TODO(mflodman): Add support when audio input manager is available.
NOTREACHED();
return NULL;
}
@@ -404,7 +410,7 @@ MediaStreamManager::MediaStreamManager()
device_settings_(NULL) {
device_settings_ = new MediaStreamDeviceSettings(this);
video_capture_manager_->Register(this);
- // TODO(mflodman) Add when audio input manager is available.
+ // TODO(mflodman): Add when audio input manager is available.
}
MediaStreamManager::DeviceRequest::DeviceRequest()
diff --git a/content/browser/renderer_host/media/media_stream_manager.h b/content/browser/renderer_host/media/media_stream_manager.h
index f5792ce..27fea0c 100644
--- a/content/browser/renderer_host/media/media_stream_manager.h
+++ b/content/browser/renderer_host/media/media_stream_manager.h
@@ -30,6 +30,7 @@
namespace media_stream {
+class AudioInputDeviceManager;
class MediaStreamDeviceSettings;
class MediaStreamRequester;
class VideoCaptureManager;
@@ -49,6 +50,9 @@ class MediaStreamManager
// Used to access VideoCaptuerManager.
VideoCaptureManager* video_capture_manager();
+ // Used to access AudioInputDeviceManager.
+ AudioInputDeviceManager* audio_input_device_manager();
+
// GenerateStream opens new media devices according to |components|. The
// request is identified using |label|, which is pointing to an already
// created std::string.
@@ -113,7 +117,6 @@ class MediaStreamManager
MediaStreamManager();
VideoCaptureManager* video_capture_manager_;
- // TODO(mflodman) Add AudioInputManager.
// Keeps track of device types currently being enumerated to not enumerate
// when not necessary.
diff --git a/content/common/media/audio_messages.h b/content/common/media/audio_messages.h
index 7a7fde4..3499258 100644
--- a/content/common/media/audio_messages.h
+++ b/content/common/media/audio_messages.h
@@ -88,6 +88,11 @@ IPC_MESSAGE_CONTROL2(AudioMsg_NotifyStreamStateChanged,
int /* stream id */,
AudioStreamState /* new state */)
+// Notification message sent from browser to renderer for state update.
+IPC_MESSAGE_CONTROL2(AudioInputMsg_NotifyStreamStateChanged,
+ int /* stream id */,
+ AudioStreamState /* new state */)
+
IPC_MESSAGE_CONTROL2(AudioMsg_NotifyStreamVolume,
int /* stream id */,
double /* volume */)
@@ -96,6 +101,10 @@ IPC_MESSAGE_CONTROL2(AudioInputMsg_NotifyStreamVolume,
int /* stream id */,
double /* volume */)
+IPC_MESSAGE_CONTROL2(AudioInputMsg_NotifyDeviceStarted,
+ int /* stream id */,
+ int /* device_index */)
+
// Messages sent from the renderer to the browser.
// Request that got sent to browser for creating an audio output stream
@@ -159,3 +168,9 @@ IPC_MESSAGE_CONTROL2(AudioHostMsg_SetVolume,
IPC_MESSAGE_CONTROL2(AudioInputHostMsg_SetVolume,
int /* stream_id */,
double /* volume */)
+
+// Start the device referenced by the session_id for the input stream specified
+// by stream_id.
+IPC_MESSAGE_CONTROL2(AudioInputHostMsg_StartDevice,
+ int /* stream_id */,
+ int /* session_id */)
diff --git a/content/renderer/media/audio_input_device.cc b/content/renderer/media/audio_input_device.cc
index 8b87a3e..7e5f532 100644
--- a/content/renderer/media/audio_input_device.cc
+++ b/content/renderer/media/audio_input_device.cc
@@ -15,17 +15,22 @@
AudioInputDevice::AudioInputDevice(size_t buffer_size,
int channels,
double sample_rate,
- CaptureCallback* callback)
- : buffer_size_(buffer_size),
- channels_(channels),
- bits_per_sample_(16),
- sample_rate_(sample_rate),
- callback_(callback),
+ CaptureCallback* callback,
+ CaptureEventHandler* event_handler)
+ : callback_(callback),
+ event_handler_(event_handler),
audio_delay_milliseconds_(0),
volume_(1.0),
- stream_id_(0) {
+ stream_id_(0),
+ session_id_(0),
+ pending_device_ready_(false) {
filter_ = RenderThread::current()->audio_input_message_filter();
audio_data_.reserve(channels);
+ audio_parameters_.format = AudioParameters::AUDIO_PCM_LINEAR;
+ audio_parameters_.channels = channels;
+ audio_parameters_.sample_rate = static_cast<int>(sample_rate);
+ audio_parameters_.bits_per_sample = 16;
+ audio_parameters_.samples_per_packet = buffer_size;
for (int i = 0; i < channels; ++i) {
float* channel_data = new float[buffer_size];
audio_data_.push_back(channel_data);
@@ -36,23 +41,23 @@ AudioInputDevice::~AudioInputDevice() {
// TODO(henrika): The current design requires that the user calls
// Stop before deleting this class.
CHECK_EQ(0, stream_id_);
- for (int i = 0; i < channels_; ++i)
+ for (int i = 0; i < audio_parameters_.channels; ++i)
delete [] audio_data_[i];
}
void AudioInputDevice::Start() {
VLOG(1) << "Start()";
- AudioParameters params;
- // TODO(henrika): add support for low-latency mode?
- params.format = AudioParameters::AUDIO_PCM_LINEAR;
- params.channels = channels_;
- params.sample_rate = static_cast<int>(sample_rate_);
- params.bits_per_sample = bits_per_sample_;
- params.samples_per_packet = buffer_size_;
+ ChildProcess::current()->io_message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &AudioInputDevice::InitializeOnIOThread));
+}
+void AudioInputDevice::SetDevice(int session_id) {
+ VLOG(1) << "SetDevice (session_id=" << session_id << ")";
ChildProcess::current()->io_message_loop()->PostTask(
FROM_HERE,
- NewRunnableMethod(this, &AudioInputDevice::InitializeOnIOThread, params));
+ NewRunnableMethod(this, &AudioInputDevice::SetSessionIdOnIOThread,
+ session_id));
}
bool AudioInputDevice::Stop() {
@@ -99,7 +104,7 @@ bool AudioInputDevice::GetVolume(double* volume) {
return false;
}
-void AudioInputDevice::InitializeOnIOThread(const AudioParameters& params) {
+void AudioInputDevice::InitializeOnIOThread() {
DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
// Make sure we don't call Start() more than once.
DCHECK_EQ(0, stream_id_);
@@ -107,7 +112,21 @@ void AudioInputDevice::InitializeOnIOThread(const AudioParameters& params) {
return;
stream_id_ = filter_->AddDelegate(this);
- Send(new AudioInputHostMsg_CreateStream(stream_id_, params, true));
+ // If |session_id_| is not specified, it will directly create the stream;
+ // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser
+ // and create the stream when getting a OnDeviceReady() callback.
+ if (!session_id_) {
+ Send(new AudioInputHostMsg_CreateStream(stream_id_, audio_parameters_,
+ true));
+ } else {
+ Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id_));
+ pending_device_ready_ = true;
+ }
+}
+
+void AudioInputDevice::SetSessionIdOnIOThread(int session_id) {
+ DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
+ session_id_ = session_id;
}
void AudioInputDevice::StartOnIOThread() {
@@ -126,7 +145,10 @@ void AudioInputDevice::ShutDownOnIOThread(base::WaitableEvent* completion) {
filter_->RemoveDelegate(stream_id_);
Send(new AudioInputHostMsg_CloseStream(stream_id_));
+
stream_id_ = 0;
+ session_id_ = 0;
+ pending_device_ready_ = false;
completion->Signal();
}
@@ -178,6 +200,65 @@ void AudioInputDevice::OnVolume(double volume) {
NOTIMPLEMENTED();
}
+void AudioInputDevice::OnStateChanged(AudioStreamState state) {
+ DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
+ switch (state) {
+ case kAudioStreamPaused:
+ // Do nothing if the stream has been closed.
+ if (!stream_id_)
+ return;
+
+ filter_->RemoveDelegate(stream_id_);
+
+ // Joining the audio thread will be quite soon, since the stream has
+ // been closed before.
+ if (audio_thread_.get()) {
+ socket_->Close();
+ audio_thread_->Join();
+ audio_thread_.reset(NULL);
+ }
+
+ if (event_handler_)
+ event_handler_->OnDeviceStopped();
+
+ stream_id_ = 0;
+ pending_device_ready_ = false;
+ break;
+ case kAudioStreamPlaying:
+ NOTIMPLEMENTED();
+ break;
+ case kAudioStreamError:
+ DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)";
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+void AudioInputDevice::OnDeviceReady(int index) {
+ DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
+ VLOG(1) << "OnDeviceReady (index=" << index << ")";
+
+ // Takes care of the case when Stop() is called before OnDeviceReady().
+ if (!pending_device_ready_)
+ return;
+
+ // -1 means no device has been started.
+ if (index == -1) {
+ filter_->RemoveDelegate(stream_id_);
+ stream_id_ = 0;
+ } else {
+ Send(new AudioInputHostMsg_CreateStream(
+ stream_id_, audio_parameters_, true));
+ }
+
+ pending_device_ready_ = false;
+ // Notify the client that the device has been started.
+ if (event_handler_)
+ event_handler_->OnDeviceStarted(index);
+}
+
void AudioInputDevice::Send(IPC::Message* message) {
filter_->Send(message);
}
@@ -188,8 +269,10 @@ void AudioInputDevice::Run() {
audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio);
int pending_data;
- const int samples_per_ms = static_cast<int>(sample_rate_) / 1000;
- const int bytes_per_ms = channels_ * (bits_per_sample_ / 8) * samples_per_ms;
+ const int samples_per_ms =
+ static_cast<int>(audio_parameters_.sample_rate) / 1000;
+ const int bytes_per_ms = audio_parameters_.channels *
+ (audio_parameters_.bits_per_sample / 8) * samples_per_ms;
while (sizeof(pending_data) == socket_->Receive(&pending_data,
sizeof(pending_data)) &&
@@ -209,7 +292,7 @@ void AudioInputDevice::FireCaptureCallback() {
if (!callback_)
return;
- const size_t number_of_frames = buffer_size_;
+ const size_t number_of_frames = audio_parameters_.samples_per_packet;
// Read 16-bit samples from shared memory (browser writes to it).
int16* input_audio = static_cast<int16*>(shared_memory_data());
@@ -217,10 +300,11 @@ void AudioInputDevice::FireCaptureCallback() {
// Deinterleave each channel and convert to 32-bit floating-point
// with nominal range -1.0 -> +1.0.
- for (int channel_index = 0; channel_index < channels_; ++channel_index) {
+ for (int channel_index = 0; channel_index < audio_parameters_.channels;
+ ++channel_index) {
media::DeinterleaveAudioChannel(input_audio,
audio_data_[channel_index],
- channels_,
+ audio_parameters_.channels,
channel_index,
bytes_per_sample,
number_of_frames);
diff --git a/content/renderer/media/audio_input_device.h b/content/renderer/media/audio_input_device.h
index 2418a44..8b65613 100644
--- a/content/renderer/media/audio_input_device.h
+++ b/content/renderer/media/audio_input_device.h
@@ -12,21 +12,35 @@
// | |
// v IPC v
// AudioInputRendererHost <---------> AudioInputMessageFilter
+// ^
+// |
+// v
+// AudioInputDeviceManager
//
// Transportation of audio samples from the browser to the render process
// is done by using shared memory in combination with a sync socket pair
// to generate a low latency transport. The AudioInputDevice user registers
// an AudioInputDevice::CaptureCallback at construction and will be called
// by the AudioInputDevice with recorded audio from the underlying audio layers.
+// The session ID is used by the AudioInputRendererHost to start the device
+// referenced by this ID.
//
// State sequences:
//
// Task [IO thread] IPC [IO thread]
//
+// Sequence where session_id has not been set using SetDevice():
// Start -> InitializeOnIOThread -----> AudioInputHostMsg_CreateStream ------->
// <- OnLowLatencyCreated <- AudioInputMsg_NotifyLowLatencyStreamCreated <-
// ---> StartOnIOThread ---------> AudioInputHostMsg_PlayStream -------->
//
+// Sequence where session_id has been set using SetDevice():
+// Start -> InitializeOnIOThread --> AudioInputHostMsg_StartDevice --->
+// <---- OnStarted <-------------- AudioInputMsg_NotifyDeviceStarted <----
+// -> OnDeviceReady ------------> AudioInputHostMsg_CreateStream ------->
+// <- OnLowLatencyCreated <- AudioInputMsg_NotifyLowLatencyStreamCreated <-
+// ---> StartOnIOThread ---------> AudioInputHostMsg_PlayStream -------->
+//
// AudioInputDevice::Capture => low latency audio transport on audio thread =>
// |
// Stop --> ShutDownOnIOThread ------> AudioInputHostMsg_CloseStream -> Close
@@ -48,6 +62,7 @@
//
// - Start() is asynchronous/non-blocking.
// - Stop() is synchronous/blocking.
+// - SetDevice() is asynchronous/non-blocking.
// - The user must call Stop() before deleting the class instance.
#ifndef CONTENT_RENDERER_MEDIA_AUDIO_INPUT_DEVICE_H_
@@ -61,8 +76,7 @@
#include "base/shared_memory.h"
#include "base/threading/simple_thread.h"
#include "content/renderer/media/audio_input_message_filter.h"
-
-struct AudioParameters;
+#include "media/audio/audio_parameters.h"
// TODO(henrika): This class is based on the AudioDevice class and it has
// many components in common. Investigate potential for re-factoring.
@@ -83,13 +97,32 @@ class AudioInputDevice
virtual ~CaptureCallback() {}
};
+ class CaptureEventHandler {
+ public:
+ // Notification to the client that the device with the specific index has
+ // been started. This callback is triggered as a result of StartDevice().
+ virtual void OnDeviceStarted(int device_index) = 0;
+
+ // Notification to the client that the device has been stopped.
+ virtual void OnDeviceStopped() = 0;
+
+ protected:
+ virtual ~CaptureEventHandler() {}
+ };
+
// Methods called on main render thread -------------------------------------
AudioInputDevice(size_t buffer_size,
int channels,
double sample_rate,
- CaptureCallback* callback);
+ CaptureCallback* callback,
+ CaptureEventHandler* event_handler);
virtual ~AudioInputDevice();
+ // Specify the |session_id| to query which device to use. This method is
+ // asynchronous/non-blocking.
+ // Start() will use the second sequence if this method is called before.
+ void SetDevice(int session_id);
+
// Starts audio capturing. This method is asynchronous/non-blocking.
// TODO(henrika): add support for notification when recording has started.
void Start();
@@ -107,8 +140,8 @@ class AudioInputDevice
// Returns |true| on success.
bool GetVolume(double* volume);
- double sample_rate() const { return sample_rate_; }
- size_t buffer_size() const { return buffer_size_; }
+ double sample_rate() const { return audio_parameters_.sample_rate; }
+ size_t buffer_size() const { return audio_parameters_.samples_per_packet; }
// Methods called on IO thread ----------------------------------------------
// AudioInputMessageFilter::Delegate impl., called by AudioInputMessageFilter
@@ -116,13 +149,16 @@ class AudioInputDevice
base::SyncSocket::Handle socket_handle,
uint32 length);
virtual void OnVolume(double volume);
+ virtual void OnStateChanged(AudioStreamState state);
+ virtual void OnDeviceReady(int index);
private:
// 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 AudioInputMessageFilter and
// sends IPC messages on that thread.
- void InitializeOnIOThread(const AudioParameters& params);
+ void InitializeOnIOThread();
+ void SetSessionIdOnIOThread(int session_id);
void StartOnIOThread();
void ShutDownOnIOThread(base::WaitableEvent* completion);
void SetVolumeOnIOThread(double volume);
@@ -137,12 +173,10 @@ class AudioInputDevice
virtual void Run();
// Format
- size_t buffer_size_; // in sample-frames
- int channels_;
- int bits_per_sample_;
- double sample_rate_;
+ AudioParameters audio_parameters_;
CaptureCallback* callback_;
+ CaptureEventHandler* event_handler_;
// The client callback receives captured audio here.
std::vector<float*> audio_data_;
@@ -169,6 +203,14 @@ class AudioInputDevice
// Our stream ID on the message filter. Only modified on the IO thread.
int32 stream_id_;
+ // The media session ID used to identify which input device to be started.
+ // Only modified on the IO thread.
+ int session_id_;
+
+ // State variable used to indicate it is waiting for a OnDeviceReady()
+ // callback. Only modified on the IO thread.
+ bool pending_device_ready_;
+
scoped_ptr<base::SharedMemory> shared_memory_;
scoped_ptr<base::SyncSocket> socket_;
diff --git a/content/renderer/media/audio_input_message_filter.cc b/content/renderer/media/audio_input_message_filter.cc
index 27706e2..4f8c8ba 100644
--- a/content/renderer/media/audio_input_message_filter.cc
+++ b/content/renderer/media/audio_input_message_filter.cc
@@ -43,6 +43,10 @@ bool AudioInputMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyLowLatencyStreamCreated,
OnLowLatencyStreamCreated)
IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamVolume, OnStreamVolume)
+ IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamStateChanged,
+ OnStreamStateChanged)
+ IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyDeviceStarted,
+ OnDeviceStarted)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@@ -96,6 +100,27 @@ void AudioInputMessageFilter::OnStreamVolume(int stream_id, double volume) {
delegate->OnVolume(volume);
}
+void AudioInputMessageFilter::OnStreamStateChanged(
+ int stream_id, AudioStreamState state) {
+ Delegate* delegate = delegates_.Lookup(stream_id);
+ if (!delegate) {
+ DLOG(WARNING) << "Got audio stream event for a non-existent or removed"
+ " audio renderer.";
+ return;
+ }
+ delegate->OnStateChanged(state);
+}
+
+void AudioInputMessageFilter::OnDeviceStarted(int stream_id, int index) {
+ Delegate* delegate = delegates_.Lookup(stream_id);
+ if (!delegate) {
+ DLOG(WARNING) << "Got audio stream event for a non-existent or removed"
+ " audio renderer.";
+ return;
+ }
+ delegate->OnDeviceReady(index);
+}
+
int32 AudioInputMessageFilter::AddDelegate(Delegate* delegate) {
return delegates_.Add(delegate);
}
diff --git a/content/renderer/media/audio_input_message_filter.h b/content/renderer/media/audio_input_message_filter.h
index 1ea0283..74ba3c0 100644
--- a/content/renderer/media/audio_input_message_filter.h
+++ b/content/renderer/media/audio_input_message_filter.h
@@ -16,6 +16,7 @@
#include "base/id_map.h"
#include "base/shared_memory.h"
#include "base/sync_socket.h"
+#include "content/common/media/audio_stream_state.h"
#include "ipc/ipc_channel_proxy.h"
#include "media/audio/audio_buffers_state.h"
@@ -35,6 +36,13 @@ class AudioInputMessageFilter : public IPC::ChannelProxy::MessageFilter {
// browser process.
virtual void OnVolume(double volume) = 0;
+ // Called when state of an input stream has changed in the browser process.
+ virtual void OnStateChanged(AudioStreamState state) = 0;
+
+ // Called when the device referenced by the index has been started in
+ // the browswer process.
+ virtual void OnDeviceReady(int index) = 0;
+
protected:
virtual ~Delegate() {}
};
@@ -71,6 +79,13 @@ class AudioInputMessageFilter : public IPC::ChannelProxy::MessageFilter {
// Notification of volume property of an audio input stream.
void OnStreamVolume(int stream_id, double volume);
+ // Received when internal state of browser process' audio input stream has
+ // changed.
+ void OnStreamStateChanged(int stream_id, AudioStreamState state);
+
+ // Notification of the opened device of an audio session.
+ void OnDeviceStarted(int stream_id, int index);
+
// A map of stream ids to delegates.
IDMap<Delegate> delegates_;
diff --git a/content/renderer/media/webrtc_audio_device_impl.cc b/content/renderer/media/webrtc_audio_device_impl.cc
index 702d428..397aa4f 100644
--- a/content/renderer/media/webrtc_audio_device_impl.cc
+++ b/content/renderer/media/webrtc_audio_device_impl.cc
@@ -25,6 +25,7 @@ WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()
output_delay_ms_(0),
last_error_(AudioDeviceModule::kAdmErrNone),
last_process_time_(base::TimeTicks::Now()),
+ session_id_(0),
initialized_(false),
playing_(false),
recording_(false) {
@@ -159,6 +160,25 @@ void WebRtcAudioDeviceImpl::Capture(
}
}
+void WebRtcAudioDeviceImpl::OnDeviceStarted(int device_index) {
+ VLOG(1) << "OnDeviceStarted (device_index=" << device_index << ")";
+ // -1 is an invalid device index. Do nothing if a valid device has
+ // been started. Otherwise update the |recording_| state to false.
+ if (device_index != -1)
+ return;
+
+ base::AutoLock auto_lock(lock_);
+ if (recording_)
+ recording_ = false;
+}
+
+void WebRtcAudioDeviceImpl::OnDeviceStopped() {
+ VLOG(1) << "OnDeviceStopped";
+ base::AutoLock auto_lock(lock_);
+ if (recording_)
+ recording_ = false;
+}
+
int32_t WebRtcAudioDeviceImpl::Version(char* version,
uint32_t& remaining_buffer_in_bytes,
uint32_t& position) const {
@@ -352,7 +372,7 @@ int32_t WebRtcAudioDeviceImpl::Init() {
// Create and configure the audio capturing client.
audio_input_device_ = new AudioInputDevice(
- input_buffer_size, input_channels, output_sample_rate, this);
+ input_buffer_size, input_channels, output_sample_rate, this, this);
#if defined(OS_MACOSX)
// We create the input device for Mac as well but the performance
// will be very bad.
@@ -549,12 +569,22 @@ int32_t WebRtcAudioDeviceImpl::StartRecording() {
LOG(ERROR) << "Audio transport is missing";
return -1;
}
+
+ if (session_id_ <= 0) {
+ LOG(WARNING) << session_id_ << " is an invalid session id.";
+ return -1;
+ }
+
+ base::AutoLock auto_lock(lock_);
if (recording_) {
// webrtc::VoiceEngine assumes that it is OK to call Start() twice and
// that the call is ignored the second time.
LOG(WARNING) << "Recording is already active";
return 0;
}
+
+ // Specify the session_id which is mapped to a certain device.
+ audio_input_device_->SetDevice(session_id_);
audio_input_device_->Start();
recording_ = true;
return 0;
@@ -563,6 +593,8 @@ int32_t WebRtcAudioDeviceImpl::StartRecording() {
int32_t WebRtcAudioDeviceImpl::StopRecording() {
VLOG(1) << "StopRecording()";
DCHECK(audio_input_device_);
+
+ base::AutoLock auto_lock(lock_);
if (!recording_) {
// webrtc::VoiceEngine assumes that it is OK to call Stop() just in case.
LOG(WARNING) << "Recording was already stopped";
@@ -892,3 +924,7 @@ int32_t WebRtcAudioDeviceImpl::GetLoudspeakerStatus(bool* enabled) const {
NOTIMPLEMENTED();
return -1;
}
+
+void WebRtcAudioDeviceImpl::SetSessionId(int session_id) {
+ session_id_ = session_id;
+}
diff --git a/content/renderer/media/webrtc_audio_device_impl.h b/content/renderer/media/webrtc_audio_device_impl.h
index 508fa5b..968afb4 100644
--- a/content/renderer/media/webrtc_audio_device_impl.h
+++ b/content/renderer/media/webrtc_audio_device_impl.h
@@ -20,10 +20,14 @@
// A WebRtcAudioDeviceImpl instance implements the abstract interface
// webrtc::AudioDeviceModule which makes it possible for a user (e.g. webrtc::
// VoiceEngine) to register this class as an external AudioDeviceModule (ADM).
-// The user can then call WebRtcAudioDeviceImpl::StartPlayout() and
-// WebRtcAudioDeviceImpl::StartRecording() from the render process
-// to initiate and start audio rendering and capturing in the browser process.
-// IPC is utilized to set up the media streams.
+// Then WebRtcAudioDeviceImpl::SetSessionId() needs to be called to set the
+// session id that tells which device to use. The user can either get the
+// session id from the MediaStream or use a value of 1 (AudioInputDeviceManager
+// ::kFakeOpenSessionId), the later will open the default device without going
+// through the MediaStream. The user can then call WebRtcAudioDeviceImpl::
+// StartPlayout() and WebRtcAudioDeviceImpl::StartRecording() from the render
+// process to initiate and start audio rendering and capturing in the browser
+// process. IPC is utilized to set up the media streams.
//
// Usage example:
//
@@ -32,6 +36,7 @@
// {
// scoped_refptr<WebRtcAudioDeviceImpl> external_adm;
// external_adm = new WebRtcAudioDeviceImpl();
+// external_adm->SetSessionId(1);
// VoiceEngine* voe = VoiceEngine::Create();
// VoEBase* base = VoEBase::GetInterface(voe);
// base->Init(external_adm);
@@ -88,7 +93,8 @@
class WebRtcAudioDeviceImpl
: public webrtc::AudioDeviceModule,
public AudioDevice::RenderCallback,
- public AudioInputDevice::CaptureCallback {
+ public AudioInputDevice::CaptureCallback,
+ public AudioInputDevice::CaptureEventHandler {
public:
// Methods called on main render thread.
WebRtcAudioDeviceImpl();
@@ -112,6 +118,10 @@ class WebRtcAudioDeviceImpl
size_t number_of_frames,
size_t audio_delay_milliseconds) OVERRIDE;
+ // AudioInputDevice::CaptureEventHandler implementation.
+ virtual void OnDeviceStarted(int device_index);
+ virtual void OnDeviceStopped();
+
// webrtc::Module implementation.
virtual int32_t Version(char* version,
uint32_t& remaining_buffer_in_bytes,
@@ -238,6 +248,9 @@ class WebRtcAudioDeviceImpl
virtual int32_t SetLoudspeakerStatus(bool enable) OVERRIDE;
virtual int32_t GetLoudspeakerStatus(bool* enabled) const OVERRIDE;
+ // Sets the session id.
+ void SetSessionId(int session_id);
+
// Accessors.
size_t input_buffer_size() const { return input_buffer_size_; }
size_t output_buffer_size() const { return output_buffer_size_; }
@@ -293,6 +306,13 @@ class WebRtcAudioDeviceImpl
base::TimeTicks last_process_time_;
+ // Id of the media session to be started, it tells which device to be used
+ // on the input/capture side.
+ int session_id_;
+
+ // Protect |recording_|.
+ base::Lock lock_;
+
int bytes_per_sample_;
bool initialized_;