Friday, January 5, 2024
HomeiOS Developmentandroid - How do i implement webrtc on flutter?

android – How do i implement webrtc on flutter?


I’m engaged on a voip app for android and IOS utilizing flutter. I’m utilizing dart sip_ua. I’m able to register to the signaling server in addition to obtain a name. The consumer can also be in a position to connect with the ice server. Nonetheless, the decision terminstes after 30 seconds with the error rtp timeout. Under is the error log:
I/flutter ( 6747): Document-Route: sip:192.168.0.7:5080;transport=ws;r2=on;lr=on;nat=sure;rtp=bridge;rtp=ws
I/flutter ( 6747): Document-Route: sip:192.168.0.7;r2=on;lr=on;nat=sure;rtp=bridge;rtp=ws
D/FlutterWebRTCPlugin( 6747): onAddTrack
D/FlutterWebRTCPlugin( 6747): onIceGatheringChangeGATHERING
D/FlutterWebRTCPlugin( 6747): onConnectionChangeCONNECTING
D/FlutterWebRTCPlugin( 6747): onIceCandidate
D/FlutterWebRTCPlugin( 6747): onIceGatheringChangeCOMPLETE
I/flutter ( 6747): Document-Route: sip:192.168.0.7:5080;transport=ws;r2=on;lr=on;nat=sure;rtp=bridge;rtp=ws
I/flutter ( 6747): Document-Route: sip:192.168.0.7;r2=on;lr=on;nat=sure;rtp=bridge;rtp=ws
I/flutter ( 6747): m=audio 56441 RTP/SAVPF 0 8 101
D/FlutterWebRTCPlugin( 6747): onIceCandidate
I/flutter ( 6747): m=audio 56441 RTP/SAVPF 0 8 101
D/FlutterWebRTCPlugin( 6747): onConnectionChangeFAILED
I/flutter ( 6747): [2024-01-02 00:28:28.596] Degree.debug sip_ua_helper.dart:249 ::: name ended with trigger: Code: [408], Trigger: RTP Timeout, Motive: RTP Timeout
D/FlutterWebRTCPlugin( 6747): onConnectionChangeCLOSED
I/flutter ( 6747): Route: sip:192.168.0.7:5080;transport=ws;r2=on;lr=on;nat=sure;rtp=bridge;rtp=ws
I/flutter ( 6747): Route: sip:192.168.0.7;r2=on;lr=on;nat=sure;rtp=bridge;rtp=ws
I/flutter ( 6747): Motive: SIP ;case=408; textual content=”RTP Timeout”

Under is the sip ua code

