Skip to content

Commit

Permalink
[getUserMedia] Add support for opening audio devices with different s…
Browse files Browse the repository at this point in the history
…ettings.

The current implementation limits the capabilities of already opened
devices to the currently configured settings. For example, if a device
is opened with echo cancellation enabled, it is not possible to reopen
the same device with echo cancellation disabled.

This CL aims at allowing to open the same device using getUserMedia for
echo cancellation (excluding HW echo cancellation).

TEST=manually tested with https://codepen.io/anon/pen/EzwjoG and https://codepen.io/anon/pen/mYRjZJ
BUG=796964

Change-Id: I0b26e787df3af125939500ea9d4e5cd2757f1229
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1624908
Commit-Queue: Armando Miraglia <armax@chromium.org>
Reviewed-by: Kinuko Yasuda <kinuko@chromium.org>
Reviewed-by: Guido Urdaneta <guidou@chromium.org>
Cr-Commit-Position: refs/heads/master@{#683569}
  • Loading branch information
Armando Miraglia authored and Commit Bot committed Aug 2, 2019
1 parent 69fc937 commit 233be4f
Show file tree
Hide file tree
Showing 28 changed files with 636 additions and 138 deletions.
1 change: 1 addition & 0 deletions content/browser/bad_message.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ enum BadMessageReason {
RFHI_BEGIN_NAVIGATION_NON_WEBBY_TRANSITION = 215,
RFH_NO_MATCHING_NAVIGATION_REQUEST_ON_COMMIT = 216,
AUTH_INVALID_ICON_URL = 217,
MDDH_INVALID_STREAM_SELECTION_INFO = 218,

// Please add new elements here. The naming convention is abbreviated class
// name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@
#include "base/logging.h"
#include "base/task/post_task.h"
#include "base/task_runner_util.h"
#include "content/browser/bad_message.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
#include "url/origin.h"

namespace content {
Expand Down Expand Up @@ -123,22 +124,34 @@ void MediaStreamDispatcherHost::GenerateStream(
int32_t page_request_id,
const blink::StreamControls& controls,
bool user_gesture,
blink::mojom::StreamSelectionInfoPtr audio_stream_selection_info_ptr,
GenerateStreamCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);

if (audio_stream_selection_info_ptr->strategy ==
blink::mojom::StreamSelectionStrategy::SEARCH_BY_SESSION_ID &&
(!audio_stream_selection_info_ptr->session_id.has_value() ||
audio_stream_selection_info_ptr->session_id->is_empty())) {
bad_message::ReceivedBadMessage(
render_process_id_, bad_message::MDDH_INVALID_STREAM_SELECTION_INFO);
return;
}

base::PostTaskAndReplyWithResult(
base::CreateSingleThreadTaskRunner({BrowserThread::UI}).get(), FROM_HERE,
base::BindOnce(salt_and_origin_callback_, render_process_id_,
render_frame_id_),
base::BindOnce(&MediaStreamDispatcherHost::DoGenerateStream,
weak_factory_.GetWeakPtr(), page_request_id, controls,
user_gesture, std::move(callback)));
user_gesture, std::move(audio_stream_selection_info_ptr),
std::move(callback)));
}

