Skip to content

Commit 600cf86

Browse files
committed
Support in band (rfc2833).
1 parent e751f9e commit 600cf86

File tree

5 files changed

+81
-37
lines changed

5 files changed

+81
-37
lines changed

example/lib/src/register.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ class _MyRegisterWidget extends State<RegisterWidget>
108108
settings.password = _password;
109109
settings.displayName = _displayName;
110110
settings.userAgent = 'Dart SIP Client v1.0.0';
111+
settings.dtmfMode = DtmfMode.RFC2833;
111112

112113
helper.start(settings);
113114
}

lib/src/config.dart

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import 'package:sip_ua/sip_ua.dart';
2+
13
import 'constants.dart';
24
import 'constants.dart' as DartSIP_C;
35
import 'exceptions.dart' as Exceptions;
@@ -39,6 +41,9 @@ class Settings {
3941
dynamic registrar_server;
4042
Map<String, dynamic> register_extra_contact_uri_params;
4143

44+
// Dtmf mode
45+
DtmfMode dtmf_mode = DtmfMode.INFO;
46+
4247
// Connection options.
4348
List<WebSocketInterface> sockets = <WebSocketInterface>[];
4449
int connection_recovery_max_interval = 30;
@@ -237,7 +242,14 @@ class Checks {
237242
if (use_preloaded_route is bool) {
238243
dst.use_preloaded_route = use_preloaded_route;
239244
}
240-
}
245+
},
246+
'dtmf_mode': (Settings src, Settings dst) {
247+
DtmfMode dtmf_mode = src.dtmf_mode;
248+
if (dtmf_mode == null) return;
249+
if (dtmf_mode is DtmfMode) {
250+
dst.dtmf_mode = dtmf_mode;
251+
}
252+
},
241253
};
242254
}
243255

lib/src/rtc_session.dart

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:async';
22

33
import 'package:flutter_webrtc/flutter_webrtc.dart';
44
import 'package:sdp_transform/sdp_transform.dart' as sdp_transform;
5+
import 'package:sip_ua/sip_ua.dart';
56

