Bug 218012

Summary: Audio Volume reduces considerably on accepting the mic permissions.
Product: WebKit Reporter: asanand
Component: Web AudioAssignee: Nobody <webkit-unassigned>
Status: RESOLVED CONFIGURATION CHANGED    
Severity: Critical CC: 541657414, andres.traumann.01, aqlykamarudin, bfulgham, bryce.aebi, cdumez, david.goelzhaeuser, eric.carlson, glefebvr, homerlex, jameshoward, jer.noble, juberti, justinhiggy, ngode, peng.liu6, philipp.hancke, smoley, stuart.todd, taimoor, tobias.bley, varundabke, webkit-bug-importer, youennf, zale
Priority: P2 Keywords: InRadar
Version: Safari 14   
Hardware: iPhone / iPad   
OS: Unspecified   
See Also: https://bugs.webkit.org/show_bug.cgi?id=233316

Description asanand 2020-10-21 02:31:56 PDT
Source code - https://github.com/ashishanand26cs/ashishanand26cs.github.io/blob/master/index.html 

Steps to reproduce:-

In "Website Settings" of Safari, set the microphone's permission to "Ask". Open page "https://ashishanand26cs.github.io" on safari(ios version 14.0.1)"
Clicking on the webpage generates Gunshots. Observe the volume of the gunshot for below two cases.

Case 1:-
On opening the webpage the popup generates "Would Like To Access the Microphone"
Press "Allow". Now press click on the white page. It will generate the Gunshots on every click.
Observer the audio volume.

Case 2:-
Again refresh the page. It will again generate "Would Like To Access the Microphone"
Press "Cancel". Now press click on the white page. It will generate the Gunshots on every click.
Observer the audio volume.


Audio Volume generated in "Case 1" is significantly lower than "Case 2".
Comment 1 Chris Dumez 2020-10-21 09:26:18 PDT
Does not reproduce on macOS but I can reproduce on iOS 14.
Comment 2 Smoley 2020-10-22 13:57:21 PDT
Also reproduces on iOS 13.5.1 using the provided link.
Comment 3 Radar WebKit Bug Importer 2020-10-22 13:57:44 PDT
<rdar://problem/70588151>
Comment 4 asanand 2020-11-01 21:45:38 PST
Hi
Do we have any update on this issue? 
Is the root cause identified? When can we expect the fix for this issue?
Comment 5 youenn fablet 2020-11-02 01:57:42 PST
When starting capturing, we are changing of audio category which might explain the issue.The following fiddle helps: https://jsfiddle.net/af147yqz/

If you start capturing, then create the audio context, you will get the audio volume as high.

If you create the audio context, audio volume will be low and will stay like this, even after starting capture.
If during capture, you will suspend/resume the audio context, audio volume will be high.

Hopefully, that can help you find a temporary workaround.
Comment 6 ngode 2020-11-06 08:55:49 PST
We tried the WAR, however, unfortunately, it seems to be working just on a few devices - for several devices, the WAR does not have any effect

Few further isolations which we observed:
- Volume is also reset for pre-existing audio contexts, even just if a new audio context is created when recording starts
- On devices which WAR doesn't work, suspending/Resuming audio stream/track makes no difference

Devices on which WAR works: iPad Pro 12.9-in (Second Generation), iPhone 7, iPhone X
Devices on which WAR doesn't work: iPad Pro 11-in (Third Generation), iPhone XR
Comment 7 :fippo 2020-11-19 13:40:24 PST
I can reproduce quite reliably after finding out they key is rotating the device somehow.
I can reproduce on an iphone SE (2020) and both in iOS 14.1 and 14.2. Upgrading to 14.2 caused a (hopefullly) unrelated webaudio issue which makes the audio stutter for several seconds.

The minimal sample is at https://fippo.github.io/htmlthings/aadz4a.html
It plays a constant tone using webaudio and visualizes the audio level webrtc sees.

Steps to reproduce low audio volume:
1/ open Safari, put into portrait mode
2/ put phone on the desk, do not hold it
3/ open https://fippo.github.io/htmlthings/aadz4a.html
4/ click "play noise" button. This emits a constant tone.
5/ click "request getusermedia" button. Audio volume usually increases. Note that the graph which shows the audio level webrtc computes stays at 1.0
6/ reload, pick up phone, rotate to portrait mode, put phone on the desk
7/ click "play noise" button. This emits a constant tone roughly the same volume as in step 4.
8/ click "request getusermedia" button". Audio volume drops considerably. Note that the graph which shows the audio level webrtc computes stays at 1.0

