<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE bugzilla SYSTEM "https://bugs.webkit.org/page.cgi?id=bugzilla.dtd">

<bugzilla version="5.0.4.1"
          urlbase="https://bugs.webkit.org/"
          
          maintainer="admin@webkit.org"
>

    <bug>
          <bug_id>198040</bug_id>
          
          <creation_ts>2019-05-20 07:46:54 -0700</creation_ts>
          <short_desc>getDisplayMedia fails when called from a promise created during a user gesture</short_desc>
          <delta_ts>2019-05-24 15:00:55 -0700</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>1</classification_id>
          <classification>Unclassified</classification>
          <product>WebKit</product>
          <component>WebRTC</component>
          <version>Safari Technology Preview</version>
          <rep_platform>Unspecified</rep_platform>
          <op_sys>Unspecified</op_sys>
          <bug_status>NEW</bug_status>
          <resolution></resolution>
          
          
          <bug_file_loc></bug_file_loc>
          <status_whiteboard></status_whiteboard>
          <keywords>InRadar</keywords>
          <priority>P2</priority>
          <bug_severity>Normal</bug_severity>
          <target_milestone>---</target_milestone>
          
          
          <everconfirmed>1</everconfirmed>
          <reporter>philipp.weissensteiner</reporter>
          <assigned_to name="Nobody">webkit-unassigned</assigned_to>
          <cc>eric.carlson</cc>
    
    <cc>ggaren</cc>
    
    <cc>webkit-bug-importer</cc>
    
    <cc>youennf</cc>
          

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>1537572</commentid>
    <comment_count>0</comment_count>
      <attachid>370251</attachid>
    <who name="">philipp.weissensteiner</who>
    <bug_when>2019-05-20 07:46:54 -0700</bug_when>
    <thetext>Created attachment 370251
getDisplayMedia example

Hi,

Since Safari Tech Preview 82 

&gt; getDisplayMedia must be called from a user gesture handler.

If said handler has an async call to say getUserMedia or enumerateDevices, before
invoking getDisplayMedia, the call will always fail with the above message.

```javascript
//  my user gesture handler is called after a button is clicked
async function myUserGestureHandler() {
  // both will cause a failure
  // const camera = await navigator.mediaDevices.getUserMedia({ video: true });
  const devices = await navigator.mediaDevices.enumerateDevices();

  // calling getUserMedia here works
  const screen = await navigator.mediaDevices.getDisplayMedia({ video: true });
}
```

- Invoking getUserMedia works.
- Recent Firefox and Chrome versions work too.
- Worked in Safari Tech Preview 81.

I&apos;ve attached an example page demonstrating the issue.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>1537611</commentid>
    <comment_count>1</comment_count>
    <who name="Radar WebKit Bug Importer">webkit-bug-importer</who>
    <bug_when>2019-05-20 10:31:45 -0700</bug_when>
    <thetext>&lt;rdar://problem/50950989&gt;</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>1537626</commentid>
    <comment_count>2</comment_count>
    <who name="youenn fablet">youennf</who>
    <bug_when>2019-05-20 10:52:38 -0700</bug_when>
    <thetext>Hi Philipp,

I guess a workaround is to do:

const gumPromise = navigator.mediaDevices.getUserMedia({ video: true });
const screenPromise = await anavigator.mediaDevices.getDisplayMedia({ video: true });
const camera = await gumPromise;

Would that work for you?
Or do you want to NOT request getDisplayMedia access if getUserMedia is rejected?

I am also not sure why you want to do enumerateDevices there.


FWIW, it will, in most cases, trigger two prompts to the user in a very short amount of time. I wonder whether this is a good application flow.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>1537836</commentid>
    <comment_count>3</comment_count>
    <who name="">philipp.weissensteiner</who>
    <bug_when>2019-05-21 02:41:22 -0700</bug_when>
    <thetext>Hi! Thanks for the quick response.

Let&apos;s say we want to build a screen sharing app where we mix the
camera and the screen stream.
We&apos;d have a button &quot;share screen&quot; and invoke the two .getMedia
functions in a handler.
Is that handler function not a &quot;user gesture handler&quot;?

My main concern is that &quot;user gesture handler&quot; is ambiguous.
Can you clarify what a user gesture handler is and why the example
code I posted,
doesn&apos;t qualify as such?

If I invoke a different Promise instead of getUserMedia or enumarteDevices, e.g:

const examplePromise = () =&gt; {
  return new Promise(res =&gt; window.setTimeout(() =&gt; res(), 500));
};

A subsequent call to getDisplayMedia works just fine, but increasing
the delay to 1s causes the error message too.

The work-around is viable, but I&apos;d it&apos;s still consider it a &quot;work-around&quot;.
It&apos;s not clear why you&apos;d have to invoke gDM before gUM, right?
I&apos;d probably have to add a comment &quot;order is important here!&quot; so I
won&apos;t forget it in 6 months :).

(As far as enumarteDevices goes, that was just an example).

Hope that clarifies my issue.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>1538464</commentid>
    <comment_count>4</comment_count>
    <who name="youenn fablet">youennf</who>
    <bug_when>2019-05-22 16:41:23 -0700</bug_when>
    <thetext>&gt; A subsequent call to getDisplayMedia works just fine, but increasing
