Safari Audio Not Working On Web SDK 1.4.0

Description

Hi Zoom Team,

I read through a related topic (#69650 - Audio not joining in Safari) and I am still encountering the same issue where Safari audio simply does not work. I’ve tried to start audio automatically and with a button press but still no progress. I am not getting any console error oddly enough.

Any help here would be immensely appreciated!

P.S.
Apologies in advance for creating the same ticket but the previous one was closed.

Browser Console Error
N/A

Which Web Video SDK version?
Initially - 1.2.7
Later on - 1.4.0

Video SDK Code Snippets

automatically:

if (decode && encode) {
   try {
     stream.startAudio({ autoStartAudioInSafari: true });
   } catch (err) {
     console.warn(err);
   }
}

button press:

if (decode && encode) {
  stream.startAudio()
}

To Reproduce(If applicable)
Steps to reproduce the behavior:

  1. Follow the documentation for startAudio on Safari
  2. Doesn’t work

Screenshots
N/A

Troubleshooting Routes

Device (please complete the following information):

  • Device: M1 Macbook Pro
  • OS: macOS 12.2.1
  • Browser: Safari
  • Browser Version 15.3 (17612.4.9.1.8)

Additional context
I am testing locally on the same machine between a Chrome user and a Safari user. If audio was working, I’d hear an echo.

Hey @brendonion

Could you serve your webpage on a web server? Sometimes the Safari audio cannot work in the local environment.
And could you take a look at our sample app?

Thanks
Vic

Hi Vic.

I tested again on a hosted environment and the audio is still not working. I’m logging everything and it should work, but doesn’t.

if (encode && decode) {
    stream
         .startAudio()
         .then(() => console.log("Safari audio initialized successfully!"))
         .catch((e) => console.log("Safari audio failed to initialize: ", e))
} else {
    console.log("Safari audio has not been initialized...")
}

And the console returns “Safari audio initialized successfully!”

Any ideas here?

Thank you.

Hey Brendan, we had lots of issues with waiting for the Stream to finish initializing before we were able to call startAudio successfully. Is it possible stream is null or undefined right before your startAudio is called? Recommend trying to log the stream in your pseudocode example to check for that scenario.

Hi Parker,

No it’s not possible the stream is null or undefined. I check the stream value before this gets called and it’s getting to the .then promise handler. I can try logging stream just in case though. Any other ideas here would be greatly appreciated :slight_smile: .

Thank you

Hi @brendonion

how do you set encode and decode variables?

I hope you are using “media-sdk-change” event and then using the below code to set the encode and decode variable

const { action, type, result } = payload;
    if (type === "audio" && result === "success") {
      if (action === "encode") {
        audioEncode = true;
      } else if (action === "decode") {
        audioDecode = true;
      }
    }

For me this setup works on safari browser.

Hi @gourishmesta1993

Our code looks similar to this:
(using redux as a local store)

// file 1 (watch for media changes)
client.on("media-sdk-change", onMediaSDKChange)

const onMediaSDKChange = useCallback((payload) => {
    const { action, type, result } = payload
    const payload = { type: type, action: action, result: result === "success" } // converts to boolean
    dispatch(setMediaShape(payload))
}, [])

// file 2 (redux action)
const setMediaShape = (state, action) => {
    const mediaShape = state.mediaShape
    const mediaType = action.payload.type
    const mediaShapeAction = action.payload.action
    if (mediaType && mediaShapeAction) {
        mediaShape[mediaType][mediaShapeAction] = action.payload.result
    }
}

// file 3 (button click)
const onAudioClick = useCallback(() => {
    if (isStartedAudio) {
      dispatch(setIsMuted(!isMuted))
    } else {
      // this is where audio is triggered
      dispatch(setIsStartedAudio(true))
      dispatch(setIsMuted(false))
    }
}, [mediaStream, isStartedAudio, isMuted])

// file 4 (react hook)
useEffect(() => {
    if (isStartedAudio === null) {
      return
    }

    const isCurrentUserStartedAudio = zmClient.getCurrentUserInfo()?.audio.length > 0 && isStartedAudio

    const handleSafariAudio = () => {
      if (mediaShape.audio.encode && mediaShape.audio.decode) {
        mediaStream
          .startAudio()
          .then(() => console.log("Safari audio initialized successfully!")) // gets here successfully, still no audio
          .catch((e) => console.log("Safari audio failed to initialize: ", e))
      } else {
        console.log("Safari audio has not been initialized...")
      }
    }

    if (isStartedAudio && mediaStream) {
      if (!isCurrentUserStartedAudio) {
        if (isSafari) {
          handleSafariAudio()
        } else {
          mediaStream.startAudio()
        }
      }

      if (isCurrentUserStartedAudio) {
        if (isMuted) {
          mediaStream.muteAudio()
        } else {
          mediaStream.unmuteAudio()
        }
      }
    }
  }, [mediaStream, isStartedAudio, isMuted, zmClient, mediaShape])

Maybe the useEffect above is being called a couple times and that is causing an issue? I’m not sure but I hope this clears things up for how we are handling the audio logic.

Thank you.

Hey @brendonion

As the document mentioned, stream.startAudio should be in the event handler on Safari. So the code can be modified like this:

const onAudioClick = useCallback(() => {
    if (isStartedAudio) {
      if (!isMuted) {
        mediaStream.muteAudio()
      } else {
        mediaStream.unmuteAudio()
      }
    } else {
      if (isSafari) {
        handleSafariAudio()
      } else {
        mediaStream.startAudio()
      }
    }
}, [mediaStream, isStartedAudio, isMuted])

Thanks
Vic

@vic.yang

Tried that and still nothing. Console logs successfully strangely enough. I’m running out of ideas here :sweat:

@brendonion
How do u check isSafari?

And did u try adding the below code after @vic.yang gave u the fix?

await mediaStream.startAudio({
          autoStartAudioInSafari: true
        });

@gourishmesta1993

const isSafari = navigator.userAgent.indexOf('Safari') > -1 && navigator.userAgent.indexOf('Chrome') === -1

It is running the code. It gets to console.log("Safari audio initialized successfully!") but still silence. Even tried the button click callback with {autoStartAudioInSafari: true} and still no luck.

@brendonion
can u log the content of mediaShape object once handleSafariAudio is called?
just want to cross check the data of mediaShape object

Thank You
@gourishmesta1993

@gourishmesta1993

{
  audio: {encode: true, decode: true},
  video: {encode: true, decode: true},
  share: {encode: true, decode: true}
}

Another update:

I tried the demo react app on localhost with two safari browsers. Oddly enough the Local Preview echoed just fine, but joining a Subsession for both browsers the audio is still void. Very odd.

Hey @brendonion

In-session audio on the localhost environment of Safari may not work, it’s a known issue. As I mentioned above, could you test it on the Web server?

Thanks
Vic