| Index: content/browser/renderer_host/media/media_stream_device_settings.cc
|
| diff --git a/content/browser/renderer_host/media/media_stream_device_settings.cc b/content/browser/renderer_host/media/media_stream_device_settings.cc
|
| index f701a1d179793d8033e550ccdda8888c8b8b0423..054a07a25d45f87c9049d2b44f22a7d87510814a 100644
|
| --- a/content/browser/renderer_host/media/media_stream_device_settings.cc
|
| +++ b/content/browser/renderer_host/media/media_stream_device_settings.cc
|
| @@ -86,7 +86,7 @@ typedef std::map<MediaStreamType, StreamDeviceInfoArray> DeviceMap;
|
|
|
| // Device request contains all data needed to keep track of requests between the
|
| // different calls.
|
| -class MediaStreamDeviceSettingsRequest : public MediaStreamRequest {
|
| +struct MediaStreamDeviceSettingsRequest : public MediaStreamRequest {
|
| public:
|
| MediaStreamDeviceSettingsRequest(
|
| int render_pid,
|
| @@ -102,6 +102,9 @@ class MediaStreamDeviceSettingsRequest : public MediaStreamRequest {
|
| // Request options.
|
| StreamOptions options;
|
| // Map containing available devices for the requested capture types.
|
| + // Note, never call devices_full[stream_type].empty() before making sure
|
| + // that type of device has existed on the map, otherwise it will create an
|
| + // empty device entry on the map.
|
| DeviceMap devices_full;
|
| // Whether or not a task was posted to make the call to
|
| // RequestMediaAccessPermission, to make sure that we never post twice to it.
|
| @@ -111,9 +114,8 @@ class MediaStreamDeviceSettingsRequest : public MediaStreamRequest {
|
| namespace {
|
|
|
| // Sends the request to the appropriate WebContents.
|
| -void DoDeviceRequest(
|
| - const MediaStreamDeviceSettingsRequest& request,
|
| - const content::MediaResponseCallback& callback) {
|
| +void DoDeviceRequest(const MediaStreamDeviceSettingsRequest& request,
|
| + const content::MediaResponseCallback& callback) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
|
| // Send the permission request to the web contents.
|
| @@ -130,6 +132,20 @@ void DoDeviceRequest(
|
| host->GetDelegate()->RequestMediaAccessPermission(&request, callback);
|
| }
|
|
|
| +bool IsRequestReadyForView(
|
| + media_stream::MediaStreamDeviceSettingsRequest* request) {
|
| + if ((request->options.audio && request->devices_full.count(
|
| + content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE) == 0) ||
|
| + (request->options.video && request->devices_full.count(
|
| + content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE) == 0)) {
|
| + return false;
|
| + }
|
| +
|
| + // We have got all the requested devices, it is ready if it has not
|
| + // been posted for UI yet.
|
| + return !request->posted_task;
|
| +}
|
| +
|
| } // namespace
|
|
|
| MediaStreamDeviceSettings::MediaStreamDeviceSettings(
|
| @@ -148,12 +164,7 @@ void MediaStreamDeviceSettings::RequestCaptureDeviceUsage(
|
| const std::string& label, int render_process_id, int render_view_id,
|
| const StreamOptions& request_options, const GURL& security_origin) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| -
|
| - if (requests_.find(label) != requests_.end()) {
|
| - // Request with this id already exists.
|
| - requester_->SettingsError(label);
|
| - return;
|
| - }
|
| + DCHECK(requests_.find(label) == requests_.end());
|
|
|
| // Create a new request.
|
| requests_.insert(std::make_pair(label, new MediaStreamDeviceSettingsRequest(
|
| @@ -163,22 +174,27 @@ void MediaStreamDeviceSettings::RequestCaptureDeviceUsage(
|
| void MediaStreamDeviceSettings::RemovePendingCaptureRequest(
|
| const std::string& label) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| -
|
| SettingsRequests::iterator request_it = requests_.find(label);
|
| if (request_it != requests_.end()) {
|
| // Proceed the next pending request for the same page.
|
| MediaStreamDeviceSettingsRequest* request = request_it->second;
|
| - std::string new_label = FindReadyRequestForView(request->render_view_id,
|
| - request->render_process_id);
|
| - if (!new_label.empty()) {
|
| - PostRequestToUi(new_label);
|
| - }
|
| + int render_view_id = request->render_view_id;
|
| + int render_process_id = request->render_process_id;
|
| + bool was_posted = request->posted_task;
|
|
|
| // TODO(xians): Post a cancel request on UI thread to dismiss the infobar
|
| // if request has been sent to the UI.
|
| // Remove the request from the queue.
|
| requests_.erase(request_it);
|
| delete request;
|
| +
|
| + // Simply return if the canceled request has not been brought to UI.
|
| + if (!was_posted)
|
| + return;
|
| +
|
| + // Process the next pending request to replace the old infobar on the same
|
| + // page.
|
| + ProcessNextRequestForView(render_view_id, render_process_id);
|
| }
|
| }
|
|
|
| @@ -190,69 +206,25 @@ void MediaStreamDeviceSettings::AvailableDevices(
|
|
|
| SettingsRequests::iterator request_it = requests_.find(label);
|
| DCHECK(request_it != requests_.end());
|
| -
|
| // Add the answer for the request.
|
| MediaStreamDeviceSettingsRequest* request = request_it->second;
|
| - DCHECK_EQ(request->devices_full.count(stream_type), static_cast<size_t>(0)) <<
|
| - "This request already has a list of devices for this stream type.";
|
| + DCHECK_EQ(request->devices_full.count(stream_type), static_cast<size_t>(0))
|
| + << "This request already has a list of devices for this stream type.";
|
| request->devices_full[stream_type] = devices;
|
|
|
| - // Check if we're done.
|
| - size_t num_media_requests = 0;
|
| - if (request->options.audio) {
|
| - num_media_requests++;
|
| - }
|
| - if (request->options.video) {
|
| - num_media_requests++;
|
| - }
|
| -
|
| - if (request->devices_full.size() == num_media_requests) {
|
| - // We have all answers needed.
|
| - if (!use_fake_ui_) {
|
| - // Abort if the task was already posted: wait for it to PostResponse.
|
| - if (request->posted_task) {
|
| - return;
|
| - }
|
| - // Since the UI can only handle one request at the time, verify there
|
| - // is no unanswered request posted for this view. If there is, this
|
| - // new request will be handled once we get a response for the first one.
|
| - if (IsUiBusy(request->render_view_id, request->render_process_id)) {
|
| - return;
|
| - }
|
| - PostRequestToUi(label);
|
| - } else {
|
| - // Used to fake UI, which is needed for server based testing.
|
| - // Choose first non-opened device for each media type.
|
| - StreamDeviceInfoArray devices_to_use;
|
| - for (DeviceMap::iterator it = request->devices_full.begin();
|
| - it != request->devices_full.end(); ++it) {
|
| - for (StreamDeviceInfoArray::iterator device_it = it->second.begin();
|
| - device_it != it->second.end(); ++device_it) {
|
| - if (!device_it->in_use) {
|
| - devices_to_use.push_back(*device_it);
|
| - break;
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (!request->devices_full[
|
| - content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE].empty() &&
|
| - num_media_requests != devices_to_use.size()) {
|
| - // Not all requested device types were opened. This happens if all
|
| - // video capture devices are already opened, |in_use| isn't set for
|
| - // audio devices. Allow the first video capture device in the list to be
|
| - // opened for this user too.
|
| - StreamDeviceInfoArray device_array =
|
| - request->devices_full[
|
| - content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE];
|
| - devices_to_use.push_back(*(device_array.begin()));
|
| - }
|
| + if (IsRequestReadyForView(request)) {
|
| + if (use_fake_ui_) {
|
| + PostRequestToFakeUI(label);
|
| + return;
|
| + }
|
|
|
| - // Post result and delete request.
|
| - requester_->DevicesAccepted(label, devices_to_use);
|
| - requests_.erase(request_it);
|
| - delete request;
|
| + if (IsUIBusy(request->render_view_id, request->render_process_id)) {
|
| + // The UI can handle only one request at the time, do not post the
|
| + // request to the view if the UI is handling any other request.
|
| + return;
|
| }
|
| +
|
| + PostRequestToUI(label);
|
| }
|
| }
|
|
|
| @@ -260,23 +232,19 @@ void MediaStreamDeviceSettings::PostResponse(
|
| const std::string& label,
|
| const content::MediaStreamDevices& devices) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| -
|
| SettingsRequests::iterator req = requests_.find(label);
|
| // Return if the request has been removed.
|
| if (req == requests_.end())
|
| return;
|
|
|
| DCHECK(requester_);
|
| - MediaStreamDeviceSettingsRequest* request = req->second;
|
| + scoped_ptr<MediaStreamDeviceSettingsRequest> request(req->second);
|
| requests_.erase(req);
|
|
|
| // Look for queued requests for the same view. If there is a pending request,
|
| // post it for user approval.
|
| - std::string new_label = FindReadyRequestForView(request->render_view_id,
|
| - request->render_process_id);
|
| - if (!new_label.empty()) {
|
| - PostRequestToUi(new_label);
|
| - }
|
| + ProcessNextRequestForView(request->render_view_id,
|
| + request->render_process_id);
|
|
|
| if (devices.size() > 0) {
|
| // Build a list of "full" device objects for the accepted devices.
|
| @@ -293,7 +261,6 @@ void MediaStreamDeviceSettings::PostResponse(
|
| } else {
|
| requester_->SettingsError(label);
|
| }
|
| - delete request;
|
| }
|
|
|
| void MediaStreamDeviceSettings::UseFakeUI() {
|
| @@ -301,7 +268,7 @@ void MediaStreamDeviceSettings::UseFakeUI() {
|
| use_fake_ui_ = true;
|
| }
|
|
|
| -bool MediaStreamDeviceSettings::IsUiBusy(int render_view_id,
|
| +bool MediaStreamDeviceSettings::IsUIBusy(int render_view_id,
|
| int render_process_id) {
|
| for (SettingsRequests::iterator it = requests_.begin();
|
| it != requests_.end(); ++it) {
|
| @@ -314,37 +281,32 @@ bool MediaStreamDeviceSettings::IsUiBusy(int render_view_id,
|
| return false;
|
| }
|
|
|
| -std::string MediaStreamDeviceSettings::FindReadyRequestForView(
|
| +void MediaStreamDeviceSettings::ProcessNextRequestForView(
|
| int render_view_id, int render_process_id) {
|
| + std::string new_label;
|
| for (SettingsRequests::iterator it = requests_.begin(); it != requests_.end();
|
| ++it) {
|
| if (it->second->render_process_id == render_process_id &&
|
| it->second->render_view_id == render_view_id) {
|
| // This request belongs to the given render view.
|
| MediaStreamDeviceSettingsRequest* request = it->second;
|
| - if (request->options.audio &&
|
| - request->devices_full[
|
| - content::MEDIA_STREAM_DEVICE_TYPE_AUDIO_CAPTURE].empty()) {
|
| - // Audio requested, but no devices enumerated yet. Continue to next
|
| - // request.
|
| - continue;
|
| - }
|
| - if (request->options.video &&
|
| - request->devices_full[
|
| - content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE].empty()) {
|
| - // Video requested, but no devices enumerated yet. Continue to next
|
| - // request.
|
| - continue;
|
| + if (IsRequestReadyForView(request)) {
|
| + new_label = it->first;
|
| + break;
|
| }
|
| - // This request belongs to the same view as the treated request and is
|
| - // ready to be requested. Return its label.
|
| - return it->first;
|
| }
|
| }
|
| - return std::string();
|
| +
|
| + if (new_label.empty())
|
| + return;
|
| +
|
| + if (use_fake_ui_)
|
| + PostRequestToFakeUI(new_label);
|
| + else
|
| + PostRequestToUI(new_label);
|
| }
|
|
|
| -void MediaStreamDeviceSettings::PostRequestToUi(const std::string& label) {
|
| +void MediaStreamDeviceSettings::PostRequestToUI(const std::string& label) {
|
| MediaStreamDeviceSettingsRequest* request = requests_[label];
|
| DCHECK(request != NULL);
|
|
|
| @@ -372,4 +334,38 @@ void MediaStreamDeviceSettings::PostRequestToUi(const std::string& label) {
|
| base::Bind(&DoDeviceRequest, *request, callback));
|
| }
|
|
|
| +void MediaStreamDeviceSettings::PostRequestToFakeUI(const std::string& label) {
|
| + SettingsRequests::iterator request_it = requests_.find(label);
|
| + DCHECK(request_it != requests_.end());
|
| + MediaStreamDeviceSettingsRequest* request = request_it->second;
|
| + // Used to fake UI, which is needed for server based testing.
|
| + // Choose first non-opened device for each media type.
|
| + content::MediaStreamDevices devices_to_use;
|
| + for (DeviceMap::iterator it = request->devices_full.begin();
|
| + it != request->devices_full.end(); ++it) {
|
| + StreamDeviceInfoArray::iterator device_it = it->second.begin();
|
| + for (; device_it != it->second.end(); ++device_it) {
|
| + if (!device_it->in_use) {
|
| + devices_to_use.push_back(content::MediaStreamDevice(
|
| + device_it->stream_type, device_it->device_id, device_it->name));
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if (it->second.size() != 0 && device_it == it->second.end()) {
|
| + // Use the first capture device in the list if all the devices are
|
| + // being used.
|
| + devices_to_use.push_back(
|
| + content::MediaStreamDevice(it->second.begin()->stream_type,
|
| + it->second.begin()->device_id,
|
| + it->second.begin()->name));
|
| + }
|
| + }
|
| +
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE,
|
| + base::Bind(&MediaStreamDeviceSettings::PostResponse,
|
| + weak_ptr_factory_.GetWeakPtr(), label, devices_to_use));
|
| +}
|
| +
|
| } // namespace media_stream
|
|
|