void MediaStreamDispatcherHost::DoGenerateStream(
int32_t page_request_id,
const blink::StreamControls& controls,
bool user_gesture,
blink::mojom::StreamSelectionInfoPtr audio_stream_selection_info_ptr,
GenerateStreamCallback callback,
MediaDeviceSaltAndOrigin salt_and_origin) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
Expand All @@ -153,7 +166,8 @@ void MediaStreamDispatcherHost::DoGenerateStream(

media_stream_manager_->GenerateStream(
render_process_id_, render_frame_id_, requester_id_, page_request_id,
controls, std::move(salt_and_origin), user_gesture, std::move(callback),
controls, std::move(salt_and_origin), user_gesture,
std::move(audio_stream_selection_info_ptr), std::move(callback),
base::BindRepeating(&MediaStreamDispatcherHost::OnDeviceStopped,
weak_factory_.GetWeakPtr()),
base::BindRepeating(&MediaStreamDispatcherHost::OnDeviceChanged,
Expand Down
22 changes: 13 additions & 9 deletions content/browser/renderer_host/media/media_stream_dispatcher_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ class CONTENT_EXPORT MediaStreamDispatcherHost
void CancelAllRequests();

// mojom::MediaStreamDispatcherHost implementation
void GenerateStream(int32_t request_id,
const blink::StreamControls& controls,
bool user_gesture,
GenerateStreamCallback callback) override;
void GenerateStream(
int32_t request_id,
const blink::StreamControls& controls,
bool user_gesture,
blink::mojom::StreamSelectionInfoPtr audio_stream_selection_info_ptr,
GenerateStreamCallback callback) override;
void CancelRequest(int32_t request_id) override;
void StopStreamDevice(
const std::string& device_id,
Expand All @@ -72,11 +74,13 @@ class CONTENT_EXPORT MediaStreamDispatcherHost
bool is_secure) override;
void OnStreamStarted(const std::string& label) override;

void DoGenerateStream(int32_t request_id,
const blink::StreamControls& controls,
bool user_gesture,
GenerateStreamCallback callback,
MediaDeviceSaltAndOrigin salt_and_origin);
void DoGenerateStream(
int32_t request_id,
const blink::StreamControls& controls,
bool user_gesture,
blink::mojom::StreamSelectionInfoPtr audio_stream_selection_info_ptr,
GenerateStreamCallback callback,
MediaDeviceSaltAndOrigin salt_and_origin);
void DoOpenDevice(int32_t request_id,
const std::string& device_id,
blink::mojom::MediaStreamType type,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ class MockMediaStreamDispatcherHost
quit_closures_.push(quit_closure);
MediaStreamDispatcherHost::GenerateStream(
page_request_id, controls, false,
blink::mojom::StreamSelectionInfo::New(
blink::mojom::StreamSelectionStrategy::SEARCH_BY_DEVICE_ID,
base::nullopt),
base::BindOnce(&MockMediaStreamDispatcherHost::OnStreamGenerated,
base::Unretained(this), page_request_id));
}
Expand Down
69 changes: 63 additions & 6 deletions content/browser/renderer_host/media/media_stream_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ using blink::StreamControls;
using blink::TrackControls;
using blink::mojom::MediaStreamRequestResult;
using blink::mojom::MediaStreamType;
using blink::mojom::StreamSelectionInfo;
using blink::mojom::StreamSelectionInfoPtr;
using blink::mojom::StreamSelectionStrategy;

namespace {
// Creates a random label used to identify requests.
Expand Down Expand Up @@ -284,6 +287,7 @@ class MediaStreamManager::DeviceRequest {
int requester_id,
int page_request_id,
bool user_gesture,
StreamSelectionInfoPtr audio_stream_selection_info_ptr,
MediaStreamRequestType request_type,
const StreamControls& controls,
MediaDeviceSaltAndOrigin salt_and_origin,
Expand All @@ -293,6 +297,8 @@ class MediaStreamManager::DeviceRequest {
requester_id(requester_id),
page_request_id(page_request_id),
user_gesture(user_gesture),
audio_stream_selection_info_ptr(
std::move(audio_stream_selection_info_ptr)),
controls(controls),
salt_and_origin(std::move(salt_and_origin)),
device_stopped_cb(std::move(device_stopped_cb)),
Expand Down Expand Up @@ -439,6 +445,11 @@ class MediaStreamManager::DeviceRequest {

const bool user_gesture;

// Information as of how to select a stream for an audio device provided by
// the caller.
// NB: This information is invalid after the request has been processed.
StreamSelectionInfoPtr audio_stream_selection_info_ptr;

const StreamControls controls;

const MediaDeviceSaltAndOrigin salt_and_origin;
Expand Down Expand Up @@ -635,9 +646,14 @@ std::string MediaStreamManager::MakeMediaAccessRequest(
MediaAccessRequestCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);

StreamSelectionInfoPtr audio_stream_selection_info_ptr =
StreamSelectionInfo::New(
blink::mojom::StreamSelectionStrategy::SEARCH_BY_DEVICE_ID,
base::nullopt);
auto request = std::make_unique<DeviceRequest>(
render_process_id, render_frame_id, requester_id, page_request_id,
false /* user gesture */, blink::MEDIA_DEVICE_ACCESS, controls,
false /* user gesture */, std::move(audio_stream_selection_info_ptr),
blink::MEDIA_DEVICE_ACCESS, controls,
MediaDeviceSaltAndOrigin{std::string() /* salt */,
std::string() /* group_id_salt */,
security_origin});
Expand All @@ -664,6 +680,7 @@ void MediaStreamManager::GenerateStream(
const StreamControls& controls,
MediaDeviceSaltAndOrigin salt_and_origin,
bool user_gesture,
StreamSelectionInfoPtr audio_stream_selection_info_ptr,
GenerateStreamCallback generate_stream_cb,
DeviceStoppedCallback device_stopped_cb,
DeviceChangedCallback device_changed_cb) {
Expand All @@ -672,8 +689,9 @@ void MediaStreamManager::GenerateStream(

DeviceRequest* request = new DeviceRequest(
render_process_id, render_frame_id, requester_id, page_request_id,
user_gesture, blink::MEDIA_GENERATE_STREAM, controls,
std::move(salt_and_origin), std::move(device_stopped_cb));
user_gesture, std::move(audio_stream_selection_info_ptr),
blink::MEDIA_GENERATE_STREAM, controls, std::move(salt_and_origin),
std::move(device_stopped_cb));
request->device_changed_cb = std::move(device_changed_cb);

const std::string& label = AddRequest(base::WrapUnique(request));
Expand Down Expand Up @@ -898,9 +916,16 @@ void MediaStreamManager::OpenDevice(int render_process_id,
} else {
NOTREACHED();
}
// For pepper, we default to searching for a device always based on device ID,
// independently of whether the request is for an audio or a video device.
StreamSelectionInfoPtr audio_stream_selection_info_ptr =
StreamSelectionInfo::New(
blink::mojom::StreamSelectionStrategy::SEARCH_BY_DEVICE_ID,
base::nullopt);
auto request = std::make_unique<DeviceRequest>(
render_process_id, render_frame_id, requester_id, page_request_id,
false /* user gesture */, blink::MEDIA_OPEN_DEVICE_PEPPER_ONLY, controls,
false /* user gesture */, std::move(audio_stream_selection_info_ptr),
blink::MEDIA_OPEN_DEVICE_PEPPER_ONLY, controls,
std::move(salt_and_origin), std::move(device_stopped_cb));

request->open_device_cb = std::move(open_device_cb);
Expand Down Expand Up @@ -1450,17 +1475,49 @@ bool MediaStreamManager::FindExistingRequestedDevice(
DCHECK(existing_device);
DCHECK(existing_request_state);

std::string source_id = GetHMACForMediaDeviceID(
std::string hashed_source_id = GetHMACForMediaDeviceID(
new_request.salt_and_origin.device_id_salt,
new_request.salt_and_origin.origin, new_device.id);

bool is_audio_capture =
new_device.type == MediaStreamType::DEVICE_AUDIO_CAPTURE &&
new_request.audio_type() == MediaStreamType::DEVICE_AUDIO_CAPTURE;
StreamSelectionStrategy strategy =
new_request.audio_stream_selection_info_ptr->strategy;
if (is_audio_capture &&
strategy == blink::mojom::StreamSelectionStrategy::FORCE_NEW_STREAM) {
return false;
}

base::Optional<base::UnguessableToken> requested_session_id =
new_request.audio_stream_selection_info_ptr->session_id;
#if DCHECK_IS_ON()
if (strategy == StreamSelectionStrategy::SEARCH_BY_SESSION_ID) {
DCHECK(requested_session_id);
DCHECK(!requested_session_id->is_empty());
}
#endif
for (const LabeledDeviceRequest& labeled_request : requests_) {
const DeviceRequest* request = labeled_request.second.get();
if (request->requesting_process_id == new_request.requesting_process_id &&
request->requesting_frame_id == new_request.requesting_frame_id &&
request->request_type() == new_request.request_type()) {
for (const MediaStreamDevice& device : request->devices) {
if (device.id == source_id && device.type == new_device.type) {
bool is_same_device =
device.id == hashed_source_id && device.type == new_device.type;
// If |strategy| is equal to SEARCH_BY_DEVICE_ID, the
// search is performed only based on the |device.id|. If, however,
// |strategy| is equal to SEARCH_BY_SESSION_ID, the
// search also includes the session ID provided in the request.
// NB: this only applies to audio. In case of media stream types that
// are not an audio capture, the session id is always ignored.
bool is_same_session =
!is_audio_capture ||
strategy == StreamSelectionStrategy::SEARCH_BY_DEVICE_ID ||
(strategy == StreamSelectionStrategy::SEARCH_BY_SESSION_ID &&
device.session_id() == *requested_session_id);

if (is_same_device && is_same_session) {
*existing_device = device;
// Make sure that the audio |effects| reflect what the request
// is set to and not what the capabilities are.
Expand Down
24 changes: 13 additions & 11 deletions content/browser/renderer_host/media/media_stream_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
#include "third_party/blink/public/common/mediastream/media_devices.h"
#include "third_party/blink/public/common/mediastream/media_stream_controls.h"
#include "third_party/blink/public/common/mediastream/media_stream_request.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"

namespace media {
class AudioSystem;
Expand Down Expand Up @@ -176,16 +176,18 @@ class CONTENT_EXPORT MediaStreamManager
// to determine where the infobar will appear to the user. |device_stopped_cb|
// is set to receive device stopped notifications. |device_change_cb| is set
// to receive device changed notifications.
void GenerateStream(int render_process_id,
int render_frame_id,
int requester_id,
int page_request_id,
const blink::StreamControls& controls,
MediaDeviceSaltAndOrigin salt_and_origin,
bool user_gesture,
GenerateStreamCallback generate_stream_cb,
DeviceStoppedCallback device_stopped_cb,
DeviceChangedCallback device_changed_cb);
void GenerateStream(
int render_process_id,
int render_frame_id,
int requester_id,
int page_request_id,
const blink::StreamControls& controls,
MediaDeviceSaltAndOrigin salt_and_origin,
bool user_gesture,
blink::mojom::StreamSelectionInfoPtr audio_stream_selection_info_ptr,
GenerateStreamCallback generate_stream_cb,
DeviceStoppedCallback device_stopped_cb,
DeviceChangedCallback device_changed_cb);

// Cancel an open request identified by |page_request_id| for the given frame.
// Must be called on the IO thread.
Expand Down
Loading

0 comments on commit 233be4f

Please sign in to comment.