`import 'package deal:flutter/materials.dart';
import 'package deal:flutter_callkit_incoming/entities/entities.dart';
import 'package deal:uuid/uuid.dart';
import 'package deal:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package deal:sip_ua/sip_ua.dart';
import 'package deal:flutter_webrtc/flutter_webrtc.dart';

void major() {
  runApp(const MyApp());
  var uuid = const Uuid();
  var sipHelper = SIPUAHelper();

  SipEvents sipevent = SipEvents();
  sipevent._initRenderers();

  var ua = UaSettings();
  ua.authorizationUser="2167";
  ua.password = 'XXXX';
  ua.webSocketUrl="wss://flip.konza.go.ke/ws";
  ua.uri = 'sip:[email protected]';
  ua.iceGatheringTimeout = 3000;
  ua.iceServers = <Map<String, String>>[
    <String, String>{
      'url': 'turn:turn.konza.go.ke:3478',
      'username': 'goipvoice',
      'credential': 'XXXXX',
    },
  ];
  ua.register = true;
  sipHelper.begin(ua);
  print("listeners right here");
  print(sipHelper.listeners);
  sipHelper.addSipUaHelperListener(sipevent);
}

class SipEvents extends SipUaHelperListener {
  closing RTCVideoRenderer? _localRenderer = RTCVideoRenderer();
  closing RTCVideoRenderer? _remoteRenderer = RTCVideoRenderer();
  double? _localVideoHeight;
  double? _localVideoWidth;
  closing mediaConstraints = <String, dynamic>{
    'audio': true,
    'video': false,
  };
  MediaStream? _localStream;
  MediaStream? _remoteStream;
  late MediaStream mediaStream;

  void _handleAccept() async {
    mediaStream = await navigator.mediaDevices.getUserMedia(mediaConstraints);
  }

  void _handelStreams(CallState occasion) async {
    MediaStream? stream = occasion.stream;
    if (occasion.originator == 'native') {
      if (_localRenderer != null) {
        _localRenderer!.srcObject = stream;
      }
      if (!WebRTC.platformIsDesktop) {
        occasion.stream?.getAudioTracks().first.enableSpeakerphone(false);
      }
      _localStream = stream;
    }
    if (occasion.originator == 'distant') {
      if (_remoteRenderer != null) {
        _remoteRenderer!.srcObject = stream;
      }
      _remoteStream = stream;
    }
  }

  void _initRenderers() async {
    if (_localRenderer != null) {
      await _localRenderer!.initialize();
    }
    if (_remoteRenderer != null) {
      await _remoteRenderer!.initialize();
    }
  }

  @override
  Future<void> callStateChanged(Name name, CallState state) async {
    // TODO: implement callStateChanged
    String stateName = state.state.title;
    print("new Name $stateName");
    print(state.state.title);
    if (stateName == "PROGRESS") {
      print("name has began");
      strive {
        mediaStream =
            await navigator.mediaDevices.getUserMedia(mediaConstraints);
        name.reply(SIPUAHelper().buildCallOptions(true),
            mediaStream: mediaStream);
        print("gotten media");
        var peerConnection = name.peerConnection;
        print("peer connection $peerConnection");
      } catch (e) {}
    }
    if (stateName == "STREAM") {
      _handelStreams(state);
    }
  }

  @override
  void onNewMessage(SIPMessageRequest msg) {
    // TODO: implement onNewMessage
    print("new sip mesasge");
  }

  @override
  void onNewNotify(Notify ntf) {
    // TODO: implement onNewNotify
    print("new notify");
  }

  @override
  void registrationStateChanged(RegistrationState state) {
    // TODO: implement registrationStateChanged
    print("new registration");
  }

  @override
  void transportStateChanged(TransportState state) {
    // TODO: implement transportStateChanged
    print("new transport");
  }
}

class MyApp extends StatelessWidget {
  const MyApp({tremendous.key});

  // This widget is the foundation of your utility.
  @override
  Widget construct(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // That is the theme of your utility.
        //
        // TRY THIS: Strive working your utility with "flutter run". You may see
        // the appliance has a purple toolbar. Then, with out quitting the app,
        // strive altering the seedColor within the colorScheme under to Colours.inexperienced
        // after which invoke "scorching reload" (save your adjustments or press the "scorching
        // reload" button in a Flutter-supported IDE, or press "r" for those who used
        // the command line to start out the app).
        //
        // Discover that the counter did not reset again to zero; the appliance
        // state will not be misplaced throughout the reload. To reset the state, use scorching
        // restart as a substitute.
        //
        // This works for code too, not simply values: Most code adjustments will be
        // examined with only a scorching reload.
        colorScheme: ColorScheme.fromSeed(seedColor: Colours.deepPurple),
        useMaterial3: true,
      ),
      residence: const MyHomePage(
          title: 'Flutter Demo Dwelling Web page scorching reload depend right here'),
    );
  }
}

class MyHomePage extends StatefulWidget implements SipUaHelperListener {
  const MyHomePage({tremendous.key, required this.title});

  // This widget is the house web page of your utility. It's stateful, that means
  // that it has a State object (outlined under) that incorporates fields that have an effect on
  // the way it seems.

  // This class is the configuration for the state. It holds the values (on this
  // case the title) supplied by the father or mother (on this case the App widget) and
  // utilized by the construct methodology of the State. Fields in a Widget subclass are
  // all the time marked "closing".

  closing String title;

  void initState() {
    SIPUAHelper().addSipUaHelperListener(this);
  }

  @override
  State<MyHomePage> createState() => _MyHomePageState();

  @override
  void callStateChanged(Name name, CallState state) {
    // TODO: implement callStateChanged
    print("new message");
  }

  @override
  void onNewMessage(SIPMessageRequest msg) {
    // TODO: implement onNewMessage
    print("new message");
  }

  @override
  void onNewNotify(Notify ntf) {
    // TODO: implement onNewNotify
    print("new message");
  }

  @override
  void registrationStateChanged(RegistrationState state) {
    // TODO: implement registrationStateChanged
    print("new message");
  }

  @override
  void transportStateChanged(TransportState state) {
    // TODO: implement transportStateChanged
    print("new message");
  }
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      // This name to setState tells the Flutter framework that one thing has
      // modified on this State, which causes it to rerun the construct methodology under
      // in order that the show can mirror the up to date values. If we modified
      // _counter with out calling setState(), then the construct methodology wouldn't be
      // referred to as once more, and so nothing would seem to occur.
      _counter++;
    });
  }

  @override
  Widget construct(BuildContext context) {
    var uuid = const Uuid();
    var callid = uuid.v4();

    // This methodology is rerun each time setState known as, as an example as completed
    // by the _incrementCounter methodology above.
    //
    // The Flutter framework has been optimized to make rerunning construct strategies
    // quick, so to simply rebuild something that wants updating slightly
    // than having to individually change situations of widgets.
    return Scaffold(
      appBar: AppBar(
        // TRY THIS: Strive altering the colour right here to a selected shade (to
        // Colours.amber, maybe?) and set off a scorching reload to see the AppBar
        // change shade whereas the opposite colours keep the identical.
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        // Right here we take the worth from the MyHomePage object that was created by
        // the App.construct methodology, and use it to set our appbar title.
        title: Textual content(widget.title),
      ),
      physique: Heart(
        // Heart is a format widget. It takes a single little one and positions it
        // in the midst of the father or mother.
        little one: Column(
          // Column can also be a format widget. It takes an inventory of youngsters and
          // arranges them vertically. By default, it sizes itself to suit its
          // youngsters horizontally, and tries to be as tall as its father or mother.
          //
          // Column has varied properties to manage the way it sizes itself and
          // the way it positions its youngsters. Right here we use mainAxisAlignment to
          // middle the kids vertically; the primary axis right here is the vertical
          // axis as a result of Columns are vertical (the cross axis can be
          // horizontal).
          //
          // TRY THIS: Invoke "debug portray" (select the "Toggle Debug Paint"
          // motion within the IDE, or press "p" within the console), to see the
          // wireframe for every widget.
          mainAxisAlignment: MainAxisAlignment.middle,
          youngsters: <Widget>[
            const Text(
              'You have pushed the button this many times here:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
            ElevatedButton(
              onPressed: () async {
                print("action button pressed");
                CallKitParams params = CallKitParams(
                    id: callid,
                    nameCaller: 'Emmanuel',
                    appName: 'go mobile',
                    type: 0,
                    duration: 30000,
                    textAccept: 'Answer',
                    textDecline: 'Decline',
                    handle: '0716597086',
                    extra: {'userId': '1a2b3c4d'},
                    missedCallNotification: const NotificationParams(
                      id: 234,
                      showNotification: true,
                      callbackText: "Call back",
                    ),
                    android: const AndroidParams(
                      ringtonePath: 'system_ringtone_default',
                      isCustomNotification: true,
                      isShowLogo: false,
                    ));
                await FlutterCallkitIncoming.showCallkitIncoming(params);
                FlutterCallkitIncoming.onEvent.listen((event) {
                  print(event?.event);
                  switch (event?.event) {
                    case Event.actionCallAccept:
                      FlutterCallkitIncoming.setCallConnected(callid);
                      print("call accepter");
                      break;
                    default:
                  }
                });
              },
              child: const Text('Incoming Call'),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        little one: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for construct strategies.
    );
  }
}`

Kindly assist with this.I’m new to flutter however i’ve expertise with webrct on javascript.

I attempted altering the ice servers and as effectively examined the ice server connection to verify the ice servers are working in addition to the signalling servers.



Supply hyperlink

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments