opentok / opentok-react

React components for OpenTok.js
https://www.npmjs.com/package/opentok-react
MIT License
107 stars 105 forks source link

How to attach MediaStream #160

Open falecci opened 3 years ago

falecci commented 3 years ago

Hi folks,

I want to request microphone and camera permissions before actually making a call (like Skype/Meet web does). I was planning to use navigator.mediaDevices.getUserMedia(), save the media stream in memory to later use it with this library. For instance, something like this:

const [localStream, setLocalStream] = useState(null);
useEffect(() => {
    navigator.mediaDevices.getUserMedia({ video: true, audio: true })
        .then(stream => { setLocalStream(stream); })
        .catch(err => throw new Error('User has denied media'));
}, []);

return (
   <>
        <OTStreams>
                <OTSubscriber
                  stream={localStream}
                />
        </OTStreams>
        <OTPublisher
              properties={{
                ...publisherProperties,
                publishAudio: isAudioEnabled,
                publishVideo: isVideoEnabled,
              }}
              onError={handleError}
         />
   </>
)

Is this possible? The streams I see in opentok-react are not MediaStreams.

gbrocha commented 3 years ago

Hello! I tried to implement this scenario here, but it was not possible using the components of this lib.(because the lib components needs the session instance) I had to implement my own component using @ opentok / client

gbrocha commented 3 years ago

Something like this:

useEffect(() => {
    const publish = async () => {
      try {
        const stream = await OT.getUserMedia()
        // Stop the tracks so that we stop using this camera and microphone
        // If you don't do this then cycleVideo does not work on some Android devices
        stream.getTracks().forEach(track => track.stop())

        const newPublisher = OT.initPublisher(publisherElemRef.current, {
          width: '100%',
          height: '100%',
          fitMode: fitMode || 'contain',
          style: {
            audioLevelDisplayMode: 'off',
            nameDisplayMode: 'off',
            buttonDisplayMode: 'off',
          },
        })

        setPublisher(newPublisher)
      } catch (err) {
        errorLog(err)
      }
    }

    publish()
  }, [fitMode])
gbrocha commented 3 years ago

publisherElemRef can be an empty div on the component

falecci commented 3 years ago

Something like this:

useEffect(() => {
    const publish = async () => {
      try {
        const stream = await OT.getUserMedia()
        // Stop the tracks so that we stop using this camera and microphone
        // If you don't do this then cycleVideo does not work on some Android devices
        stream.getTracks().forEach(track => track.stop())

        const newPublisher = OT.initPublisher(publisherElemRef.current, {
          width: '100%',
          height: '100%',
          fitMode: fitMode || 'contain',
          style: {
            audioLevelDisplayMode: 'off',
            nameDisplayMode: 'off',
            buttonDisplayMode: 'off',
          },
        })

        setPublisher(newPublisher)
      } catch (err) {
        errorLog(err)
      }
    }

    publish()
  }, [fitMode])

Yeah, I was starting to think this wasn't possible with this wrapper. So, with OT.getUserMedia(), we don't need to establish a session yet, right?

Thanks for your help!

gbrocha commented 3 years ago

Something like this:

useEffect(() => {
    const publish = async () => {
      try {
        const stream = await OT.getUserMedia()
        // Stop the tracks so that we stop using this camera and microphone
        // If you don't do this then cycleVideo does not work on some Android devices
        stream.getTracks().forEach(track => track.stop())

        const newPublisher = OT.initPublisher(publisherElemRef.current, {
          width: '100%',
          height: '100%',
          fitMode: fitMode || 'contain',
          style: {
            audioLevelDisplayMode: 'off',
            nameDisplayMode: 'off',
            buttonDisplayMode: 'off',
          },
        })

        setPublisher(newPublisher)
      } catch (err) {
        errorLog(err)
      }
    }

    publish()
  }, [fitMode])

Yeah, I was starting to think this wasn't possible with this wrapper. So, with OT.getUserMedia(), we don't need to establish a session yet, right?

Thanks for your help!

Yes, you only need to use OT.getUserMedia () to gain access to the media devices. Then, use OT.initPublisher to create an publisher and that's it.