This message was deleted.
# helpdesk
s
This message was deleted.
b
I'm using the LiveKit JavaScript SDK to connect participants to a room. I'm not getting any audio from any participants that join the room. The participants are not muted and have given browser permission to publish audio. I've confirmed that RemoteParticipants have published an audio track and that the LocalParticipant is subscribed to that audio track. I'm also seeing the active speaker border around participants that are speaking, but I don't actually get any audio. Any thoughts on what might be going on?
I am using the LiveKitRoom react component if that's helpful, which I believe handles publishing tracks and turning them on
m
cc @eager-zoo-16408
d
is the user that isn't able to get audio publishing any audio themselves? you might need an user-interaction on the browser before audio tracks could playback. We have a StartAudio component that does just that. Or you can handle it yourself like this
b
All the users are publishing audio in that the track says it’s publishing, but they can’t hear anything. Also yeah since I’m using the live kit component the start audio component is showing up, but clicking on it doesn’t have any effect.
e
Hey @billions-summer-21168, are you using the
<RoomAudioRenderer />
(https://github.com/livekit/components-js/blob/main/packages/react/src/components/RoomAudioRenderer.tsx) component to render the audio or have you implemented something custom at the participant level?
b
Hey @eager-zoo-16408, this is super helpful! I am not using
RoomAudioRenderer
. I actually am not using the
VideoConference
component at all and have replaced it with something custom, but that custom piece is missing the
RoomAudioRenderer
Is there anything else I need to do besides drop that component in to my custom
VideoConference
replacement? I just dropped it in but I'm still not getting audio
e
No, you should hear audio if you place the
RoomAudioRenderer
as a child of the
LiveKitRoom
component. Do you get any error message in the console? Can you share some code to show what your implementation looks like?
b
Aha I do see some new console errors after adding the
RoomAudioRenderer
, which says
could not playback audio DOMException: The play() request was interrupted by a new load request
Here's what my implementation looks like:
This is where we use the
LiveKitRoom
and within it, our custom component called
SessionLayout
which replaces the
VideoConference
Copy code
<LiveKitRoom
        room={room}
        token={token}
        serverUrl={process.env.NEXT_PUBLIC_LIVEKIT_SERVER_URL}
        connect={true}
        video={true}
        audio={true}
        data-lk-theme="default"
        style={{ backgroundColor: 'transparent' }}
        onConnected={() => setConnected(true)}
        onDisconnected={() => {
          router.replace('/join')
        }}
      >
        {connected && (
          <SessionLayout
            cameraControlEnabled={cameraControlEnabled}
            microphoneControlEnabled={microphoneControlEnabled}
            selfViewVisible={selfViewVisible}
            endCallEnabled={endCallEnabled}
            canvasVisible={canvasVisible}
          />
        )}
      </LiveKitRoom>
SessionLayout
was copied from
VideoConference
so a lot of it should look similar but with some functional and UI tweaks we wanted to make. I added
RoomAudioRenderer
to the end of this component.
Copy code
export default function SessionLayout({
  cameraControlEnabled,
  microphoneControlEnabled,
  selfViewVisible,
  endCallEnabled,
  canvasVisible,
}: SessionLayoutProps) {
  const participantIdentities = useParticipants().map((p) => p.identity)
  const roomName = useRoomContext().name
  const tracks = filterLocalTrack(
    useTracks(
      [
        { source: Track.Source.Camera, withPlaceholder: true },
        { source: Track.Source.ScreenShare, withPlaceholder: false },
      ],
      { updateOnlyOn: [RoomEvent.ActiveSpeakersChanged] }
    ),
    selfViewVisible
  )
  const screenShareTracks = tracks
    .filter(isTrackReference)
    .filter((track) => track.publication.source === Track.Source.ScreenShare)
  const layoutContext = useCreateLayoutContext()
  const focusTrack = filterLocalTrack(
    usePinnedTracks(layoutContext),
    selfViewVisible
  )?.[0]

  const carouselTracks = tracks.filter(
    (track) => !isEqualTrackRef(track, focusTrack)
  )
  const [showControlPanel, setShowControlPanel] = useState(false)
  const [widgetState, setWidgetState] = useState<WidgetState>({
    showChat: false,
  })

  const [clipboardOpen, setClipboardOpen] = useState(false)
  const userContext = useUser()

  useEffect(() => {
    // if screen share tracks are published, and no pin is set explicitly, auto set the screen share
    if (
      screenShareTracks.length > 0 &&
      focusTrack === undefined &&
      !canvasVisible
    ) {
      layoutContext.pin.dispatch?.({
        msg: 'set_pin',
        trackReference: screenShareTracks[0],
      })
    } else if (
      (screenShareTracks.length === 0 &&
        focusTrack?.source === Track.Source.ScreenShare) ||
      tracks.length <= 1 ||
      canvasVisible
    ) {
      layoutContext.pin.dispatch?.({ msg: 'clear_pin' })
    }
  }, [
    JSON.stringify(screenShareTracks.map((ref) => ref.publication.trackSid)),
    tracks.length,
    focusTrack?.publication?.trackSid,
    canvasVisible,
  ])

  const copyUrl = async () => {
    try {
      await navigator.clipboard.writeText(window.location.href.split('?')[0])
      setClipboardOpen(true)
    } catch (err) {
      console.error('Failed to copy: ', err)
    }
  }

  const widgetUpdate = (state: WidgetState) => {
    log.debug('updating widget state', state)
    setWidgetState(state)
  }

  const handleClipboardClose = (
    event?: React.SyntheticEvent | Event,
    reason?: string
  ) => {
    if (reason === 'clickaway') {
      return
    }

    setClipboardOpen(false)
  }

  return (
    <div className="lk-video-conference">
      <LayoutContextProvider
        value={layoutContext}
        // onPinChange={handleFocusStateChange}
        onWidgetChange={widgetUpdate}
      >
        <div
          className="lk-video-conference-inner"
          style={{ height: 'calc(100vh - 24px)' }}
        >
          {!focusTrack && !canvasVisible ? (
            <div className="lk-grid-layout-wrapper">
              <GridLayout tracks={tracks}>
                <ParticipantTile />
              </GridLayout>
            </div>
          ) : (
            <div className="lk-focus-layout-wrapper">
              <FocusLayoutContainer>
                <CarouselView tracks={carouselTracks}>
                  <ParticipantTile />
                </CarouselView>
                {focusTrack && <FocusLayout track={focusTrack} />}
                {canvasVisible && (
                  <div className="lk-participant-tile">
                    <Canvas />
                  </div>
                )}
              </FocusLayoutContainer>
            </div>
          )}
          <ControlBar
            controls={{
              chat: true,
              microphone: microphoneControlEnabled,
              camera: cameraControlEnabled,
              leave: endCallEnabled,
            }}
          >
            {userContext.isLoading && <CircularProgress />}
            {userContext.user && (
              <>
                <button
                  className="lk-button"
                  style={{ backgroundColor: '#38C9BA' }}
                  onClick={copyUrl}
                >
                  Copy Join Link
                </button>
                <button
                  className="lk-button"
                  style={{ backgroundColor: '#38C9BA' }}
                  onClick={() => setShowControlPanel(!showControlPanel)}
                >
                  {`${showControlPanel ? 'Hide' : 'Show'} Control Panel`}
                </button>
                <button
                  className="lk-button"
                  style={{ backgroundColor: '#38C9BA' }}
                  onClick={() => {
                    toggleCanvas(participantIdentities, roomName, canvasVisible)
                  }}
                >
                  {`${canvasVisible ? 'Hide' : 'Show'} Canvas`}
                </button>
              </>
            )}
          </ControlBar>
        </div>
        <Chat style={{ display: widgetState.showChat ? 'flex' : 'none' }} />
        {userContext.user && (
          <ControlPanel
            open={showControlPanel}
            togglePanel={setShowControlPanel}
          />
        )}
        <Snackbar
          anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
          open={clipboardOpen}
          autoHideDuration={1500}
          onClose={handleClipboardClose}
        >
          <Alert
            onClose={handleClipboardClose}
            severity="success"
            sx={{ width: '100%' }}
          >
            Copied Link to clipboard!
          </Alert>
        </Snackbar>
      </LayoutContextProvider>
      <RoomAudioRenderer />
    </div>
  )
}
👀 1
Interestingly I'm getting audio when I'm in a room via Safari, but not via Chrome
e
@billions-summer-21168 thanks for the code 👍 Based on the error you are getting, I could imagine that there is a render loop in the code. Could you check to see if something is causing a constant rerender of your
SessionLayout
component? Could you replace your custom
SessionLayout
component with the default
VideoConference
component to see if the audio works for you?
b
Yeah I had tried that yesterday to try and narrow things down...I just tried it again and I see the same console warning
could not playback audio DOMException: The play() request was interrupted by a new load request.
e
Cool 🙏. What livekit client version are you using?
If you have to same error with the latest version then I will look into it and get back to you. Thank you for you cooperation 👍🏼
b
I've also just stripped everything away from the code surrounding the
LiveKitRoom
and I still see the same console warning...Do you see anything in this that would lead to a render loop?
Copy code
import { LiveKitRoom, VideoConference, useToken } from '@livekit/components-react'
import '@livekit/components-styles'
import CircularProgress from '@mui/material/CircularProgress'
import {
  Room,
} from 'livekit-client'
import { NextPage } from 'next'
import { useRouter } from 'next/router'
import { useMemo, useState } from 'react'
import { v4 } from 'uuid'

const SessionRoom: NextPage = () => {
  const router = useRouter()
  const room = new Room()

  const { roomId, name } = router.query
  const roomName = roomId as string
  const displayName = name ? (name as string) : 'User'
  const identity = useMemo(() => v4(), [])
  const options = {
    userInfo: {
      identity: identity,
      name: displayName,
    },
  }
  const token = useToken('/api/clinician-access-token', roomName, options)

  return token ? (
    <div>
      <LiveKitRoom
        room={room}
        token={token}
        serverUrl={process.env.NEXT_PUBLIC_LIVEKIT_SERVER_URL}
        connect={true}
        video={false}
        audio={true}
        data-lk-theme="default"
        style={{ backgroundColor: 'transparent' }}
        onDisconnected={() => {
          router.replace('/join')
        }}
      >
        <VideoConference />
      </LiveKitRoom>
    </div>
  ) : (
    <div
      style={{
        width: '100vw',
        height: '100vh',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <CircularProgress />
    </div>
  )
}
Cool 🙏. What livekit client version are you using?
I was using 1.7.1 for
livekit-client
I just updated to 1.10.0 and I still see the same thing, with the added console warning of
volume can only be set on remote audio tracks
Hi there @eager-zoo-16408 or anyone else that might be able to help - Any pointers in the right direction or things that I can try? At this point things are stripped down to using LiveKit's react components pretty similar to the snippet found in Get started here and I'm still not hearing audio. It's somewhat urgent as I have some user testing scheduled for a couple days from now, any chance at scheduling something synchronous to debug together?
d
can you share a version of the app so we could take a look?
can you reproduce it on meet.livekit.io ?
b
The app is not publicly available yet. We could schedule some time to get on a call and invite someone into a video session but I'd need to be present to do that.
I can not reproduce it on meet.livekit.io. I'm getting audio from that just as I'd expect
e
@billions-summer-21168 we are investigating the problem but so far we can’t reproduce it. Can you provide us with a minimal example repo so we can narrow down the range of possible problems? Perhaps an easier way is to use the minimal example from our repo. Setup steps:
Copy code
git clone git@github.com:livekit/components-js.git
cd components-js
yarn install
Copy and rename the
examples/nextjs/.env.example
to
examples/nextjs/.env
and update the content with your LiveKit Cloud credentials. Then run
yarn dev:next
, open http://localhost:3000/minimal?user=A in one browser and http://localhost:3000/minimal?user=B in another and see if you still get the same error.
b
Yep, I will work on this right now! Thanks for your support
@eager-zoo-16408 Ok so I've gotten this up and running and done some testing - it seems to be behaving similarly to what we have built: • Chrome: On Chrome I'm not getting any audio. As soon as a second user joins, both browsers show a console warning saying
could not playback audio DOMException: The play() request was interrupted by a new load request.
Safari: If I'm using Safari I am getting audio, but I only seem to be getting audio from the second participant that joins. I tested with 3 participants and only the third seemed to be transmitting audio to the other two? • Firefox: I tested with 3 participants and all three were receiving audio just fine?
What browser(s) have y'all been using to recreate?
Just for clarity too in case it matters, the way I've been testing is opening up multiple browsers, each with a different participant, and talking to see if I get audio coming out of the other participant browsers.
Following up again @eager-zoo-16408 - I learned that adding
RoomAudioRenderer
and pushing that to production fixed the issue across all the browsers...However it doesn't work locally? These descriptions are still happening locally 🤔
e
Thank you for all the data points @billions-summer-21168! We usually test it the same way you did (with Chrome, Firefox and Safari). We can confirm that we also see the same warning, but the audio still gets through without any problems. Based on your description that the problem only happens in development, I suspect that React Strict mode is the root of the problem.
Strict Mode enables the following development-only behaviors:
• Your components will re-render an extra time to find bugs caused by impure rendering.
• Your components will re-run Effects an extra time to find bugs caused by missing Effect cleanup.
We need to investigate further to see if we can handle this better from our end. So if you could share a repo with which you can reliably reproduce the bug, we would be very grateful! This could speed up fixing and releasing a new version quite a bit.