From ea69ae69ada0c23fd91be897b493d6d243228f7e Mon Sep 17 00:00:00 2001 From: Victor Uvarov Date: Tue, 22 Oct 2024 18:37:15 -0700 Subject: [PATCH 01/13] make sure the session terminates (#485) Co-authored-by: Victor Uvarov --- lib/src/sip_ua_helper.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/sip_ua_helper.dart b/lib/src/sip_ua_helper.dart index 71de9291..a27d44ae 100644 --- a/lib/src/sip_ua_helper.dart +++ b/lib/src/sip_ua_helper.dart @@ -554,7 +554,7 @@ class Call { assert(_session != null, 'ERROR(hangup): rtc session is invalid!'); if (peerConnection != null) { for (MediaStream? stream in peerConnection!.getLocalStreams()) { - if (stream == null) return; + if (stream == null) continue; logger.d( 'Stopping local stream with tracks: ${stream.getTracks().length}'); for (MediaStreamTrack track in stream.getTracks()) { @@ -563,7 +563,7 @@ class Call { } } for (MediaStream? stream in peerConnection!.getRemoteStreams()) { - if (stream == null) return; + if (stream == null) continue; logger.d( 'Stopping remote stream with tracks: ${stream.getTracks().length}'); for (MediaStreamTrack track in stream.getTracks()) { From 23c25959d4d2103e09fd277a90c5cb2ced812c3f Mon Sep 17 00:00:00 2001 From: Mikael Wills <63661422+mikaelwills@users.noreply.github.com> Date: Mon, 2 Dec 2024 01:18:14 +0000 Subject: [PATCH 02/13] Hold and video upgrade fixed (#503) Co-authored-by: Mikael Wills --- example/lib/src/callscreen.dart | 13 +- example/lib/src/register.dart | 26 +++- example/test/widget_test.dart | 2 +- lib/src/rtc_session.dart | 249 ++++++++++++++++++++++++-------- lib/src/sip_ua_helper.dart | 4 +- 5 files changed, 222 insertions(+), 72 deletions(-) diff --git a/example/lib/src/callscreen.dart b/example/lib/src/callscreen.dart index 976c0307..4bfba3dc 100644 --- a/example/lib/src/callscreen.dart +++ b/example/lib/src/callscreen.dart @@ -181,7 +181,10 @@ class _MyCallScreenWidget extends State if (_localRenderer != null) { _localRenderer!.srcObject = stream; } - if (!kIsWeb && !WebRTC.platformIsDesktop) { + + if (!kIsWeb && + !WebRTC.platformIsDesktop && + event.stream?.getAudioTracks().isNotEmpty == true) { event.stream?.getAudioTracks().first.enableSpeakerphone(false); } _localStream = stream; @@ -334,10 +337,14 @@ class _MyCallScreenWidget extends State call!.voiceOnly = false; }); helper!.renegotiate( - call: call!, voiceOnly: false, done: (incomingMessage) {}); + call: call!, + voiceOnly: false, + done: (IncomingMessage? incomingMessage) {}); } else { helper!.renegotiate( - call: call!, voiceOnly: true, done: (incomingMessage) {}); + call: call!, + voiceOnly: true, + done: (IncomingMessage? incomingMessage) {}); } } diff --git a/example/lib/src/register.dart b/example/lib/src/register.dart index a9f0bc98..f315bf3d 100644 --- a/example/lib/src/register.dart +++ b/example/lib/src/register.dart @@ -156,6 +156,27 @@ class _MyRegisterWidget extends State appBar: AppBar( title: Text("SIP Account"), ), + bottomNavigationBar: Padding( + padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 20), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + children: [ + Expanded( + child: SizedBox( + height: 40, + child: ElevatedButton( + child: Text('Register'), + onPressed: () => _handleSave(context), + ), + ), + ), + ], + ), + ], + ), + ), body: ListView( padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 20), children: [ @@ -281,11 +302,6 @@ class _MyRegisterWidget extends State ], ), ], - const SizedBox(height: 20), - ElevatedButton( - child: Text('Register'), - onPressed: () => _handleSave(context), - ), ], ), ); diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart index 4e8e53f4..900418a1 100644 --- a/example/test/widget_test.dart +++ b/example/test/widget_test.dart @@ -13,7 +13,7 @@ import 'package:dart_sip_ua_example/main.dart'; void main() { testWidgets('Counter increments smoke test', (WidgetTester tester) async { // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); + await tester.pumpWidget(MyApp()); // Verify that our counter starts at 0. expect(find.text('0'), findsOneWidget); diff --git a/lib/src/rtc_session.dart b/lib/src/rtc_session.dart index 9fc9da52..d9937d07 100644 --- a/lib/src/rtc_session.dart +++ b/lib/src/rtc_session.dart @@ -301,7 +301,8 @@ class RTCSession extends EventManager implements Owner { // Set anonymous property. bool anonymous = options['anonymous'] ?? false; Map requestParams = { - 'from_tag': _from_tag + 'from_tag': _from_tag, + 'to_display_name': options['to_display_name'] ?? '', }; _ua.contact!.anonymous = anonymous; _ua.contact!.outbound = true; @@ -314,7 +315,7 @@ class RTCSession extends EventManager implements Owner { requestParams['from_display_name'] = options['from_display_name'] ?? ''; requestParams['from_uri'] = URI.parse(options['from_uri']); extraHeaders - .add('P-Preferred-Identity: ${_ua.configuration.uri.toString()}'); + .add('P-Preferred-Identity: ${_ua.configuration.uri.toString()}'); } if (anonymous) { @@ -1032,7 +1033,7 @@ class RTCSession extends EventManager implements Owner { /** * Hold */ - bool hold([Map? options, Function? done]) { + bool hold([Map? options, Function(IncomingMessage?)? done]) { logger.d('hold()'); options = options ?? {}; @@ -1056,7 +1057,7 @@ class RTCSession extends EventManager implements Owner { handlers.on(EventSucceeded(), (EventSucceeded event) { if (done != null) { - done(); + done(event.response); } }); handlers.on(EventCallFailed(), (EventCallFailed event) { @@ -1083,7 +1084,8 @@ class RTCSession extends EventManager implements Owner { return true; } - bool unhold([Map? options, Function? done]) { + bool unhold( + [Map? options, Function(IncomingMessage?)? done]) { logger.d('unhold()'); options = options ?? {}; @@ -1106,7 +1108,7 @@ class RTCSession extends EventManager implements Owner { EventManager handlers = EventManager(); handlers.on(EventSucceeded(), (EventSucceeded event) { if (done != null) { - done(); + done(event.response); } }); handlers.on(EventCallFailed(), (EventCallFailed event) { @@ -1135,8 +1137,8 @@ class RTCSession extends EventManager implements Owner { bool renegotiate( {Map? options, - Function(IncomingMessage)? done, - bool useUpdate = false}) { + bool useUpdate = false, + Function(IncomingMessage?)? done}) { logger.d('renegotiate()'); options = options ?? {}; @@ -1155,6 +1157,15 @@ class RTCSession extends EventManager implements Owner { return false; } + bool? upgradeToVideo; + try { + upgradeToVideo = (options['mediaConstraints']?['video'] != false || + options['mediaConstraints']?['mandatory']?['video'] != null) && + rtcOfferConstraints?['offerToReceiveVideo'] == null; + } catch (e) { + print('Failed to determine upgrade to video: $e'); + } + if (!_isReadyToReOffer()) { return false; } @@ -1175,7 +1186,7 @@ class RTCSession extends EventManager implements Owner { _setLocalMediaStatus(); - if (useUpdate) { + if (options['useUpdate'] != null) { _sendUpdate({ 'sdpOffer': true, 'eventHandlers': handlers, @@ -1183,13 +1194,21 @@ class RTCSession extends EventManager implements Owner { 'extraHeaders': options['extraHeaders'] }); } else { - _sendReinvite({ - 'eventHandlers': handlers, - 'sdpSemantics': sdpSemantics, - 'rtcOfferConstraints': rtcOfferConstraints, - 'mediaConstraints': mediaConstraints, - 'extraHeaders': options['extraHeaders'] - }); + if (upgradeToVideo ?? false) { + _sendVideoUpgradeReinvite({ + 'eventHandlers': handlers, + 'sdpSemantics': sdpSemantics, + 'rtcOfferConstraints': rtcOfferConstraints, + 'mediaConstraints': mediaConstraints, + 'extraHeaders': options['extraHeaders'] + }); + } else { + _sendReinvite({ + 'eventHandlers': handlers, + 'rtcOfferConstraints': rtcOfferConstraints, + 'extraHeaders': options['extraHeaders'] + }); + } } return true; @@ -1592,19 +1611,6 @@ class RTCSession extends EventManager implements Owner { 'optional': [], }; offerConstraints['mandatory']['IceRestart'] = true; - - EventManager handlers = EventManager(); - handlers.on(EventSucceeded(), (EventSucceeded event) async { - logger.d('ICE Restart was successful'); - }); - handlers.on(EventCallFailed(), (EventCallFailed event) { - terminate({ - 'cause': DartSIP_C.CausesType.WEBRTC_ERROR, - 'status_code': 500, - 'reason_phrase': 'Media Renegotiation Failed' - }); - }); - offerConstraints['eventHandlers'] = handlers; renegotiate(options: offerConstraints); } @@ -1670,7 +1676,7 @@ class RTCSession extends EventManager implements Owner { modifiers = constraints['offerModifiers'] ?? Function(RTCSessionDescription)>[]; - constraints.remove('offerModifiers'); + constraints['offerModifiers'] = null; if (type != 'offer' && type != 'answer') { completer.completeError(Exceptions.TypeError( @@ -2013,17 +2019,16 @@ class RTCSession extends EventManager implements Owner { bool upgradeToVideo = false; if (sdp != null) { List mediaList = sdp['media']; - for (Map m in mediaList) { - if (holdMediaTypes.indexOf(m['type']) == -1) { - continue; - } - - if (m['type'] == 'video') { - upgradeToVideo = true; - } - - String direction = m['direction'] ?? sdp['direction'] ?? 'sendrecv'; + // Loop media list items for video upgrade + for (Map media in mediaList) { + if (holdMediaTypes.indexOf(media['type']) == -1) continue; + if (media['type'] == 'video') upgradeToVideo = true; + } + // Loop media list items for hold + for (Map media in mediaList) { + if (holdMediaTypes.indexOf(media['type']) == -1) continue; + String direction = media['direction'] ?? sdp['direction'] ?? 'sendrecv'; if (direction == 'sendonly' || direction == 'inactive') { hold = true; } @@ -2046,19 +2051,34 @@ class RTCSession extends EventManager implements Owner { 'facingMode': 'user', } }; - MediaStream localStream = - await navigator.mediaDevices.getUserMedia(mediaConstraints); - if (localStream.getVideoTracks().isEmpty) { - logger.w( - 'Remote wants to upgrade to video but failed to get local video'); - } - for (MediaStreamTrack track in localStream.getTracks()) { - if (track.kind == 'video') { - _connection!.addTrack(track, localStream); + bool hasCamera = false; + try { + List devices = + await navigator.mediaDevices.enumerateDevices(); + for (MediaDeviceInfo device in devices) { + if (device.kind == 'videoinput') hasCamera = true; } + } catch (e) { + logger.w('Failed to enumerate devices: $e'); + } + if (hasCamera) { + MediaStream localStream = + await navigator.mediaDevices.getUserMedia(mediaConstraints); + if (localStream.getVideoTracks().isEmpty) { + logger.w( + 'Remote wants to upgrade to video but failed to get local video'); + } + for (MediaStreamTrack track in localStream.getTracks()) { + if (track.kind == 'video') { + _connection!.addTrack(track, localStream); + } + } + emit(EventStream( + session: this, originator: 'local', stream: localStream)); + } else { + logger.w( + 'Remote wants to upgrade to video but no camera available to send'); } - emit( - EventStream(session: this, originator: 'local', stream: localStream)); } logger.d('emit "sdp"'); @@ -2485,6 +2505,9 @@ class RTCSession extends EventManager implements Owner { emit(EventSetRemoteDescriptionFailed(exception: error)); } } else if (utils.test2XX(status_code)) { + // 2XX + _status = C.STATUS_CONFIRMED; + if (response.body == null || response.body!.isEmpty) { _acceptAndTerminate(response, 400, DartSIP_C.CausesType.MISSING_SDP); _failed('remote', null, null, response, 400, @@ -2506,8 +2529,6 @@ class RTCSession extends EventManager implements Owner { return; } - _status = C.STATUS_CONFIRMED; - logger.d('emit "sdp"'); emit(EventSdp(originator: 'remote', type: 'answer', sdp: response.body)); @@ -2567,6 +2588,113 @@ class RTCSession extends EventManager implements Owner { options = options ?? {}; + List extraHeaders = options['extraHeaders'] != null + ? utils.cloneArray(options['extraHeaders']) + : []; + EventManager eventHandlers = options['eventHandlers'] ?? EventManager(); + Map? rtcOfferConstraints = + options['rtcOfferConstraints'] ?? _rtcOfferConstraints; + + bool succeeded = false; + + extraHeaders.add('Contact: $_contact'); + extraHeaders.add('Content-Type: application/sdp'); + + // Session Timers. + if (_sessionTimers.running) { + extraHeaders.add( + 'Session-Expires: ${_sessionTimers.currentExpires};refresher=${_sessionTimers.refresher ? 'uac' : 'uas'}'); + } + + void onFailed([dynamic response]) { + eventHandlers.emit(EventCallFailed(session: this, response: response)); + } + + void onSucceeded(IncomingResponse? response) async { + if (_status == C.STATUS_TERMINATED) { + return; + } + + sendRequest(SipMethod.ACK); + + // If it is a 2XX retransmission exit now. + if (succeeded != null) { + return; + } + + // Handle Session Timers. + _handleSessionTimersInIncomingResponse(response); + + // Must have SDP answer. + if (response!.body == null || response.body!.isEmpty) { + onFailed(); + return; + } else if (response.getHeader('Content-Type') != 'application/sdp') { + onFailed(); + return; + } + + logger.d('emit "sdp"'); + emit(EventSdp(originator: 'remote', type: 'answer', sdp: response.body)); + + RTCSessionDescription answer = + RTCSessionDescription(response.body, 'answer'); + + try { + await _connection!.setRemoteDescription(answer); + eventHandlers.emit(EventSucceeded(response: response)); + } catch (error) { + onFailed(); + logger.e( + 'emit "peerconnection:setremotedescriptionfailed" [error:${error.toString()}]'); + emit(EventSetRemoteDescriptionFailed(exception: error)); + } + } + + try { + RTCSessionDescription desc = + await _createLocalDescription('offer', rtcOfferConstraints); + String? sdp = _mangleOffer(desc.sdp); + logger.d('emit "sdp"'); + emit(EventSdp(originator: 'local', type: 'offer', sdp: sdp)); + + EventManager handlers = EventManager(); + handlers.on(EventOnSuccessResponse(), (EventOnSuccessResponse event) { + onSucceeded(event.response as IncomingResponse?); + succeeded = true; + }); + handlers.on(EventOnErrorResponse(), (EventOnErrorResponse event) { + onFailed(event.response); + }); + handlers.on(EventOnTransportError(), (EventOnTransportError event) { + onTransportError(); // Do nothing because session ends. + }); + handlers.on(EventOnRequestTimeout(), (EventOnRequestTimeout event) { + onRequestTimeout(); // Do nothing because session ends. + }); + handlers.on(EventOnDialogError(), (EventOnDialogError event) { + onDialogError(); // Do nothing because session ends. + }); + + sendRequest(SipMethod.INVITE, { + 'extraHeaders': extraHeaders, + 'body': sdp, + 'eventHandlers': handlers + }); + } catch (e, s) { + logger.e(e.toString(), error: e, stackTrace: s); + onFailed(); + } + } + + /** + * Send Re-INVITE + */ + void _sendVideoUpgradeReinvite([Map? options]) async { + logger.d('sendVideoUpgradeReinvite()'); + + options = options ?? {}; + List extraHeaders = options['extraHeaders'] != null ? utils.cloneArray(options['extraHeaders']) : []; @@ -2577,26 +2705,22 @@ class RTCSession extends EventManager implements Owner { Map mediaConstraints = options['mediaConstraints'] ?? {}; + mediaConstraints['audio'] = false; + dynamic sdpSemantics = options['pcConfig']?['sdpSemantics'] ?? 'unified-plan'; - bool hasVideo = (options['mediaConstraints']?['video'] ?? false) != false; - try { MediaStream localStream = await navigator.mediaDevices.getUserMedia(mediaConstraints); _localMediaStreamLocallyGenerated = true; - _localMediaStream = localStream; - - emit( - EventStream(session: this, originator: 'local', stream: localStream)); switch (sdpSemantics) { case 'unified-plan': localStream.getTracks().forEach((MediaStreamTrack track) { - if (track.kind == 'video' && hasVideo) { + if (track.kind == 'video') _connection!.addTrack(track, localStream); - } + _localMediaStream?.addTrack(track); }); break; case 'plan-b': @@ -2606,6 +2730,9 @@ class RTCSession extends EventManager implements Owner { logger.e('Unkown sdp semantics $sdpSemantics'); throw Exceptions.NotReadyError('Unkown sdp semantics $sdpSemantics'); } + + emit(EventStream( + session: this, originator: 'local', stream: _localMediaStream)); } catch (error) { if (_status == C.STATUS_TERMINATED) { throw Exceptions.InvalidStateError('terminated'); diff --git a/lib/src/sip_ua_helper.dart b/lib/src/sip_ua_helper.dart index a27d44ae..3e6dc480 100644 --- a/lib/src/sip_ua_helper.dart +++ b/lib/src/sip_ua_helper.dart @@ -123,7 +123,7 @@ class SIPUAHelper extends EventManager { required bool voiceOnly, Map? options, bool useUpdate = false, - Function(IncomingMessage)? done, + Function(IncomingMessage?)? done, }) async { Map finalOptions = options ?? buildCallOptions(voiceOnly); call.renegotiate(options: finalOptions, useUpdate: useUpdate, done: done); @@ -600,7 +600,7 @@ class Call { void renegotiate({ required Map? options, bool useUpdate = false, - Function(IncomingMessage)? done, + Function(IncomingMessage?)? done, }) { assert(_session != null, 'ERROR(renegotiate): rtc session is invalid!'); _session.renegotiate(options: options, useUpdate: useUpdate, done: done); From 0eb206e974d23c41d7537a0e46d9cc4b7b5c396f Mon Sep 17 00:00:00 2001 From: Emmanuel Schmidbauer Date: Sun, 1 Dec 2024 20:18:41 -0500 Subject: [PATCH 03/13] sip_ua_helper: add sendOptions (#476) --- lib/src/sip_ua_helper.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/src/sip_ua_helper.dart b/lib/src/sip_ua_helper.dart index 3e6dc480..1ed2ae1f 100644 --- a/lib/src/sip_ua_helper.dart +++ b/lib/src/sip_ua_helper.dart @@ -14,6 +14,7 @@ import 'event_manager/event_manager.dart'; import 'event_manager/subscriber_events.dart'; import 'logger.dart'; import 'message.dart'; +import 'options.dart'; import 'rtc_session.dart'; import 'rtc_session/refer_subscriber.dart'; import 'sip_message.dart'; @@ -413,6 +414,10 @@ class SIPUAHelper extends EventManager { return _ua!.sendMessage(target, body, options, params); } + Options sendOptions(String target, String body, Map? params) { + return _ua!.sendOptions(target, body, params); + } + void subscribe(String target, String event, String contentType) { Subscriber s = _ua!.subscribe(target, event, contentType); From d7047176e0b84794bfe7b78fa6b9e0bff0edcc19 Mon Sep 17 00:00:00 2001 From: HVaidehi <87645715+HVaidehi@users.noreply.github.com> Date: Mon, 2 Dec 2024 06:53:28 +0530 Subject: [PATCH 04/13] Update callscreen.dart (#427) IOS video call issue on acceptance fixed Co-authored-by: CloudWebRTC --- example/lib/src/callscreen.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/example/lib/src/callscreen.dart b/example/lib/src/callscreen.dart index 4bfba3dc..a6b6ebe9 100644 --- a/example/lib/src/callscreen.dart +++ b/example/lib/src/callscreen.dart @@ -230,6 +230,7 @@ class _MyCallScreenWidget extends State 'minFrameRate': '30', }, 'facingMode': 'user', + 'optional': [], } : false }; @@ -242,6 +243,9 @@ class _MyCallScreenWidget extends State await navigator.mediaDevices.getUserMedia(mediaConstraints); mediaStream.addTrack(userStream.getAudioTracks()[0], addToNative: true); } else { + if (!remoteHasVideo) { + mediaConstraints['video'] = false; + } mediaStream = await navigator.mediaDevices.getUserMedia(mediaConstraints); } From 27d7ba9b6a1a5196b8f3202460243441b724986d Mon Sep 17 00:00:00 2001 From: Mikael Wills Date: Wed, 18 Dec 2024 13:54:03 +0000 Subject: [PATCH 05/13] Dependency updates --- example/ios/Podfile | 2 +- example/pubspec.yaml | 4 ++-- pubspec.yaml | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/example/ios/Podfile b/example/ios/Podfile index c9339a03..ed164703 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '12.0' +platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 1e834d69..6c4c2372 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -25,14 +25,14 @@ dependencies: path: ../ shared_preferences: ^2.2.0 permission_handler: ^11.1.0 - flutter_webrtc: ^0.10.4 + flutter_webrtc: ^0.12.4 provider: 6.1.2 logger: ^2.4.0 dev_dependencies: flutter_test: sdk: flutter - lints: ^3.0.0 + lints: ^4.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/pubspec.yaml b/pubspec.yaml index 1ebd9cd5..6535e6de 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -9,8 +9,8 @@ environment: dependencies: collection: ^1.18.0 crypto: ^3.0.3 - flutter_webrtc: ^0.10.4 - intl: ^0.19.0 + flutter_webrtc: ^0.12.4 + intl: ^0.20.1 logger: ^2.0.2+1 path: ^1.6.4 random_string: ^2.3.1 @@ -22,5 +22,5 @@ dependencies: dev_dependencies: import_sorter: ^4.6.0 - lints: ^3.0.0 + lints: ^4.0.0 test: any From 523904e3abfa29e68b499d69dc8d84e1526b9c5f Mon Sep 17 00:00:00 2001 From: Mikael Wills Date: Wed, 18 Dec 2024 14:20:15 +0000 Subject: [PATCH 06/13] Build check fixes --- lib/sip_ua.dart | 2 -- lib/src/config.dart | 1 - lib/src/rtc_session.dart | 4 +--- lib/src/rtc_session/dtmf.dart | 1 - lib/src/sip_ua_helper.dart | 8 ++++---- lib/src/transports/tcp_socket.dart | 2 +- 6 files changed, 6 insertions(+), 12 deletions(-) diff --git a/lib/sip_ua.dart b/lib/sip_ua.dart index c7f2efe7..397defee 100644 --- a/lib/sip_ua.dart +++ b/lib/sip_ua.dart @@ -3,5 +3,3 @@ export 'src/sip_message.dart'; export 'src/sip_ua_helper.dart'; export 'src/transport_type.dart'; export 'src/uri.dart'; - - diff --git a/lib/src/config.dart b/lib/src/config.dart index d9849d85..4ece468f 100644 --- a/lib/src/config.dart +++ b/lib/src/config.dart @@ -7,7 +7,6 @@ import 'exceptions.dart' as Exceptions; import 'grammar.dart'; import 'logger.dart'; import 'transports/web_socket.dart'; -import 'uri.dart'; import 'utils.dart' as Utils; // Default settings. diff --git a/lib/src/rtc_session.dart b/lib/src/rtc_session.dart index d9937d07..26e2dc33 100644 --- a/lib/src/rtc_session.dart +++ b/lib/src/rtc_session.dart @@ -22,11 +22,9 @@ import 'rtc_session/info.dart' as RTCSession_Info; import 'rtc_session/info.dart'; import 'rtc_session/refer_notifier.dart'; import 'rtc_session/refer_subscriber.dart'; -import 'sip_message.dart'; import 'timers.dart'; import 'transactions/transaction_base.dart'; import 'ua.dart'; -import 'uri.dart'; import 'utils.dart' as utils; class C { @@ -3064,7 +3062,7 @@ class RTCSession extends EventManager implements Owner { } /// SDP offers may contain text media channels. e.g. Older clients using linphone. - /// + /// /// WebRTC does not support text media channels, so remove them. String? _sdpOfferToWebRTC(String? sdpInput) { if (sdpInput == null) { diff --git a/lib/src/rtc_session/dtmf.dart b/lib/src/rtc_session/dtmf.dart index df8269e3..e1fe8f16 100644 --- a/lib/src/rtc_session/dtmf.dart +++ b/lib/src/rtc_session/dtmf.dart @@ -7,7 +7,6 @@ import '../event_manager/internal_events.dart'; import '../exceptions.dart' as Exceptions; import '../logger.dart'; import '../rtc_session.dart' as rtc; -import '../sip_message.dart'; import '../utils.dart' as Utils; class C { diff --git a/lib/src/sip_ua_helper.dart b/lib/src/sip_ua_helper.dart index 1ed2ae1f..fba7de89 100644 --- a/lib/src/sip_ua_helper.dart +++ b/lib/src/sip_ua_helper.dart @@ -17,7 +17,6 @@ import 'message.dart'; import 'options.dart'; import 'rtc_session.dart'; import 'rtc_session/refer_subscriber.dart'; -import 'sip_message.dart'; import 'stack_trace_nj.dart'; import 'subscriber.dart'; import 'transports/web_socket.dart'; @@ -180,9 +179,9 @@ class SIPUAHelper extends EventManager { _settings.instance_id = uaSettings.instanceId; _settings.registrar_server = uaSettings.registrarServer; _settings.contact_uri = uaSettings.contact_uri; - _settings.connection_recovery_max_interval = + _settings.connection_recovery_max_interval = uaSettings.connectionRecoveryMaxInterval; - _settings.connection_recovery_min_interval = + _settings.connection_recovery_min_interval = uaSettings.connectionRecoveryMinInterval; _settings.terminateOnAudioMediaPortZero = uaSettings.terminateOnMediaPortZero; @@ -414,7 +413,8 @@ class SIPUAHelper extends EventManager { return _ua!.sendMessage(target, body, options, params); } - Options sendOptions(String target, String body, Map? params) { + Options sendOptions( + String target, String body, Map? params) { return _ua!.sendOptions(target, body, params); } diff --git a/lib/src/transports/tcp_socket.dart b/lib/src/transports/tcp_socket.dart index 1b5b1e6e..85aa9ecc 100644 --- a/lib/src/transports/tcp_socket.dart +++ b/lib/src/transports/tcp_socket.dart @@ -179,7 +179,7 @@ class SIPUATcpSocket extends SIPUASocketInterface { @override String? get url { - if (_host == null || _port == null) { + if (_host == null || _port == null) { return null; } return '$_host:$_port'; From adf4aa1cfc01ab60f8f89780137d4bc77a2b303d Mon Sep 17 00:00:00 2001 From: Mikael Wills Date: Wed, 18 Dec 2024 14:32:32 +0000 Subject: [PATCH 07/13] Push to master checks --- .github/workflows/pushMaster.yaml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/pushMaster.yaml diff --git a/.github/workflows/pushMaster.yaml b/.github/workflows/pushMaster.yaml new file mode 100644 index 00000000..9ded7497 --- /dev/null +++ b/.github/workflows/pushMaster.yaml @@ -0,0 +1,27 @@ +name: Push To Master + +on: + push: + branches: + - master + +jobs: + build: + name: Build Checks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install Flutter + uses: subosito/flutter-action@v2 + with: + channel: "stable" + - name: Install project dependencies + run: flutter pub get + - name: Dart Format Check + run: dart format lib/ test/ --set-exit-if-changed + - name: Import Sorter Check + run: flutter pub run import_sorter:main --no-comments --exit-if-changed + - name: Dart Analyze Check + run: flutter analyze + - name: Dart Test Check + run: flutter test From 8d73bbf6c7201c2126437d4b2c2f9b2276e755f1 Mon Sep 17 00:00:00 2001 From: Mikael Wills Date: Wed, 18 Dec 2024 14:55:02 +0000 Subject: [PATCH 08/13] import sorting fix --- lib/src/sip_ua_helper.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/sip_ua_helper.dart b/lib/src/sip_ua_helper.dart index fba7de89..f2562b07 100644 --- a/lib/src/sip_ua_helper.dart +++ b/lib/src/sip_ua_helper.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'package:logger/logger.dart'; import 'package:sdp_transform/sdp_transform.dart' as sdp_transform; + import 'package:sip_ua/sip_ua.dart'; import 'package:sip_ua/src/event_manager/internal_events.dart'; import 'package:sip_ua/src/map_helper.dart'; From 2ba5b69a52bbfb09e6d60f5388739480288fa553 Mon Sep 17 00:00:00 2001 From: Mikael Wills Date: Wed, 18 Dec 2024 14:57:20 +0000 Subject: [PATCH 09/13] Push to main check file fix --- .github/workflows/pushMaster.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pushMaster.yaml b/.github/workflows/pushMaster.yaml index 9ded7497..4a80bff8 100644 --- a/.github/workflows/pushMaster.yaml +++ b/.github/workflows/pushMaster.yaml @@ -3,7 +3,7 @@ name: Push To Master on: push: branches: - - master + - main jobs: build: From be291a32c714d0499a9ce328f33c1d22489036e9 Mon Sep 17 00:00:00 2001 From: Mikael Wills Date: Wed, 18 Dec 2024 15:50:37 +0000 Subject: [PATCH 10/13] Dart analyze check fixes --- example/lib/src/dialpad.dart | 8 ++++---- example/lib/src/register.dart | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example/lib/src/dialpad.dart b/example/lib/src/dialpad.dart index 79db8747..6ec93de6 100644 --- a/example/lib/src/dialpad.dart +++ b/example/lib/src/dialpad.dart @@ -172,7 +172,7 @@ class _MyDialPadWidget extends State List _buildDialPad() { Color? textFieldColor = - Theme.of(context).textTheme.bodyMedium?.color?.withOpacity(0.5); + Theme.of(context).textTheme.bodyMedium?.color?.withValues(alpha: 0.5); Color? textFieldFill = Theme.of(context).buttonTheme.colorScheme?.surfaceContainerLowest; return [ @@ -190,15 +190,15 @@ class _MyDialPadWidget extends State filled: true, fillColor: textFieldFill, border: OutlineInputBorder( - borderSide: BorderSide(color: Colors.blue.withOpacity(0.5)), + borderSide: BorderSide(color: Colors.blue.withValues(alpha: 0.5)), borderRadius: BorderRadius.circular(5), ), enabledBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.blue.withOpacity(0.5)), + borderSide: BorderSide(color: Colors.blue.withValues(alpha: 0.5)), borderRadius: BorderRadius.circular(5), ), focusedBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.blue.withOpacity(0.5)), + borderSide: BorderSide(color: Colors.blue.withValues(alpha: 0.5)), borderRadius: BorderRadius.circular(5), ), ), diff --git a/example/lib/src/register.dart b/example/lib/src/register.dart index f315bf3d..fecc2471 100644 --- a/example/lib/src/register.dart +++ b/example/lib/src/register.dart @@ -151,7 +151,7 @@ class _MyRegisterWidget extends State borderRadius: BorderRadius.circular(5), ); Color? textLabelColor = - Theme.of(context).textTheme.bodyMedium?.color?.withOpacity(0.5); + Theme.of(context).textTheme.bodyMedium?.color?.withValues(alpha: 0.5); return Scaffold( appBar: AppBar( title: Text("SIP Account"), From 014d86663d82432b413ef2e734f7a0c086bd3473 Mon Sep 17 00:00:00 2001 From: Victor Uvarov Date: Mon, 2 Dec 2024 08:51:46 -0800 Subject: [PATCH 11/13] use rethrow when possible --- analysis_options.yaml | 1 - lib/src/config.dart | 2 +- lib/src/rtc_session.dart | 4 ++-- lib/src/transports/tcp_socket.dart | 2 +- lib/src/transports/web_socket.dart | 2 +- lib/src/transports/websocket_dart_impl.dart | 2 +- lib/src/ua.dart | 4 ++-- 7 files changed, 8 insertions(+), 9 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 3a1f08c9..9b708ede 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -53,7 +53,6 @@ analyzer: avoid_types_as_parameter_names: ignore empty_catches: ignore unawaited_futures: ignore - use_rethrow_when_possible: ignore unused_import: ignore must_be_immutable: ignore todo: ignore diff --git a/lib/src/config.dart b/lib/src/config.dart index 4ece468f..102e7ef5 100644 --- a/lib/src/config.dart +++ b/lib/src/config.dart @@ -286,6 +286,6 @@ void load(Settings src, Settings? dst) { }); } catch (e) { logger.e('Failed to load config: ${e.toString()}'); - throw e; + rethrow; } } diff --git a/lib/src/rtc_session.dart b/lib/src/rtc_session.dart index 26e2dc33..b8dfa379 100644 --- a/lib/src/rtc_session.dart +++ b/lib/src/rtc_session.dart @@ -2354,7 +2354,7 @@ class RTCSession extends EventManager implements Owner { 'User Denied Media Access'); logger.e('emit "getusermediafailed" [error:${error.toString()}]'); emit(EventGetUserMediaFailed(exception: error)); - throw error; + rethrow; } } @@ -2406,7 +2406,7 @@ class RTCSession extends EventManager implements Owner { return; } logger.e('Failed to _sendInitialRequest: ${error.toString()}'); - throw error; + rethrow; } } diff --git a/lib/src/transports/tcp_socket.dart b/lib/src/transports/tcp_socket.dart index 85aa9ecc..ce3832c7 100644 --- a/lib/src/transports/tcp_socket.dart +++ b/lib/src/transports/tcp_socket.dart @@ -140,7 +140,7 @@ class SIPUATcpSocket extends SIPUASocketInterface { return true; } catch (error) { logger.e('send() | error sending message: $error'); - throw error; + rethrow; } } diff --git a/lib/src/transports/web_socket.dart b/lib/src/transports/web_socket.dart index 66123a00..57d610c8 100644 --- a/lib/src/transports/web_socket.dart +++ b/lib/src/transports/web_socket.dart @@ -142,7 +142,7 @@ class SIPUAWebSocket extends SIPUASocketInterface { return true; } catch (error) { logger.e('send() | error sending message: $error'); - throw error; + rethrow; } } diff --git a/lib/src/transports/websocket_dart_impl.dart b/lib/src/transports/websocket_dart_impl.dart index 6516515c..1ec30b21 100644 --- a/lib/src/transports/websocket_dart_impl.dart +++ b/lib/src/transports/websocket_dart_impl.dart @@ -118,7 +118,7 @@ class SIPUAWebSocketImpl { return webSocket; } catch (e) { logger.e('error $e'); - throw e; + rethrow; } } } diff --git a/lib/src/ua.dart b/lib/src/ua.dart index 92e581bb..6d0ed965 100644 --- a/lib/src/ua.dart +++ b/lib/src/ua.dart @@ -95,7 +95,7 @@ class UA extends EventManager { } catch (e) { _status = C.STATUS_NOT_READY; _error = C.CONFIGURATION_ERROR; - throw e; + rethrow; } // Initialize registrator. @@ -821,7 +821,7 @@ class UA extends EventManager { try { config.load(configuration, _configuration); } catch (e) { - throw e; + rethrow; } // Post Configuration Process. From 66850ff9ea5174320d3e4a7ab317e12e356a1b72 Mon Sep 17 00:00:00 2001 From: cloudwebrtc Date: Thu, 19 Dec 2024 21:42:33 +0800 Subject: [PATCH 12/13] release: 1.0.1. --- CHANGELOG.md | 8 ++++++++ pubspec.yaml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e5fe8c4..0719b820 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ # Changelog -------------------------------------------- +[1.0.1] -2024.12.19 + +* make sure the session terminates by @victortive in https://github.com/flutter-webrtc/dart-sip-ua/pull/485 +* Hold and video upgrade fixed by @mikaelwills in https://github.com/flutter-webrtc/dart-sip-ua/pull/503 +* sip_ua_helper: add sendOptions by @eschmidbauer in https://github.com/flutter-webrtc/dart-sip-ua/pull/476 +* Update callscreen.dart by @HVaidehi in https://github.com/flutter-webrtc/dart-sip-ua/pull/427 + + [1.0.0] - 2024.08.24 * allow to change UA uri in runtime (#425) diff --git a/pubspec.yaml b/pubspec.yaml index 6535e6de..47237cb6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sip_ua -version: 1.0.0 +version: 1.0.1 description: A SIP UA stack for Flutter/Dart, based on flutter-webrtc, support iOS/Android/Destkop/Web. homepage: https://github.com/cloudwebrtc/dart-sip-ua environment: From 38ae9d1c888fec3a6565cc19ce753221d770d19d Mon Sep 17 00:00:00 2001 From: cloudwebrtc Date: Thu, 19 Dec 2024 21:44:04 +0800 Subject: [PATCH 13/13] ci. --- .github/workflows/dart.yml | 4 ++-- .github/workflows/publish.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index c0d76fa5..054053b0 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -3,9 +3,9 @@ name: Build on: push: - branches: [ master ] + branches: [ main ] pull_request: - branches: [ master ] + branches: [ main ] jobs: test: diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 5c9d8574..c19c1aee 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -23,8 +23,8 @@ jobs: run: flutter analyze - name: Dart Test Check run: flutter test - #- name: Check Publish Warnings - # run: dart pub publish --dry-run + - name: Check Publish Warnings + run: dart pub publish --dry-run - name: Publish uses: k-paxian/dart-package-publisher@v1.5.1 with: