jamalag / webrtc-Part-4

WebRTC Let's learn together (ReactNative) - Part 4
15 stars 13 forks source link

_reactNativeWebrtc.MediaStreamTrack.getSources is not a function #3

Closed adrien-prototype closed 4 years ago

adrien-prototype commented 4 years ago

Hi @jamalag ,

We spoke before through comments on your youtube webrtc serie. Once again, thank you so much for this great work. I have an issue running react-native-webrtc on ios. I'm doing everything you do in Xcode in the video, tried also other things, went back and fourth for a few days now, and I still have that nasty TypeError : " _reactNativeWebrtc.MediaStreamTrack.getSources is not a function".

Have you ever encounter this before ? I’m using : I have the same package.json you have on the repo. My Xcode Version is 11.4.1 and I use a real device (iphone 8)

My Xcode build is succeeding, the app launches and then crashes with this error. Any tip would be very welcome since I’ve been scratching my head on this for several evenings now. I reinstalled all packages, tried different xcode build configurations, and almost know by heart everything you need to do to install react-native-webrtc on ios 😓

Thank you very much !!

jamalag commented 4 years ago

Hi adrien, do you know if the error is thrown while enumerating devices at ...

mediaDevices.enumerateDevices().then(sourceInfos => {

jamalag commented 4 years ago

BTW, if possible could you copy and paste your App.js code so that I can have a look at it?

adrien-prototype commented 4 years ago

Hi Amir,

I couldn't tell at the moment if the error is thrown while enumerating devices like you said. I'm sorry but how can I check for this ?

Here is my App.js code :

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React from 'react'
import {
  SafeAreaView,
  StyleSheet,
  ScrollView,
  View,
  Text,
  StatusBar,
  Dimensions
} from 'react-native'
import Video from './video.js'

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={styles.scrollView}>
          <View style={styles.body}>
           <Video />
          </View>
        </ScrollView>
      </SafeAreaView>
    </>
  )
}

const styles = StyleSheet.create({
  scrollView: {
    backgroundColor: 'white',
  },
  body: {
    backgroundColor: 'white',
  }
})

export default App

Then my

import React from 'react'
import {
  AppRegistry,
  StyleSheet,
  Text,
  TouchableHighlight,
  View,
  TextInput,
  ListView,
  ScrollView,
  Dimensions,
  Image,
  Alert
} from 'react-native'

import PropTypes from 'prop-types'

import {
  RTCPeerConnection,
  RTCMediaStream,
  RTCIceCandidate,
  RTCSessionDescription,
  RTCView,
  RTCVideoView,
  MediaStreamTrack,
  getUserMedia,
} from 'react-native-webrtc'

import Janus from './janus.mobile.js'
import config from './config.js

let janus
let sfu = null
let started = false
let myUsername = 'Adrien'
let roomId = 1234

const wsServer = `ws://${config.server}:8188/`
Janus.init({
  debug: "all",
  callback: function() {
    if(started) {
      return
    }
    started = true
  }
})

class Video extends React.Component {
  constructor(props) {
    super(props)
    this.state ={
      info: 'Initializing',
      status: 'init',
      roomID: '',
      selfViewSrc: null,
      selfViewSrcKey: null
    }
  }

  componentDidMount(){
    this.janusStart()
  }