For extra fun, continue testing:
9/ pick up phone, put in portrait mode, put down phone
10/ reload
11/ click "play noise" button followed by getUserMedia button
12/ Observe low volume

For even more fun, kill safari, then repeat but starting from landscape mode and switch to portrait mode.

https://bugs.webkit.org/show_bug.cgi?id=198545#c29 suggests rotation fixes *some* issue.
This sounds like some kind of "audio ducking" issue.
This is not detectable from what I can see.
Comment 8 ngode 2020-11-23 00:01:57 PST
Hi, I wonder if there were any updates on this issue?

This seems to be reproing without device rotation too for us
Comment 9 asanand 2021-01-06 20:25:58 PST
We are still seeing this issue on 14.3. The workaround mentioned is not working.

Do we have any updates on this issue? 
When can we expect the fix for this issue?
Comment 10 asanand 2021-02-07 17:57:03 PST
We are still seeing this issue on 14.4. 

If we play the audio element again(WAR) it increases the volume but only until 50 percent.

Is there a plan for a fix in some upcoming version?
Comment 11 Andres Traumann 2021-03-09 02:55:33 PST
We still have the bug on 14.5 beta.
Comment 12 James Howard 2021-03-19 10:54:59 PDT
It looks like Safari uses the following options when setting the audio category to play and record:

auto options = AVAudioSessionCategoryOptionAllowBluetooth | AVAudioSessionCategoryOptionMixWithOthers;

https://git.webkit.org/?p=WebKit-https.git;a=blob;f=Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm;hb=29d45f52c2db831d9b6a7d9e96dfd44624984c24#l110

I think this means when the mic turns on that the receiver speaker becomes the only one active (the little earpiece one on a phone). This is probably a reasonable set of options for when you're holding the phone like a phone, but it's maybe not great for video chat or music apps. Using AVAudioSessionCategoryOptionDefaultToSpeaker would be better for our use case, but I'm not sure what the fallout would be by changing it across the board. I kind of think maybe AVAudioSessionCategoryOptionDefaultToSpeaker better fits what most web apps want to do; most web apps aren't trying to just make phone calls.
Comment 13 :fippo 2021-03-19 11:03:13 PDT
Would it be possible to use AVAudioSessionCategoryOptionDefaultToSpeaker when there is a stereo track playing?
Comment 14 Andres Traumann 2021-04-30 02:50:05 PDT
The issue seems to have disappeared in 14.5. However, it seems there is now an opposite issue, on at least one device the volume seemed to slightly increase after asking for microphone permissions. Of course this new issue is a much smaller problem, at least in my use case.
Comment 15 David Gölzhäuser 2021-10-01 00:37:02 PDT
I still see this issue on iOS 15 and iOS 15.1 Beta 2.

All workarounds do not work for me.
Comment 16 asanand 2021-10-04 09:28:41 PDT
This issue still seems to be happening on iOS 15.
The audio is switching to receiver speakers on enabling mic
Comment 17 David Gölzhäuser 2021-10-04 23:18:34 PDT
I am currently working on a workaround, I made some progress.


Here is our use case.

Web based WebRTC Application that initially receives a Video Stream, then when calling the remote peer the local and remote audio will be enabled

The current implementation acquired the devices local microphone stream and added its track to the RTCPeerConnection, this triggered a renegotiate and eventually in receiving the remote peers audio stream. => Remote Audio was emitted through the earpiece

I restructured this behavior because I noticed the correct speaker is used when first receiving the remote peers audio stream and then acquiring the local devices microphone stream. => Remote Audio was emitted through the speaker

However, this only works once per app livecycle (Cordova based App). So I am still working on it, but its an improvement.


FYI:
I simply add the empty Track `audioContext.createMediaStreamDestination().stream.getAudioTracks()[0]` to the RTCPeerConnection, then when the mic stream is acquired I simply replace the former added track with the local microphone track of the resulting RTCSender (from the RTCPeerConnections function `addTrack`)
Comment 18 Varun D 2021-11-28 08:55:03 PST
Thanks for the trick.
I tried this solution. This improved audio level - but only till the code acquired MIC stream.
If I deny the Mic permission when it is asked later - the volume still continued to be good. But as soon as I say 'yes' to mic permissions - volume goes to very low.
I am using iPhone XR with 15.1 iOS.
May I know what is your setup where it stayed High even after giving mic permissions? @David

