Skip to content

Commit

Permalink
Support groupId in MediaDevices.getUserMedia() for audio tracks
Browse files Browse the repository at this point in the history
Bug: 834281
Change-Id: I246b48483acb423bf83ab9c3e352d51bfe31070f
Reviewed-on: https://chromium-review.googlesource.com/1078590
Reviewed-by: Guido Urdaneta <guidou@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Chandan Padhi <c.padhi@samsung.com>
Cr-Commit-Position: refs/heads/master@{#562961}
  • Loading branch information
chandanpadhi authored and Commit Bot committed May 30, 2018
1 parent f007202 commit d637b5f
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,18 @@ std::vector<blink::mojom::AudioInputDeviceCapabilitiesPtr>
ToVectorAudioInputDeviceCapabilitiesPtr(
const std::vector<blink::mojom::AudioInputDeviceCapabilities>&
capabilities_vector,
const url::Origin& security_origin,
const std::string& salt) {
const MediaDeviceSaltAndOrigin& salt_and_origin) {
std::vector<blink::mojom::AudioInputDeviceCapabilitiesPtr> result;
result.reserve(capabilities_vector.size());
for (auto& capabilities : capabilities_vector) {
blink::mojom::AudioInputDeviceCapabilitiesPtr capabilities_ptr =
blink::mojom::AudioInputDeviceCapabilities::New();
capabilities_ptr->device_id =
GetHMACForMediaDeviceID(salt, security_origin, capabilities.device_id);
GetHMACForMediaDeviceID(salt_and_origin.device_id_salt,
salt_and_origin.origin, capabilities.device_id);
capabilities_ptr->group_id =
GetHMACForMediaDeviceID(salt_and_origin.group_id_salt,
salt_and_origin.origin, capabilities.group_id);
capabilities_ptr->parameters = capabilities.parameters;
result.push_back(std::move(capabilities_ptr));
}
Expand Down Expand Up @@ -292,8 +295,7 @@ void MediaDevicesDispatcherHost::FinalizeGetVideoInputDeviceFormats(
}

struct MediaDevicesDispatcherHost::AudioInputCapabilitiesRequest {
std::string device_id_salt;
url::Origin security_origin;
MediaDeviceSaltAndOrigin salt_and_origin;
GetAudioInputCapabilitiesCallback client_callback;
};

Expand All @@ -302,8 +304,7 @@ void MediaDevicesDispatcherHost::GetDefaultAudioInputDeviceID(
const MediaDeviceSaltAndOrigin& salt_and_origin) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
pending_audio_input_capabilities_requests_.push_back(
AudioInputCapabilitiesRequest{salt_and_origin.device_id_salt,
salt_and_origin.origin,
AudioInputCapabilitiesRequest{salt_and_origin,
std::move(client_callback)});
if (pending_audio_input_capabilities_requests_.size() > 1U)
return;
Expand Down Expand Up @@ -337,7 +338,7 @@ void MediaDevicesDispatcherHost::GotAudioInputEnumeration(
DCHECK_EQ(num_pending_audio_input_parameters_, 0U);
for (const auto& device_info : enumeration[MEDIA_DEVICE_TYPE_AUDIO_INPUT]) {
blink::mojom::AudioInputDeviceCapabilities capabilities(
device_info.device_id,
device_info.device_id, device_info.group_id,
media::AudioParameters::UnavailableDeviceParams());
if (device_info.device_id == default_device_id)
current_audio_input_capabilities_.insert(
Expand Down Expand Up @@ -386,8 +387,7 @@ void MediaDevicesDispatcherHost::FinalizeGetAudioInputCapabilities() {
for (auto& request : pending_audio_input_capabilities_requests_) {
std::move(request.client_callback)
.Run(ToVectorAudioInputDeviceCapabilitiesPtr(
current_audio_input_capabilities_, request.security_origin,
request.device_id_salt));
current_audio_input_capabilities_, request.salt_and_origin));
}

current_audio_input_capabilities_.clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ class SingleDeviceCandidateSet {
if (!capability.DeviceID().empty())
device_id_set_ = DiscreteSet<std::string>({capability.DeviceID()});

if (!capability.GroupID().empty())
group_id_set_ = DiscreteSet<std::string>({capability.GroupID()});

MediaStreamAudioSource* source = capability.source();

if (!source) {
Expand Down Expand Up @@ -322,6 +325,13 @@ class SingleDeviceCandidateSet {
return;
}

group_id_set_ = group_id_set_.Intersection(
StringSetFromConstraint(constraint_set.group_id));
if (group_id_set_.IsEmpty()) {
failed_constraint_name_ = constraint_set.group_id.GetName();
return;
}

goog_array_geometry_set_ = goog_array_geometry_set_.Intersection(
StringSetFromConstraint(constraint_set.goog_array_geometry));
if (goog_array_geometry_set_.IsEmpty()) {
Expand Down Expand Up @@ -382,6 +392,16 @@ class SingleDeviceCandidateSet {
}
}

if (constraint_set.group_id.HasIdeal()) {
for (const blink::WebString& ideal_value :
constraint_set.group_id.Ideal()) {
if (group_id_set_.Contains(ideal_value.Utf8())) {
fitness += 1.0;
break;
}
}
}

for (size_t i = 0; i < NUM_BOOL_CONSTRAINTS; ++i) {
if ((constraint_set.*kBlinkBoolConstraintFields[i]).HasIdeal() &&
bool_sets_[i].Contains(
Expand Down Expand Up @@ -544,6 +564,7 @@ class SingleDeviceCandidateSet {

const char* failed_constraint_name_ = nullptr;
DiscreteSet<std::string> device_id_set_;
DiscreteSet<std::string> group_id_set_;
std::array<DiscreteSet<bool>, NUM_BOOL_CONSTRAINTS> bool_sets_;
DiscreteSet<std::string> goog_array_geometry_set_;
DiscreteSet<std::string> echo_cancellation_type_set_;
Expand Down Expand Up @@ -657,15 +678,26 @@ AudioDeviceCaptureCapability::AudioDeviceCaptureCapability(

AudioDeviceCaptureCapability::AudioDeviceCaptureCapability(
std::string device_id,
std::string group_id,
const media::AudioParameters& parameters)
: device_id_(std::move(device_id)), parameters_(parameters) {
: device_id_(std::move(device_id)),
group_id_(std::move(group_id)),
parameters_(parameters) {
DCHECK(!device_id_.empty());
}

AudioDeviceCaptureCapability::AudioDeviceCaptureCapability(
const AudioDeviceCaptureCapability& other) = default;

const std::string& AudioDeviceCaptureCapability::DeviceID() const {
return source_ ? source_->device().id : device_id_;
}

const std::string& AudioDeviceCaptureCapability::GroupID() const {
return source_ && source_->device().group_id ? *source_->device().group_id
: group_id_;
}

const media::AudioParameters& AudioDeviceCaptureCapability::Parameters() const {
return source_ ? source_->device().input : parameters_;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ class CONTENT_EXPORT AudioDeviceCaptureCapability {
AudioDeviceCaptureCapability();

// This creates an AudioDeviceCaptureCapability where the device ID is limited
// to |device_id| and other settings are limited by the given |parameters|.
// |device_id| must not be empty. Intended to be used by getUserMedia() with
// device capture for devices that are not currently in use.
// to |device_id|, the group ID is limited to |group_id| and other settings
// are limited by the given |parameters|. |device_id| must not be empty.
// Intended to be used by getUserMedia() with device capture for devices that
// are not currently in use.
AudioDeviceCaptureCapability(std::string device_id,
std::string group_id,
const media::AudioParameters& parameters);

// This creates an AudioDeviceCaptureCapability where the device ID and other
Expand All @@ -53,6 +55,8 @@ class CONTENT_EXPORT AudioDeviceCaptureCapability {
// getUserMedia() with device capture for devices that are currently in use.
explicit AudioDeviceCaptureCapability(MediaStreamAudioSource* source);

AudioDeviceCaptureCapability(const AudioDeviceCaptureCapability& other);

// If this capability represents a device currently in use, this method
// returns a pointer to the MediaStreamAudioSource object associated with the
// device. Otherwise, it returns null.
Expand All @@ -64,6 +68,9 @@ class CONTENT_EXPORT AudioDeviceCaptureCapability {
// processing constraints.
const std::string& DeviceID() const;

// Returns the group ID of the device associated with this capability.
const std::string& GroupID() const;

// Returns the audio parameters for the device associated with this
// capability. If DeviceID() returns an empty string, these parameters contain
// default values that work well for content capture.
Expand All @@ -72,6 +79,7 @@ class CONTENT_EXPORT AudioDeviceCaptureCapability {
private:
MediaStreamAudioSource* source_ = nullptr;
std::string device_id_;
std::string group_id_;
media::AudioParameters parameters_;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class MediaStreamConstraintsUtilAudioTest
ResetFactory();
if (IsDeviceCapture()) {
capabilities_.emplace_back(
"default_device",
"default_device", "fake_group1",
media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
media::CHANNEL_LAYOUT_STEREO,
media::AudioParameters::kAudioCDSampleRate,
Expand All @@ -78,7 +78,7 @@ class MediaStreamConstraintsUtilAudioTest
media::AudioParameters::kAudioCDSampleRate, 1000);
hw_echo_canceller_parameters.set_effects(
media::AudioParameters::ECHO_CANCELLER);
capabilities_.emplace_back("hw_echo_canceller_device",
capabilities_.emplace_back("hw_echo_canceller_device", "fake_group2",
hw_echo_canceller_parameters);

media::AudioParameters experimental_hw_echo_canceller_parameters(
Expand All @@ -88,14 +88,16 @@ class MediaStreamConstraintsUtilAudioTest
experimental_hw_echo_canceller_parameters.set_effects(
media::AudioParameters::EXPERIMENTAL_ECHO_CANCELLER);
capabilities_.emplace_back("experimental_hw_echo_canceller_device",
"fake_group3",
experimental_hw_echo_canceller_parameters);

media::AudioParameters geometry_parameters(
media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
media::CHANNEL_LAYOUT_STEREO,
media::AudioParameters::kAudioCDSampleRate, 1000);
geometry_parameters.set_mic_positions(kMicPositions);
capabilities_.emplace_back("geometry device", geometry_parameters);
capabilities_.emplace_back("geometry device", "fake_group4",
geometry_parameters);

default_device_ = &capabilities_[0];
hw_echo_canceller_device_ = &capabilities_[1];
Expand Down Expand Up @@ -565,6 +567,29 @@ TEST_P(MediaStreamConstraintsUtilAudioTest, ExactValidDeviceID) {
}
}

TEST_P(MediaStreamConstraintsUtilAudioTest, ExactGroupID) {
for (const auto& device : capabilities_) {
constraint_factory_.basic().group_id.SetExact(
blink::WebString::FromASCII(device.GroupID()));
auto result = SelectSettings();
EXPECT_TRUE(result.HasValue());
CheckDevice(device, result);
CheckBoolDefaults(AudioSettingsBoolMembers(),
{&AudioProcessingProperties::enable_sw_echo_cancellation},
result);
bool has_hw_echo_cancellation =
device.Parameters().effects() & media::AudioParameters::ECHO_CANCELLER;
EXPECT_EQ(IsDeviceCapture() && !has_hw_echo_cancellation,
result.audio_processing_properties().enable_sw_echo_cancellation);
if (&device == geometry_device_) {
EXPECT_EQ(kMicPositions,
result.audio_processing_properties().goog_array_geometry);
} else {
CheckGeometryDefaults(result);
}
}
}

// Tests the echoCancellation constraint with a device without hardware echo
// cancellation.
TEST_P(MediaStreamConstraintsUtilAudioTest, EchoCancellationWithSw) {
Expand Down Expand Up @@ -1559,9 +1584,10 @@ TEST_P(MediaStreamConstraintsUtilAudioTest, UsedAndUnusedSources) {
false /* render_to_associated_sink */);

const std::string kUnusedDeviceID = "unused_device";
const std::string kGroupID = "fake_group";
AudioDeviceCaptureCapabilities capabilities;
capabilities.emplace_back(processed_source.get());
capabilities.emplace_back(kUnusedDeviceID,
capabilities.emplace_back(kUnusedDeviceID, kGroupID,
media::AudioParameters::UnavailableDeviceParams());

{
Expand Down
8 changes: 5 additions & 3 deletions content/renderer/media/stream/user_media_processor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -445,10 +445,12 @@ void UserMediaProcessor::SelectAudioDeviceSettings(
if (source->device().type == MEDIA_DEVICE_AUDIO_CAPTURE)
audio_source = static_cast<MediaStreamAudioSource*>(source);
}
if (audio_source)
if (audio_source) {
capabilities.emplace_back(audio_source);
else
capabilities.emplace_back(device->device_id, device->parameters);
} else {
capabilities.emplace_back(device->device_id, device->group_id,
device->parameters);
}
}

SelectAudioSettings(web_request, capabilities);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,34 @@ <h1 class="instructions">Description</h1>
}
}));
}, 'groupId is correctly supported by getUserMedia() for video devices');

promise_test(t => {
return navigator.mediaDevices.enumerateDevices()
.then(t.step_func(async devices => {
for (var i in devices) {
await navigator.mediaDevices.getUserMedia(
{audio: {groupId: {exact: devices[i].groupId}}})
.then(
t.step_func(stream => {
var found_device = devices.find(element => {
return element.deviceId ==
stream.getTracks()[0].getSettings().deviceId;
});
assert_true(undefined !== found_device);
assert_equals(found_device.kind, "audioinput");
assert_equals(found_device.groupId, devices[i].groupId);
}),
t.step_func(error => {
assert_equals(error.name, "OverconstrainedError");
assert_equals(error.constraint, "groupId");
var found_device = devices.find(element => {
return element.kind == "audioinput" &&
element.groupId == devices[i].groupId});
assert_true(undefined === found_device);
}));
}
}));
}, 'groupId is correctly supported by getUserMedia() for audio devices');
</script>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ struct VideoInputDeviceCapabilities {

struct AudioInputDeviceCapabilities {
string device_id;
string group_id;
media.mojom.AudioParameters parameters;
};

Expand Down

0 comments on commit d637b5f

Please sign in to comment.