  janusStart() {
    janus = new Janus({
      server: wsServer,
      success: () => {
        console.log('success')
          janus.attach({
            plugin: "janus.plugin.videoroom",
            success: (pluginHandle) => {
              console.log('HANDLE $$$$$$$$$$$$$', pluginHandle)
              sfu = pluginHandle
              let register = { "request": "join", "room": roomId, "ptype": "publisher", "display": myUsername }
              sfu.send({"message": register})
              sfu.createOffer({
                media: { audio: true, video: true},
                success: (jsep) => {
                  console.log('$$$$$$$$$ JSEP', jsep)
                }
              })
            },
            error: (error) => {
              Alert.alert("  -- Error attaching plugin...", error)
            },
            consentDialog: (on) => {
            },
            mediaState: (medium, on) => {
              console.log( 'mediastate $$$$$$$$$$$$$$$', medium, on)
            },
            webrtcState: (on) => {
              console.log( 'webrtcstate $$$$$$$$$$$$$$$', on)
            },
            onmessage: (msg, jsep) => {
              console.log('onmessage $$$$$$$$$$$$$$$$', msg)
              const event = msg['videoroom']
              if(event != undefined && event != null) {
                if(event === 'joined') {
                    let myid = msg['id']
                    this.publishOwnFeed(true)
                    if(msg['publishers'] !== undefined && msg['publishers'] !== null) {
                      const list = msg[publishers]
                      for(const f in list) {
                        const id = list[f]['id']
                        const display = list[f]['display']
                        this.newRemoteFeed(id, display)
                      }
                    }
                } else if(event === 'destroyed') {
                  console.log('distroying')
                // } else if(event === 'event') {
                //   if(msg['publishers'] !== undefined && msg['publishers'] !== null) {
                //     const list = msg['publishers']
                //     for(const f in list) {
                //       let id = list[f]['id']
                //       let display = list[f]['display']
                //       this.newRemoteFeed(id, display)
                //     }
                //   } else if(msg['error'] !== undefined && msg['error'] !== null) {
                //     console.log(msg['error'])
                //   }
                }
              }
              if(jsep !== undefined && jsep !== null) {
                sfutest.handleRemoteJsep({jsep: jsep});
              }
            },
            onlocalstream: (stream) => {
              console.log('ONLOCALSTREAM stream $$$$$$$$$$', stream)
              console.log('ONLOCALSTREAM  stream to url $$$$$$$$$$', stream.toURL())
              this.setState({selfViewSrc: stream.toURL()})
              this.setState({selfViewSrcKey: Math.floor(Math.random() * 1000)})
              this.setState({status: 'ready', info: 'Please enter or create room ID'})
            },
            onremotestream: (stream) => {
              console.log('onremotestream', stream)
            },
            oncleanup: () => {
              console.log('Clean up')
            }
          })
      },
      error: (error) => {
        Alert.alert("Janus Error", error)
      },
      destroyed: () => {
        Alert.alert("Success for End Call")
      }
    })
  }

  publishOwnFeed(useAudio){
    sfu.createOffer({
      media: { audioRecv: false, videoRecv: false, audioSend: useAudio, videoSend: true},
      success: (jsep) => {
        console.log('$$$$$$$$$ JSEP', jsep)
        const publish = { 'request': 'publish', 'audio': useAudio, 'video': true }
        sfu.send({'message': publish, 'jsep': jsep})
      },
      error: (error) => {
        Alert.alert('WebRTC error:', error)
        // if (useAudio) {
        //   publishOwnFeed(false)
        // }
      }
    })
  }

  render() {
    return (
      <ScrollView>
        <View style={styles.container}>
          { this.state.selfViewSrc && <RTCView key={this.state.selfViewSrcKey} streamURL={this.state.selfViewSrc} style={styles.remoteView} /> }
        </View>
      </ScrollView>
    )
  }
}