67
import 'constants.dart';
78
import 'constants.dart' as DartSIP_C;
@@ -192,6 +193,9 @@ class RTCSession extends EventManager {
192193

193194
RTCPeerConnection get connection => _connection;
194195

196+
RTCDTMFSender get dtmfSender =>
197+
_connection.createDtmfSender(_localMediaStream.getAudioTracks()[0]);
198+
195199
String get contact => _contact;
196200

197201
String get direction => _direction;
@@ -833,6 +837,8 @@ class RTCSession extends EventManager {
833837

834838
options = options ?? <String, dynamic>{};
835839

840+
DtmfMode mode = _ua.configuration.dtmf_mode;
841+
836842
// sensible defaults
837843
int duration = options['duration'] ?? RTCSession_DTMF.C.DEFAULT_DURATION;
838844
int interToneGap =
@@ -892,6 +898,8 @@ class RTCSession extends EventManager {
892898
interToneGap = utils.Math.abs(interToneGap);
893899
}
894900

901+
options['interToneGap'] = interToneGap;
902+
895903
//// ***************** and follows the actual code to queue DTMF tone(s) **********************
896904
897905
///using dtmfFuture to queue the playing of the tones
@@ -913,7 +921,7 @@ class RTCSession extends EventManager {
913921
return;
914922
}
915923

916-
RTCSession_DTMF.DTMF dtmf = RTCSession_DTMF.DTMF(this);
924+
RTCSession_DTMF.DTMF dtmf = RTCSession_DTMF.DTMF(this, mode: mode);
917925

918926
EventManager handlers = EventManager();
919927
handlers.on(EventCallFailed(), (EventCallFailed event) {

lib/src/rtc_session/dtmf.dart

Lines changed: 49 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import 'package:flutter_webrtc/flutter_webrtc.dart';
2+
import 'package:sip_ua/sip_ua.dart';
3+
14
import '../constants.dart';
25
import '../event_manager/event_manager.dart';
36
import '../event_manager/internal_events.dart';
@@ -16,12 +19,16 @@ class C {
1619
}
1720

1821
class DTMF extends EventManager {
19-
DTMF(this._session);
22+
DTMF(this._session, {DtmfMode mode = DtmfMode.INFO}) {
23+
_mode = mode;
24+
}
2025

2126
final rtc.RTCSession _session;
27+
DtmfMode _mode;
2228
String _direction;
2329
String _tone;
2430
int _duration;
31+
int _interToneGap;
2532
IncomingRequest _request;
2633
EventManager _eventHandlers;
2734

@@ -66,40 +73,47 @@ class DTMF extends EventManager {
6673

6774
// Duration is checked/corrected in RTCSession.
6875
_duration = options['duration'];
69-
70-
extraHeaders.add('Content-Type: application/dtmf-relay');
71-
72-
String body = 'Signal=$_tone\r\n';
73-
74-
body += 'Duration=$_duration';
75-
76-
_session.newDTMF('local', this, _request);
77-
78-
EventManager handlers = EventManager();
79-
handlers.on(EventOnSuccessResponse(), (EventOnSuccessResponse event) {
80-
emit(EventSucceeded(originator: 'remote', response: event.response));
81-
});
82-
handlers.on(EventOnErrorResponse(), (EventOnErrorResponse event) {
83-
_eventHandlers.emit(EventOnFialed());
84-
emit(EventOnFialed());
85-
emit(EventCallFailed(originator: 'remote', response: event.response));
86-
});
87-
handlers.on(EventOnRequestTimeout(), (EventOnRequestTimeout event) {
88-
_session.onRequestTimeout();
89-
});
90-
handlers.on(EventOnTransportError(), (EventOnTransportError event) {
91-
_session.onTransportError();
92-
});
93-
94-
handlers.on(EventOnDialogError(), (EventOnDialogError event) {
95-
_session.onDialogError();
96-
});
97-
98-
_session.sendRequest(SipMethod.INFO, <String, dynamic>{
99-
'extraHeaders': extraHeaders,
100-
'eventHandlers': handlers,
101-
'body': body
102-
});
76+
_interToneGap = options['interToneGap'];
77+
78+
if (_mode == DtmfMode.RFC2833) {
79+
RTCDTMFSender dtmfSender = _session.dtmfSender;
80+
dtmfSender.insertDTMF(_tone,
81+
duration: _duration, interToneGap: _interToneGap);
82+
} else if (_mode == DtmfMode.INFO) {
83+
extraHeaders.add('Content-Type: application/dtmf-relay');
84+
85+
String body = 'Signal=$_tone\r\n';
86+
87+
body += 'Duration=$_duration';
88+
89+
_session.newDTMF('local', this, _request);
90+
91+
EventManager handlers = EventManager();
92+
handlers.on(EventOnSuccessResponse(), (EventOnSuccessResponse event) {
93+
emit(EventSucceeded(originator: 'remote', response: event.response));
94+
});
95+
handlers.on(EventOnErrorResponse(), (EventOnErrorResponse event) {
96+
_eventHandlers.emit(EventOnFialed());
97+
emit(EventOnFialed());
98+
emit(EventCallFailed(originator: 'remote', response: event.response));
99+
});
100+
handlers.on(EventOnRequestTimeout(), (EventOnRequestTimeout event) {
101+
_session.onRequestTimeout();
102+
});
103+
handlers.on(EventOnTransportError(), (EventOnTransportError event) {
104+
_session.onTransportError();
105+
});
106+
107+
handlers.on(EventOnDialogError(), (EventOnDialogError event) {
108+
_session.onDialogError();
109+
});
110+
111+
_session.sendRequest(SipMethod.INFO, <String, dynamic>{
112+
'extraHeaders': extraHeaders,
113+
'eventHandlers': handlers,
114+
'body': body
115+
});
116+
}
103117
}
104118

105119
void init_incoming(IncomingRequest request) {

lib/src/sip_ua_helper.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ class SIPUAHelper extends EventManager {
106106
_settings.register_expires = uaSettings.register_expires;
107107
_settings.register_extra_contact_uri_params =
108108
uaSettings.registerParams.extraContactUriParams;
109+
_settings.dtmf_mode = uaSettings.dtmfMode;
109110

110111
try {
111112
_ua = UA(_settings);
@@ -543,6 +544,11 @@ class WebSocketSettings {
543544
bool allowBadCertificate = false;
544545
}
545546

547+
enum DtmfMode {
548+
INFO,
549+
RFC2833,
550+
}
551+
546552
class UaSettings {
547553
String webSocketUrl;
548554
WebSocketSettings webSocketSettings = WebSocketSettings();
@@ -565,6 +571,9 @@ class UaSettings {
565571
String ha1;
566572
String displayName;
567573

574+
/// DTMF mode, in band (rfc2833) or out of band (sip info)
575+
DtmfMode dtmfMode = DtmfMode.INFO;
576+
568577
List<Map<String, String>> iceServers = <Map<String, String>>[
569578
<String, String>{'url': 'stun:stun.l.google.com:19302'},
570579
// turn server configuration example.

0 commit comments

Comments
 (0)