Chromium Code Reviews| Index: content/renderer/media/user_media_client_impl.cc |
| diff --git a/content/renderer/media/user_media_client_impl.cc b/content/renderer/media/user_media_client_impl.cc |
| index aa65b672c2c2739f4888c8d83bda46257dc38d0e..b141fe09d2c8350b55b9a8b229952412e52994f2 100644 |
| --- a/content/renderer/media/user_media_client_impl.cc |
| +++ b/content/renderer/media/user_media_client_impl.cc |
| @@ -21,6 +21,7 @@ |
| #include "content/renderer/media/local_media_stream_audio_source.h" |
| #include "content/renderer/media/media_stream.h" |
| #include "content/renderer/media/media_stream_constraints_util.h" |
| +#include "content/renderer/media/media_stream_constraints_util_audio.h" |
| #include "content/renderer/media/media_stream_constraints_util_video_content.h" |
| #include "content/renderer/media/media_stream_constraints_util_video_device.h" |
| #include "content/renderer/media/media_stream_dispatcher.h" |
| @@ -49,6 +50,7 @@ void CopyFirstString(const blink::StringConstraint& constraint, |
| *destination = constraint.Exact()[0].Utf8(); |
| } |
| +// TODO(guidou): Remove this function. http://crbug.com/706408 |
| bool FindDeviceId(const blink::WebVector<blink::WebString> candidates, |
| const MediaDeviceInfoArray& device_infos, |
| std::string* device_id) { |
| @@ -79,8 +81,7 @@ bool FindDeviceId(const blink::WebVector<blink::WebString> candidates, |
| // such device ID is copied to |*device_id| and the function returns true. |
| // If no such device ID is found, |*device_id| is left unmodified and the |
| // function returns true. |
| -// TODO(guidou): Replace with a spec-compliant selection algorithm. See |
| -// http://crbug.com/657733. |
| +// TODO(guidou): Remove this function. http://crbug.com/706408 |
| bool PickDeviceId(const blink::WebMediaConstraints& constraints, |
| const MediaDeviceInfoArray& device_infos, |
| std::string* device_id) { |
| @@ -123,8 +124,7 @@ bool IsDeviceSource(const std::string& source) { |
| return source.empty(); |
| } |
| -// TODO(guidou): Remove once audio constraints are processed with spec-compliant |
| -// algorithm. See http://crbug.com/657733. |
| +// TODO(guidou): Remove this function. http://crbug.com/706408 |
| void CopyConstraintsToTrackControls( |
| const blink::WebMediaConstraints& constraints, |
| TrackControls* track_controls, |
| @@ -157,6 +157,7 @@ void InitializeTrackControls(const blink::WebMediaConstraints& constraints, |
| &track_controls->stream_source); |
| } |
| +// TODO(guidou): Remove this function. http://crbug.com/706408 |
| void CopyHotwordAndLocalEchoToStreamControls( |
| const blink::WebMediaConstraints& audio_constraints, |
| StreamControls* controls) { |
| @@ -219,6 +220,18 @@ blink::WebMediaDeviceInfo::MediaDeviceKind ToMediaDeviceKind( |
| } |
| } |
| +bool IsValidAudioContentSource(const std::string& source) { |
| + return source == kMediaStreamSourceTab || |
| + source == kMediaStreamSourceDesktop || |
| + source == kMediaStreamSourceSystem; |
| +} |
| + |
| +bool IsValidVideoContentSource(const std::string& source) { |
| + return source == kMediaStreamSourceTab || |
| + source == kMediaStreamSourceDesktop || |
| + source == kMediaStreamSourceScreen; |
| +} |
| + |
| static int g_next_request_id = 0; |
| } // namespace |
| @@ -265,11 +278,33 @@ class UserMediaClientImpl::UserMediaRequestInfo |
| State state() const { return state_; } |
| void set_state(State state) { state_ = state; } |
| - bool enable_automatic_output_device_selection() const { |
| - return enable_automatic_output_device_selection_; |
| + // TODO(guidou): Remove this function. http://crbug.com/706408 |
| + bool legacy_enable_automatic_output_device_selection() const { |
| + DCHECK(IsOldAudioConstraints()); |
| + return legacy_enable_automatic_output_device_selection_; |
| + } |
| + // TODO(guidou): Remove this function. http://crbug.com/706408 |
| + void set_legacy_enable_automatic_output_device_selection(bool value) { |
| + DCHECK(IsOldAudioConstraints()); |
| + legacy_enable_automatic_output_device_selection_ = value; |
| + } |
| + const AudioCaptureSettings& audio_capture_settings() const { |
| + DCHECK(!IsOldAudioConstraints()); |
| + return audio_capture_settings_; |
| + } |
| + bool is_audio_content_capture() const { |
| + DCHECK(!IsOldAudioConstraints()); |
| + return audio_capture_settings_.HasValue() && is_audio_content_capture_; |
| + } |
| + bool is_audio_device_capture() const { |
| + DCHECK(!IsOldAudioConstraints()); |
| + return audio_capture_settings_.HasValue() && !is_audio_content_capture_; |
| } |
| - void set_enable_automatic_output_device_selection(bool value) { |
| - enable_automatic_output_device_selection_ = value; |
| + void SetAudioCaptureSettings(const AudioCaptureSettings& settings, |
| + bool is_content_capture) { |
| + DCHECK(settings.HasValue()); |
| + is_audio_content_capture_ = is_content_capture; |
| + audio_capture_settings_ = settings; |
| } |
| const VideoCaptureSettings& video_capture_settings() const { |
| return video_capture_settings_; |
| @@ -305,7 +340,10 @@ class UserMediaClientImpl::UserMediaRequestInfo |
| const int request_id_; |
| State state_; |
| - bool enable_automatic_output_device_selection_; |
| + // TODO(guidou): Remove this field. http://crbug.com/706408 |
| + bool legacy_enable_automatic_output_device_selection_; |
| + AudioCaptureSettings audio_capture_settings_; |
| + bool is_audio_content_capture_; |
| VideoCaptureSettings video_capture_settings_; |
| bool is_video_content_capture_; |
| blink::WebMediaStream web_stream_; |
| @@ -390,46 +428,59 @@ void UserMediaClientImpl::MaybeProcessNextRequestInfo() { |
| current_request_info_ = std::move(pending_request_infos_.front()); |
| pending_request_infos_.pop_front(); |
| - // TODO(guidou): Request audio and video capabilities in parallel. |
| + // TODO(guidou): Set up audio and video in parallel. |
| if (current_request_info_->request().Audio()) { |
| - bool request_audio_input_devices = false; |
| - // TODO(guidou): Implement spec-compliant device selection for audio. See |
| - // http://crbug.com/623104. |
| - CopyConstraintsToTrackControls( |
| - current_request_info_->request().AudioConstraints(), |
| - ¤t_request_info_->stream_controls()->audio, |
| - &request_audio_input_devices); |
| - CopyHotwordAndLocalEchoToStreamControls( |
| - current_request_info_->request().AudioConstraints(), |
| - current_request_info_->stream_controls()); |
| - // Check if this input device should be used to select a matching output |
| - // device for audio rendering. |
| - bool enable_automatic_output_device_selection = false; |
| - GetConstraintValueAsBoolean( |
| - current_request_info_->request().AudioConstraints(), |
| - &blink::WebMediaTrackConstraintSet::render_to_associated_sink, |
| - &enable_automatic_output_device_selection); |
| - current_request_info_->set_enable_automatic_output_device_selection( |
| - enable_automatic_output_device_selection); |
| - |
| - if (request_audio_input_devices) { |
| - GetMediaDevicesDispatcher()->EnumerateDevices( |
| - true /* audio_input */, false /* video_input */, |
| - false /* audio_output */, |
| - base::Bind(&UserMediaClientImpl::SelectAudioInputDevice, |
| - weak_factory_.GetWeakPtr(), |
| - current_request_info_->request())); |
| - return; |
| - } |
| + if (IsOldAudioConstraints()) |
| + LegacySetupAudioInput(); |
| + else |
| + SetupAudioInput(current_request_info_->request()); |
| + return; |
| + } |
| + SetupVideoInput(current_request_info_->request()); |
| +} |
| + |
| +void UserMediaClientImpl::LegacySetupAudioInput() { |
| + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| + DCHECK(IsOldAudioConstraints()); |
| + DCHECK(current_request_info_); |
| + DCHECK(current_request_info_->request().Audio()); |
| + |
| + bool request_audio_input_devices = false; |
| + CopyConstraintsToTrackControls( |
| + current_request_info_->request().AudioConstraints(), |
| + ¤t_request_info_->stream_controls()->audio, |
| + &request_audio_input_devices); |
| + CopyHotwordAndLocalEchoToStreamControls( |
| + current_request_info_->request().AudioConstraints(), |
| + current_request_info_->stream_controls()); |
| + // Check if this input device should be used to select a matching output |
| + // device for audio rendering. |
| + bool enable_automatic_output_device_selection = false; |
| + GetConstraintValueAsBoolean( |
| + current_request_info_->request().AudioConstraints(), |
| + &blink::WebMediaTrackConstraintSet::render_to_associated_sink, |
| + &enable_automatic_output_device_selection); |
| + current_request_info_->set_legacy_enable_automatic_output_device_selection( |
| + enable_automatic_output_device_selection); |
| + |
| + if (request_audio_input_devices) { |
| + GetMediaDevicesDispatcher()->EnumerateDevices( |
| + true /* audio_input */, false /* video_input */, |
| + false /* audio_output */, |
| + base::Bind(&UserMediaClientImpl::LegacySelectAudioInputDevice, |
| + weak_factory_.GetWeakPtr(), |
| + current_request_info_->request())); |
| + return; |
| } |
| SetupVideoInput(current_request_info_->request()); |
| } |
| -void UserMediaClientImpl::SelectAudioInputDevice( |
| +void UserMediaClientImpl::LegacySelectAudioInputDevice( |
| const blink::WebUserMediaRequest& user_media_request, |
| const EnumerationResult& device_enumeration) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| + DCHECK(IsOldAudioConstraints()); |
| if (!IsCurrentRequestInfo(user_media_request)) |
| return; |
| @@ -447,6 +498,74 @@ void UserMediaClientImpl::SelectAudioInputDevice( |
| SetupVideoInput(user_media_request); |
| } |
| +void UserMediaClientImpl::SetupAudioInput( |
| + const blink::WebUserMediaRequest& user_media_request) { |
| + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| + DCHECK(!IsOldAudioConstraints()); |
| + DCHECK(user_media_request.Audio()); |
| + if (!IsCurrentRequestInfo(user_media_request)) |
| + return; |
| + |
| + auto& audio_controls = current_request_info_->stream_controls()->audio; |
| + InitializeTrackControls(user_media_request.AudioConstraints(), |
| + &audio_controls); |
| + if (IsDeviceSource(audio_controls.stream_source)) { |
| + GetMediaDevicesDispatcher()->GetAudioInputCapabilities( |
| + base::Bind(&UserMediaClientImpl::SelectAudioSettings, |
| + weak_factory_.GetWeakPtr(), user_media_request)); |
| + } else { |
| + if (!IsValidAudioContentSource(audio_controls.stream_source)) { |
| + blink::WebString failed_constraint_name = |
| + blink::WebString::FromASCII(user_media_request.AudioConstraints() |
| + .Basic() |
| + .media_stream_source.GetName()); |
| + MediaStreamRequestResult result = MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED; |
| + GetUserMediaRequestFailed(user_media_request, result, |
| + failed_constraint_name); |
| + return; |
| + } |
| + SelectAudioSettings(user_media_request, AudioDeviceCaptureCapabilities()); |
| + } |
| +} |
| + |
| +void UserMediaClientImpl::SelectAudioSettings( |
| + const blink::WebUserMediaRequest& user_media_request, |
| + std::vector<::mojom::AudioInputDeviceCapabilitiesPtr> |
| + audio_input_capabilities) { |
| + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| + DCHECK(!IsOldAudioConstraints()); |
| + if (!IsCurrentRequestInfo(user_media_request)) |
| + return; |
| + |
| + DCHECK(current_request_info_->stream_controls()->audio.requested); |
| + auto settings = |
| + SelectSettingsAudioCapture(std::move(audio_input_capabilities), |
| + user_media_request.AudioConstraints()); |
| + if (!settings.HasValue()) { |
| + blink::WebString failed_constraint_name = |
| + blink::WebString::FromASCII(settings.failed_constraint_name()); |
| + MediaStreamRequestResult result = |
| + failed_constraint_name.IsEmpty() |
| + ? MEDIA_DEVICE_NO_HARDWARE |
| + : MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED; |
| + GetUserMediaRequestFailed(user_media_request, result, |
| + failed_constraint_name); |
| + return; |
| + } |
| + current_request_info_->stream_controls()->audio.device_id = |
| + settings.device_id(); |
|
hbos_chromium
2017/06/16 17:27:14
What about ->audio.stream_source?
Guido Urdaneta
2017/06/19 11:56:48
It's set by InitializeTrackControls().
hbos_chromium
2017/06/19 15:14:41
Acknowledged.
|
| + current_request_info_->stream_controls()->disable_local_echo = |
| + settings.disable_local_echo(); |
| + current_request_info_->stream_controls()->hotword_enabled = |
| + settings.hotword_enabled(); |
| + current_request_info_->SetAudioCaptureSettings( |
| + settings, |
| + !IsDeviceSource( |
| + current_request_info_->stream_controls()->audio.stream_source)); |
| + |
| + SetupVideoInput(user_media_request); |
| +} |
| + |
| void UserMediaClientImpl::SetupVideoInput( |
| const blink::WebUserMediaRequest& user_media_request) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| @@ -465,6 +584,16 @@ void UserMediaClientImpl::SetupVideoInput( |
| base::Bind(&UserMediaClientImpl::SelectVideoDeviceSettings, |
| weak_factory_.GetWeakPtr(), user_media_request)); |
| } else { |
| + if (!IsValidVideoContentSource(video_controls.stream_source)) { |
| + blink::WebString failed_constraint_name = |
| + blink::WebString::FromASCII(user_media_request.VideoConstraints() |
| + .Basic() |
| + .media_stream_source.GetName()); |
| + MediaStreamRequestResult result = MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED; |
| + GetUserMediaRequestFailed(user_media_request, result, |
| + failed_constraint_name); |
| + return; |
|
hbos_chromium
2017/06/16 17:27:14
Was this a drive-by fix?
Guido Urdaneta
2017/06/19 11:56:48
Yes.
|
| + } |
| base::PostTaskAndReplyWithResult( |
| worker_task_runner_.get(), FROM_HERE, |
| base::Bind(&SelectSettingsVideoContentCapture, |
| @@ -540,8 +669,6 @@ void UserMediaClientImpl::FinalizeSelectVideoContentSettings( |
| blink::WebString failed_constraint_name = |
| blink::WebString::FromASCII(settings.failed_constraint_name()); |
| DCHECK(!failed_constraint_name.IsEmpty()); |
| - blink::WebString device_id_constraint_name = blink::WebString::FromASCII( |
| - user_media_request.VideoConstraints().Basic().device_id.GetName()); |
| GetUserMediaRequestFailed(user_media_request, |
| MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED, |
| failed_constraint_name); |
| @@ -847,12 +974,18 @@ MediaStreamAudioSource* UserMediaClientImpl::CreateAudioSource( |
| const blink::WebMediaConstraints& constraints, |
| const MediaStreamSource::ConstraintsCallback& source_ready) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| + DCHECK(current_request_info_); |
| // If the audio device is a loopback device (for screen capture), or if the |
| // constraints/effects parameters indicate no audio processing is needed, |
| // create an efficient, direct-path MediaStreamAudioSource instance. |
| + AudioProcessingProperties audio_processing_properties = |
| + IsOldAudioConstraints() ? AudioProcessingProperties::FromConstraints( |
| + constraints, device.device.input) |
| + : current_request_info_->audio_capture_settings() |
| + .audio_processing_properties(); |
| if (IsScreenCaptureMediaType(device.device.type) || |
| !MediaStreamAudioProcessor::WouldModifyAudio( |
| - constraints, device.device.input.effects)) { |
| + audio_processing_properties)) { |
| return new LocalMediaStreamAudioSource(RenderFrameObserver::routing_id(), |
| device, source_ready); |
| } |
| @@ -860,8 +993,8 @@ MediaStreamAudioSource* UserMediaClientImpl::CreateAudioSource( |
| // The audio device is not associated with screen capture and also requires |
| // processing. |
| ProcessedLocalAudioSource* source = new ProcessedLocalAudioSource( |
| - RenderFrameObserver::routing_id(), device, constraints, source_ready, |
| - dependency_factory_); |
| + RenderFrameObserver::routing_id(), device, audio_processing_properties, |
| + source_ready, dependency_factory_); |
| return source; |
| } |
| @@ -906,7 +1039,14 @@ void UserMediaClientImpl::CreateAudioTracks( |
| DCHECK_EQ(devices.size(), webkit_tracks->size()); |
| StreamDeviceInfoArray overridden_audio_array = devices; |
| - if (!current_request_info_->enable_automatic_output_device_selection()) { |
| + bool render_to_associated_sink = |
| + IsOldAudioConstraints() |
| + ? current_request_info_ |
| + ->legacy_enable_automatic_output_device_selection() |
| + : current_request_info_->audio_capture_settings().HasValue() && |
| + current_request_info_->audio_capture_settings() |
| + .render_to_associated_sink(); |
| + if (!render_to_associated_sink) { |
| // If the GetUserMedia request did not explicitly set the constraint |
| // kMediaStreamRenderToAssociatedSink, the output device parameters must |
| // be removed. |
| @@ -1261,13 +1401,25 @@ UserMediaClientImpl::GetMediaDevicesDispatcher() { |
| return media_devices_dispatcher_; |
| } |
| +const AudioCaptureSettings& |
| +UserMediaClientImpl::AudioCaptureSettingsForCurrentRequest() const { |
| + DCHECK(current_request_info_); |
| + return current_request_info_->audio_capture_settings(); |
| +} |
| + |
| +const VideoCaptureSettings& |
| +UserMediaClientImpl::VideoCaptureSettingsForCurrentRequest() const { |
| + DCHECK(current_request_info_); |
| + return current_request_info_->video_capture_settings(); |
| +} |
| + |
| base::Optional<bool> |
| UserMediaClientImpl::AutomaticOutputDeviceSelectionEnabledForCurrentRequest() { |
| if (!current_request_info_) |
| return base::Optional<bool>(); |
| return base::Optional<bool>( |
| - current_request_info_->enable_automatic_output_device_selection()); |
| + current_request_info_->legacy_enable_automatic_output_device_selection()); |
| } |
| void UserMediaClientImpl::OnDestruct() { |
| @@ -1281,7 +1433,8 @@ UserMediaClientImpl::UserMediaRequestInfo::UserMediaRequestInfo( |
| const url::Origin& security_origin) |
| : request_id_(request_id), |
| state_(State::NOT_SENT_FOR_GENERATION), |
| - enable_automatic_output_device_selection_(false), |
| + legacy_enable_automatic_output_device_selection_(false), |
| + is_audio_content_capture_(false), |
| is_video_content_capture_(false), |
| request_(request), |
| is_processing_user_gesture_(is_processing_user_gesture), |
| @@ -1293,6 +1446,11 @@ void UserMediaClientImpl::UserMediaRequestInfo::StartAudioTrack( |
| const blink::WebMediaStreamTrack& track, |
| bool is_pending) { |
| DCHECK(track.Source().GetType() == blink::WebMediaStreamSource::kTypeAudio); |
| + DCHECK(request_.Audio()); |
| +#if DCHECK_IS_ON() |
| + if (!IsOldAudioConstraints()) |
| + DCHECK(audio_capture_settings_.HasValue()); |
| +#endif |
| MediaStreamAudioSource* native_source = |
| MediaStreamAudioSource::From(track.Source()); |
| // Add the source as pending since OnTrackStarted will expect it to be there. |