&gt; the delay to 1s causes the error message too.

We currently bound the user gesture duration to 1s.

&gt; The work-around is viable, but I&apos;d it&apos;s still consider it a &quot;work-around&quot;.
&gt; It&apos;s not clear why you&apos;d have to invoke gDM before gUM, right?

My example is invoking gum first, then gdm.
It is not waiting for gum response to call gdm response.

The questions might be:
1. Can your application live with just screen, just camera or require both?
2. Do you want to ask the user for gdm in case gum is rejected?

The current design does not allow you to not ask gdm if gum is rejected without another user gesture.

Note though that two prompts that are happening shortly one after the other might be confusing to the user.
A more user friendly flow might be to enter a room and at that time trigger gum or gdm. Then have the user interact with the UI to enable the other one.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>1538627</commentid>
    <comment_count>5</comment_count>
    <who name="">philipp.weissensteiner</who>
    <bug_when>2019-05-23 03:10:28 -0700</bug_when>
    <thetext>&gt; We currently bound the user gesture duration to 1s.

Thanks for the clarification.

&gt; My example is invoking gum first, then gdm.
&gt; It is not waiting for gum response to call gdm response.

My bad. The point is that the order is important,
because of the user gesture restrictions.

&gt; 1. Can your application live with just screen, just camera or require both?

For this application I&apos;d require both.

&gt; 2. Do you want to ask the user for gdm in case gum is rejected?

No.

You&apos;re absolutely right, the current flow could be improved in that way.

I think a clarification for the behaviour might be good.

Maybe something like:

&gt; getDisplayMedia must be called from a user gesture handler. Learn more at:
&gt; https://bugs.webkit.org/show_bug.cgi?id=198040 or whatever the link might be.</thetext>
  </long_desc>
      
          <attachment
              isobsolete="0"
              ispatch="0"
              isprivate="0"
          >
            <attachid>370251</attachid>
            <date>2019-05-20 07:46:54 -0700</date>
            <delta_ts>2019-05-20 07:46:54 -0700</delta_ts>
            <desc>getDisplayMedia example</desc>
            <filename>index.html</filename>
            <type>text/html</type>
            <size>911</size>
            <attacher>philipp.weissensteiner</attacher>
            
              <data encoding="base64">PCFET0NUWVBFIGh0bWw+CjxodG1sPgogIDxoZWFkPgogICAgPG1ldGEgY2hhcnNldD0iVVRGLTgi
IC8+CiAgICA8dGl0bGU+Z2V0RGlzcGxheU1lZGlhPC90aXRsZT4KICA8L2hlYWQ+CiAgPGJvZHk+
CiAgICA8YnV0dG9uIG9uY2xpY2s9ImdldE1lZGlhKCkiPmdldCBtZWRpYTwvYnV0dG9uPgogICAg
PHZpZGVvIGlkPSJ2aWRlby0xIiB3aWR0aD0iNDAwIiBoZWlnaHQ9IjMwMCI+PC92aWRlbz4KICAg
IDx2aWRlbyBpZD0idmlkZW8tMiIgd2lkdGg9IjQwMCIgaGVpZ2h0PSIzMDAiPjwvdmlkZW8+CiAg
PC9ib2R5PgogIDxzY3JpcHQ+CiAgICBmdW5jdGlvbiBhc3NpZ25WaWRlbyhpZCwgc3RyZWFtKSB7
CiAgICAgIGNvbnN0IHZpZGVvID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoaWQpOwogICAgICB2
aWRlby5zcmNPYmplY3QgPSBzdHJlYW07CiAgICAgIHZpZGVvLnBsYXkoKTsKICAgIH0KCiAgICBh
c3luYyBmdW5jdGlvbiBnZXRNZWRpYSgpIHsKICAgICAgLy8gY29uc3QgY2FtZXJhID0gYXdhaXQg
bmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEoeyB2aWRlbzogdHJ1ZSB9KTsKICAg
ICAgLy8gYXNzaWduVmlkZW8oJ3ZpZGVvLTEnLCBjYW1lcmEpOwogICAgICBjb25zdCBkZXZpY2Vz
ID0gYXdhaXQgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5lbnVtZXJhdGVEZXZpY2VzKCk7CiAgICAg
IGNvbnNvbGUubG9nKGRldmljZXMpOwoKICAgICAgLy8gY2FsbGluZyBnZXRVc2VyTWVkaWEgaGVy
ZSB3b3JrcwogICAgICBjb25zdCBzY3JlZW4gPSBhd2FpdCBuYXZpZ2F0b3IubWVkaWFEZXZpY2Vz
LmdldERpc3BsYXlNZWRpYSh7CiAgICAgICAgdmlkZW86IHRydWUKICAgICAgfSk7CiAgICAgIGFz
c2lnblZpZGVvKCd2aWRlby0yJywgc2NyZWVuKTsKICAgIH0KICA8L3NjcmlwdD4KPC9odG1sPgo=
</data>

          </attachment>
      

    </bug>

</bugzilla>