const styles = StyleSheet.create({
  selfView: {
    width: 200,
    height: 150,
  },
  remoteView: {
    width: Dimensions.get('window').width,
    height: Dimensions.get('window').height/2.35
  },
  container: {
    flex: 1,
    justifyContent: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  listViewContainer: {
    height: 150,
  },
})

export default Video

I know it's not exactly like you do because I'm using janus here, but my error is really coming from react-native-webrtc so I thought you might have a solution. If you're curious about the janus library that I use it's coming from this file janus.mobile.js that I imported in my code : https://github.com/atyenoria/react-native-webrtc-janus-gateway/blob/master/src/janus.mobile.js I also have a janus web socket running that I can connect to.

Anyway, I think the error is throwing when I try to publish feed here : publishOwnFeed(useAudio){ sfu.createOffer({ media: { audioRecv: false, videoRecv: false, audioSend: useAudio, videoSend: true}, success: (jsep) => { console.log('$$$$$$$$$ JSEP', jsep) const publish = { 'request': 'publish', 'audio': useAudio, 'video': true } sfu.send({'message': publish, 'jsep': jsep}) }, error: (error) => { Alert.alert('WebRTC error:', error) // if (useAudio) { // publishOwnFeed(false) // } } }) }

Thank you so much for your help , if there's anything you'd like to use from my work on janus I'd be glad to share.

jamalag commented 4 years ago

ok give me sometime to digest what's happening as I have never used janus.

adrien-prototype commented 4 years ago

Sure, let me know if there's anything you need. Here is the JS API doc : https://janus.conf.meetecho.com/docs/JS.html And here is the doc for the videoroom plugin I'm using : https://janus.conf.meetecho.com/docs/videoroom.html

I guess it's pretty straight forward, I don't think I made any mistake with that. Though, I'm pretty sure something wrong with the way I use react-native-webrtc somehow.

Thanks again Amir !

adrien-prototype commented 4 years ago

I did not genuinely found why this was causing an error but I commented it in the janus.mobile.js file I am using. It seems the way react-native-webrtc mediastreamtrack was called wasn't correct. It's ok for me for now to comment it since I don't need it anyway. Looking forward for your next videos ! Thank you again.

jamalag commented 4 years ago

I was about to respond with request to clone your repo so that I can possibly help with debugging as I realized I have already spent sometime trying to understand janus.

adrien-prototype commented 4 years ago

I'm sorry I hope you didn't think it was too much lost time, in that case I truly apologise.

If you want to work on janus there are two very interestings repos here that you can check out (in case you'd like to use react-native) : https://github.com/atyenoria/janus-webrtc-gateway-docker https://github.com/atyenoria/react-native-webrtc-janus-gateway

jamalag commented 4 years ago

no worries at all adrien. I enjoy challenges :)

I thought the repos are yours?

I have actually already installed and running the docker container from the repo above. I am now figuring out how to connect to it. I guess I'll get the connection ideas from the other repo. Thanks for sharing.

jamalag commented 4 years ago

Hi adrien, I notice 11 days ago you tried to answer a question on accessing janus ... https://github.com/atyenoria/janus-webrtc-gateway-docker/issues/56 I am facing the exact issue - both ips dont work. the one display in the log 'Using .... as localIP...' as well as my actual local IP address from ifconfig. Any suggestions?

jamalag commented 4 years ago

ok I finally managed to get janus working and yes I am also getting that same error message TypeError : " _reactNativeWebrtc.MediaStreamTrack.getSources is not a function". Now I can play around with it.

jamalag commented 4 years ago

After the changes below, i am getting the video in the App:

I first added mediaDevices in the import ... import { ..., mediaDevices, }

and then I replaced the code in lines after 1646 where the error was being thrown ...

          // If we got here, we're not screensharing
          if(media === null || media === undefined || media.video !== 'screen') {
              // Check whether all media sources are actually available or not
              mediaDevices.enumerateDevices().then(sourceInfos => {
                console.log(sourceInfos);
                const constraints = {
                    audio: true,
                    video: {
                      facingMode: (true ? "user" : "environment"),
                    }
                }

                mediaDevices.getUserMedia(constraints).then( (stream) => {
                  localStream = stream
                  console.log("Succeeded to get the local camera!")
                  streamsDone(handleId, jsep, media, callbacks, stream)
                }).catch((error) => {
                  console.log("Failed to get the local camera!")
                  console.log(error)
                })
              })

            //   MediaStreamTrack.getSources(sourceInfos => {
            //       console.log(sourceInfos);
            //       getUserMedia({
            //           audio: true,
            //           video: {
            //             facingMode: (true ? "user" : "environment"),
            //           }
            //       },  (stream) => {
            //         localStream = stream
            //         console.log("Succeeded to get the local camera!")
            //         streamsDone(handleId, jsep, media, callbacks, stream)
            //       }, (error) => {
            //         console.log("Failed to get the local camera!")
            //         console.log(error)
            //       }
            //       )
            //   });
          }
      } else {
          // No need to do a getUserMedia, create offer/answer right away
          streamsDone(handleId, jsep, media, callbacks);
      }
  }
jamalag commented 4 years ago

I think the issue is that the package https://github.com/atyenoria/react-native-webrtc.git is outdated and you may have installed react-native-webrtc (https://github.com/react-native-webrtc/react-native-webrtc) instead. Hence, atyenoria's code does not work. I don't now how far you are with your project but I suspect you may face more issue.

Anyhow, thanks for pointing me to this repo.

adrien-prototype commented 4 years ago

Sorry for not answering your last messages sooner, I presume we're on different timezones that's why. I really appreciate you took the time to check it out. I get along with what you are saying with the repo, I guess I'm going to have to write something myself to use janus because there are many errors by using this work as it is. Or there are things I'm missing ... Anyway, I wanted to gain time using things that were already made up but it may not be happening.

Though, I deeply think janus plugin system is really well suited for what I want to do, which is a one to many streaming react native app ( 1 publisher - n subscribers). It's actually one of the main contributors of Jitsi who pointed it out to me.

jamalag commented 4 years ago

no worries. I am in Canada not sure where you are based in. True, after looking at Janus it has a wide range of capabilities based on plugins and I think once you master how establish connections to janus, then you are pretty much ready to go without worrying about creating your own plugin. This is so, given many use case scenarios have already been created. If I master the janus.js client library, I might create a video for it because it seems there is very little to no simple directions to set this up.

I think we have touched on mediasoup before, that gives you SFU capabilities as well.

adrien-prototype commented 4 years ago

I agree, and I am in France by the way :)

I might create a video for it because it seems there is very little to no simple directions to set this up I couldn't agree more about this. I'll be checking for your updates regularly, I already subscribed to your youtube channel. Mediasoup is also something I could consider, for now I'm just going to focus on Janus and if I have no success I will try mediasoup.

Thank you again for all the great content and help !

jamalag commented 4 years ago

Thanks for subscribing. happy coding. let me know what new stuff you discover.

BTW, I visited France Niece, Avignon a long time ago while I was in Sheffiled UK