(In reply to David Gölzhäuser from comment #17)
> I am currently working on a workaround, I made some progress.
> 
> 
> Here is our use case.
> 
> Web based WebRTC Application that initially receives a Video Stream, then
> when calling the remote peer the local and remote audio will be enabled
> 
> The current implementation acquired the devices local microphone stream and
> added its track to the RTCPeerConnection, this triggered a renegotiate and
> eventually in receiving the remote peers audio stream. => Remote Audio was
> emitted through the earpiece
> 
> I restructured this behavior because I noticed the correct speaker is used
> when first receiving the remote peers audio stream and then acquiring the
> local devices microphone stream. => Remote Audio was emitted through the
> speaker
> 
> However, this only works once per app livecycle (Cordova based App). So I am
> still working on it, but its an improvement.
> 
> 
> FYI:
> I simply add the empty Track
> `audioContext.createMediaStreamDestination().stream.getAudioTracks()[0]` to
> the RTCPeerConnection, then when the mic stream is acquired I simply replace
> the former added track with the local microphone track of the resulting
> RTCSender (from the RTCPeerConnections function `addTrack`)
Comment 19 Varun D 2021-11-28 09:10:15 PST
Update: the above trick did work for me in iOS chrome *once, but not always* - but never in Safari. 
(In reply to Varun D from comment #18)
> Thanks for the trick.
> I tried this solution. This improved audio level - but only till the code
> acquired MIC stream.
> If I deny the Mic permission when it is asked later - the volume still
> continued to be good. But as soon as I say 'yes' to mic permissions - volume
> goes to very low.
> I am using iPhone XR with 15.1 iOS.
> May I know what is your setup where it stayed High even after giving mic
> permissions? @David
> 
> (In reply to David Gölzhäuser from comment #17)
> > I am currently working on a workaround, I made some progress.
> > 
> > 
> > Here is our use case.
> > 
> > Web based WebRTC Application that initially receives a Video Stream, then
> > when calling the remote peer the local and remote audio will be enabled
> > 
> > The current implementation acquired the devices local microphone stream and
> > added its track to the RTCPeerConnection, this triggered a renegotiate and
> > eventually in receiving the remote peers audio stream. => Remote Audio was
> > emitted through the earpiece
> > 
> > I restructured this behavior because I noticed the correct speaker is used
> > when first receiving the remote peers audio stream and then acquiring the
> > local devices microphone stream. => Remote Audio was emitted through the
> > speaker
> > 
> > However, this only works once per app livecycle (Cordova based App). So I am
> > still working on it, but its an improvement.
> > 
> > 
> > FYI:
> > I simply add the empty Track
> > `audioContext.createMediaStreamDestination().stream.getAudioTracks()[0]` to
> > the RTCPeerConnection, then when the mic stream is acquired I simply replace
> > the former added track with the local microphone track of the resulting
> > RTCSender (from the RTCPeerConnections function `addTrack`)
Comment 20 David Gölzhäuser 2021-11-29 00:23:25 PST
Hi Varun,

This trick only works once per app session on WKWebView (which is also used by Chrome). I did not try this in the Safari Browser yet.

Try to close Chrome and reopen it after it worked once to see that it only works once per app session.
Comment 21 Varun D 2021-12-02 01:46:13 PST
(In reply to David Gölzhäuser from comment #20)
> Hi Varun,
> 
> This trick only works once per app session on WKWebView (which is also used
> by Chrome). I did not try this in the Safari Browser yet.
> 
> Try to close Chrome and reopen it after it worked once to see that it only
> works once per app session.

Thanks!
Did work on Safari as well.
Comment 22 Aqly 2022-01-06 00:04:37 PST
(In reply to David Gölzhäuser from comment #17)
> I am currently working on a workaround, I made some progress.
> 
> 
> Here is our use case.
> 
> Web based WebRTC Application that initially receives a Video Stream, then
> when calling the remote peer the local and remote audio will be enabled
> 
> The current implementation acquired the devices local microphone stream and
> added its track to the RTCPeerConnection, this triggered a renegotiate and
> eventually in receiving the remote peers audio stream. => Remote Audio was
> emitted through the earpiece
> 
> I restructured this behavior because I noticed the correct speaker is used
> when first receiving the remote peers audio stream and then acquiring the
> local devices microphone stream. => Remote Audio was emitted through the
> speaker
> 
> However, this only works once per app livecycle (Cordova based App). So I am
> still working on it, but its an improvement.
> 
> 
> FYI:
> I simply add the empty Track
> `audioContext.createMediaStreamDestination().stream.getAudioTracks()[0]` to
> the RTCPeerConnection, then when the mic stream is acquired I simply replace
> the former added track with the local microphone track of the resulting
> RTCSender (from the RTCPeerConnections function `addTrack`)

Hi,

Do you mind sharing sample codes on how you did it?
Comment 23 ztb 2022-01-06 11:17:28 PST
Is a patch being proposed to address this issue as it is very serious?
Comment 24 David Gölzhäuser 2022-01-10 02:38:35 PST
To shed a bit more light on this issue.

I created a issue using the Feedback-Assistent App on August the 3rd linking multiple WebKit bugs describing the same or similar issues (including this one).

After every Beta or Public release of iOS I check the behaviour and update the issue with the current state -> No Feedback whatsoever from Apple.

As our application relies on that WebRTC Audio Calls it is a critical issue. I also created an TSI (Technical Support Incident) as our Application is available in the AppStore. The response was like "You already created an issue, please use the issue to track it, we won't help you here." -> TSI wasted


Now we are in 2022 with no response from Apple whatsoever. 

This is a very serious bug.
Comment 25 youenn fablet 2022-01-10 02:45:10 PST
This is probably addressed by https://bugs.webkit.org/show_bug.cgi?id=233316.
Comment 26 David Gölzhäuser 2022-01-10 04:40:11 PST
Hey Youenn,

Thanks for taking care of https://bugs.webkit.org/show_bug.cgi?id=233752 and for checking out this issue.

I just revisited the issue after the new year break and indeed, it appears to be fixed in iOS 15.3 Beta 1. I just tested it myself in the office and not via remote. (I don't know why I did suspect it not to work when I tested it in Homeoffice.)

Thanks for taking care of this 👍
Comment 27 youenn fablet 2022-01-10 05:24:06 PST
(In reply to David Gölzhäuser from comment #26)
> Hey Youenn,
> 
> Thanks for taking care of https://bugs.webkit.org/show_bug.cgi?id=233752 and
> for checking out this issue.
> 
> I just revisited the issue after the new year break and indeed, it appears
> to be fixed in iOS 15.3 Beta 1. I just tested it myself in the office and
> not via remote. (I don't know why I did suspect it not to work when I tested
> it in Homeoffice.)
> 
> Thanks for taking care of this 👍

I am not sure the fix is in iOS 15.3 beta.
Comment 28 David Gölzhäuser 2022-01-10 06:20:35 PST
I will take a close look on any upcoming iOS Beta. At least our issue is fixed on that iOS version. It's "Case 2" of the initial post.
Comment 29 ztb 2022-01-10 10:01:45 PST
Hi Youenn,

Appreciate you being responsive to the community.

2 questions....

1st question....

Does this patch also address https://bugs.webkit.org/show_bug.cgi?id=230902 as I understood the core issue to be the same and should bot be fixed now in your opinion?

Second question.....

Is there any way to track when fixes get into iOS?

There are several critical bugs that are closed (https://bugs.webkit.org/show_bug.cgi?id=232822 for example) or have submitted patches but aren't in any version of iOS and once they are closed no more updates happen.

Am I missing where the released iOS version is being documented?
Comment 30 David Gölzhäuser 2022-01-13 00:01:24 PST
After updating to iOS 15.3 Beta 2 I am able to reproduce this issue again
Comment 31 StillTravelling 2022-02-07 00:25:40 PST
This is definitely happening to me on iPad Pro 2019 on 15.4 beta 1. Creating the context before the capturing does not resolve the issue. Stopping the mic track does not return the volume to normal.

Testing on iPhone XS on 15.4 beta 1 results in some differences. Stopping the mic track does not return the volume to normal, however if I restart the mic capture again after originally getting permissions, the volume is normal.
Comment 32 youenn fablet 2022-02-07 01:16:35 PST
(In reply to StillTravelling from comment #31)
> This is definitely happening to me on iPad Pro 2019 on 15.4 beta 1. Creating
> the context before the capturing does not resolve the issue. Stopping the
> mic track does not return the volume to normal.

The fix is only affecting audio rendering of MediaStreamTrack, not WebAudio (potentially other non-MediaStreamTrack media elements as well).
The current workaround for getting regular volume for web audio is to render WebAudio through a MediaStreamAudioDestinationNode. 

> Testing on iPhone XS on 15.4 beta 1 results in some differences. Stopping
> the mic track does not return the volume to normal, however if I restart the
> mic capture again after originally getting permissions, the volume is normal.

Thanks for the testing.
I filed https://bugs.webkit.org/show_bug.cgi?id=236219, let's continue the discussion there.
Comment 33 Brent Fulgham 2022-02-08 21:40:17 PST
Please continue the investigation of remaining issues in Bug 236219.
Comment 34 Bryce Aebi 2023-03-01 22:59:06 PST
Issue persists on iOS 16.2

Our entire web app is rendered unusable on iPhone due to this bug. I am happy to assist in any way to get this bug resolved. Thank you
Comment 35 Bryce Aebi 2023-03-01 22:59:23 PST
Issue persists on iOS 16.2

Our entire web app is rendered unusable on iPhone due to this bug. I am happy to assist in any way to get this bug resolved. Thank you
Comment 36 Bryce Aebi 2023-03-02 09:36:37 PST
I've mentioned this on the related bug, but will repeat here as it's relevant to this one as well. 

I have tried both WebAudio and routing the WebAudio through a MediaStreamAudioDestinationNode. This was on both iOS 16.2 and iOS 16.4. The volume issue persists regardless of the audio routing or iOS version.
Comment 37 Bryce Aebi 2023-03-02 12:42:44 PST
SOLUTION FOR POSTERITY:

The solution to this issue is to manually set the following BEFORE mic capture:

navigator.audioSession.type = 'play-and-record';

And then running the following AFTER mic capture

navigator.audioSession.type = 'playback';

I have confirmed that this resolves the issue in iOS 16.4 beta 2. More details about this setting can be viewed here: https://github.com/w3c/audio-session/blob/main/explainer.md
Comment 38 Justin Higgins 2023-03-13 16:42:37 PDT
Hey Bryce, is the navigator.audioSession.type API only available on iOS 16.4 beta 2? Not seeing it on iOS 16.2
Comment 39 Bryce Aebi 2023-03-13 19:34:27 PDT
Justin, I am not sure. I updated my phone to 16.4 beta 2 and haven't had a chance to test on lower versions yet. What do you mean when you say you are "not seeing it on iOS 16.2"? Are you seeing an error in the console when you try to access it?
Comment 40 Justin Higgins 2023-03-13 19:57:27 PDT
> Are you seeing an error in the console when you try to access it
Hey Bryce, yep, when in the js console for iOS safari 16.2, i get `undefined` for navigator.audioSession
Comment 41 Bryce Aebi 2023-03-13 20:17:54 PDT
Thanks for the response Justin, that's good to know. Do you mind testing if 16.3 works?

I'm guessing on 16.2 and below there isn't really any recourse then.
Comment 42 Justin Higgins 2023-03-14 09:37:09 PDT
> Thanks for the response Justin, that's good to know. Do you mind testing if 16.3 works?

Same issue on 16.3, I get `undefined` for navigator.audioSession in the js console
Comment 43 Tobi (onexip.com) 2023-06-19 01:42:49 PDT
setting the audioSession type back to "playback" after the microphone track is stopped (or WebSpeech is stopped) only helps sometimes, sometimes not. It seams that setting the type doesn't always works.
Comment 44 Tobi (onexip.com) 2023-06-20 14:35:57 PDT
any news here fixing the bug? Currently it's not possible to use recording and playback simultaniously on iOS :( On Android and native iOS it works.
Comment 45 Taimoor 2024-02-15 20:29:47 PST
None of the solutions work for me. I still see this issue in iOS 17.3.1. Please suggest any work arounds, our business rely on this and we are losing customers.
Comment 46 Tobi (onexip.com) 2024-03-11 07:23:04 PDT
Additionally to this bug, we have an "audio ducking problem". So If you play back audio using WebAudio and open the microphone stream in parallel, the audio volume decreased if the user talks to the microphone. Its like a "talk over" or "audio ducking" feature which can't be disabled.

Event disabling the mic track does not help.