Merge branch 'client-enhance-add-call-methods' into 'master'
[Client] Add call methods See merge request famedly/famedlysdk!153
This commit is contained in:
commit
5430bad08a
|
@ -32,6 +32,7 @@ export 'package:famedlysdk/src/utils/mx_content.dart';
|
||||||
export 'package:famedlysdk/src/utils/profile.dart';
|
export 'package:famedlysdk/src/utils/profile.dart';
|
||||||
export 'package:famedlysdk/src/utils/push_rules.dart';
|
export 'package:famedlysdk/src/utils/push_rules.dart';
|
||||||
export 'package:famedlysdk/src/utils/states_map.dart';
|
export 'package:famedlysdk/src/utils/states_map.dart';
|
||||||
|
export 'package:famedlysdk/src/utils/turn_server_credentials.dart';
|
||||||
export 'package:famedlysdk/src/account_data.dart';
|
export 'package:famedlysdk/src/account_data.dart';
|
||||||
export 'package:famedlysdk/src/client.dart';
|
export 'package:famedlysdk/src/client.dart';
|
||||||
export 'package:famedlysdk/src/event.dart';
|
export 'package:famedlysdk/src/event.dart';
|
||||||
|
|
|
@ -30,6 +30,7 @@ import 'package:famedlysdk/src/presence.dart';
|
||||||
import 'package:famedlysdk/src/store_api.dart';
|
import 'package:famedlysdk/src/store_api.dart';
|
||||||
import 'package:famedlysdk/src/sync/user_update.dart';
|
import 'package:famedlysdk/src/sync/user_update.dart';
|
||||||
import 'package:famedlysdk/src/utils/matrix_file.dart';
|
import 'package:famedlysdk/src/utils/matrix_file.dart';
|
||||||
|
import 'package:famedlysdk/src/utils/turn_server_credentials.dart';
|
||||||
import 'package:pedantic/pedantic.dart';
|
import 'package:pedantic/pedantic.dart';
|
||||||
import 'room.dart';
|
import 'room.dart';
|
||||||
import 'event.dart';
|
import 'event.dart';
|
||||||
|
@ -400,6 +401,15 @@ class Client {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get credentials for the client to use when initiating calls.
|
||||||
|
Future<TurnServerCredentials> getTurnServerCredentials() async {
|
||||||
|
final Map<String, dynamic> response = await this.jsonRequest(
|
||||||
|
type: HTTPType.GET,
|
||||||
|
action: "/client/r0/voip/turnServer",
|
||||||
|
);
|
||||||
|
return TurnServerCredentials.fromJson(response);
|
||||||
|
}
|
||||||
|
|
||||||
/// Fetches the pushrules for the logged in user.
|
/// Fetches the pushrules for the logged in user.
|
||||||
/// These are needed for notifications on Android
|
/// These are needed for notifications on Android
|
||||||
Future<PushRules> getPushrules() async {
|
Future<PushRules> getPushrules() async {
|
||||||
|
@ -477,6 +487,18 @@ class Client {
|
||||||
final StreamController<AccountData> onAccountData =
|
final StreamController<AccountData> onAccountData =
|
||||||
StreamController.broadcast();
|
StreamController.broadcast();
|
||||||
|
|
||||||
|
/// Will be called on call invites.
|
||||||
|
final StreamController<Event> onCallInvite = StreamController.broadcast();
|
||||||
|
|
||||||
|
/// Will be called on call hangups.
|
||||||
|
final StreamController<Event> onCallHangup = StreamController.broadcast();
|
||||||
|
|
||||||
|
/// Will be called on call candidates.
|
||||||
|
final StreamController<Event> onCallCandidates = StreamController.broadcast();
|
||||||
|
|
||||||
|
/// Will be called on call answers.
|
||||||
|
final StreamController<Event> onCallAnswer = StreamController.broadcast();
|
||||||
|
|
||||||
/// Matrix synchronisation is done with https long polling. This needs a
|
/// Matrix synchronisation is done with https long polling. This needs a
|
||||||
/// timeout which is usually 30 seconds.
|
/// timeout which is usually 30 seconds.
|
||||||
int syncTimeoutSec = 30;
|
int syncTimeoutSec = 30;
|
||||||
|
@ -894,6 +916,16 @@ class Client {
|
||||||
_updateRoomsByEventUpdate(update);
|
_updateRoomsByEventUpdate(update);
|
||||||
this.store?.storeEventUpdate(update);
|
this.store?.storeEventUpdate(update);
|
||||||
onEvent.add(update);
|
onEvent.add(update);
|
||||||
|
|
||||||
|
if (event["type"] == "m.call.invite") {
|
||||||
|
onCallInvite.add(Event.fromJson(event, getRoomById(roomID)));
|
||||||
|
} else if (event["type"] == "m.call.hangup") {
|
||||||
|
onCallHangup.add(Event.fromJson(event, getRoomById(roomID)));
|
||||||
|
} else if (event["type"] == "m.call.answer") {
|
||||||
|
onCallAnswer.add(Event.fromJson(event, getRoomById(roomID)));
|
||||||
|
} else if (event["type"] == "m.call.candidates") {
|
||||||
|
onCallCandidates.add(Event.fromJson(event, getRoomById(roomID)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -220,6 +220,18 @@ class Event {
|
||||||
return EventTypes.Sticker;
|
return EventTypes.Sticker;
|
||||||
case "m.room.message":
|
case "m.room.message":
|
||||||
return EventTypes.Message;
|
return EventTypes.Message;
|
||||||
|
case "m.call.encrypted":
|
||||||
|
return EventTypes.Encrypted;
|
||||||
|
case "m.call.encryption":
|
||||||
|
return EventTypes.Encryption;
|
||||||
|
case "m.call.invite":
|
||||||
|
return EventTypes.CallInvite;
|
||||||
|
case "m.call.answer":
|
||||||
|
return EventTypes.CallAnswer;
|
||||||
|
case "m.call.candidates":
|
||||||
|
return EventTypes.CallCandidates;
|
||||||
|
case "m.call.hangup":
|
||||||
|
return EventTypes.CallHangup;
|
||||||
}
|
}
|
||||||
return EventTypes.Unknown;
|
return EventTypes.Unknown;
|
||||||
}
|
}
|
||||||
|
@ -394,5 +406,11 @@ enum EventTypes {
|
||||||
RoomAvatar,
|
RoomAvatar,
|
||||||
GuestAccess,
|
GuestAccess,
|
||||||
HistoryVisibility,
|
HistoryVisibility,
|
||||||
|
Encryption,
|
||||||
|
Encrypted,
|
||||||
|
CallInvite,
|
||||||
|
CallAnswer,
|
||||||
|
CallCandidates,
|
||||||
|
CallHangup,
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1048,6 +1048,103 @@ class Room {
|
||||||
data: data,
|
data: data,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This is sent by the caller when they wish to establish a call.
|
||||||
|
/// [callId] is a unique identifier for the call.
|
||||||
|
/// [version] is the version of the VoIP specification this message adheres to. This specification is version 0.
|
||||||
|
/// [lifetime] is the time in milliseconds that the invite is valid for. Once the invite age exceeds this value,
|
||||||
|
/// clients should discard it. They should also no longer show the call as awaiting an answer in the UI.
|
||||||
|
/// [type] The type of session description. Must be 'offer'.
|
||||||
|
/// [sdp] The SDP text of the session description.
|
||||||
|
Future<String> inviteToCall(String callId, int lifetime, String sdp,
|
||||||
|
{String type = "offer", int version = 0, String txid}) async {
|
||||||
|
if (txid == null) txid = "txid${DateTime.now().millisecondsSinceEpoch}";
|
||||||
|
final Map<String, dynamic> response = await client.jsonRequest(
|
||||||
|
type: HTTPType.PUT,
|
||||||
|
action: "/client/r0/rooms/$id/send/m.call.invite/$txid",
|
||||||
|
data: {
|
||||||
|
"call_id": callId,
|
||||||
|
"lifetime": lifetime,
|
||||||
|
"offer": {"sdp": sdp, "type": type},
|
||||||
|
"version": version,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return response["event_id"];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is sent by callers after sending an invite and by the callee after answering.
|
||||||
|
/// Its purpose is to give the other party additional ICE candidates to try using to communicate.
|
||||||
|
///
|
||||||
|
/// [callId] The ID of the call this event relates to.
|
||||||
|
///
|
||||||
|
/// [version] The version of the VoIP specification this messages adheres to. This specification is version 0.
|
||||||
|
///
|
||||||
|
/// [candidates] Array of objects describing the candidates. Example:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// [
|
||||||
|
/// {
|
||||||
|
/// "candidate": "candidate:863018703 1 udp 2122260223 10.9.64.156 43670 typ host generation 0",
|
||||||
|
/// "sdpMLineIndex": 0,
|
||||||
|
/// "sdpMid": "audio"
|
||||||
|
/// }
|
||||||
|
/// ],
|
||||||
|
/// ```
|
||||||
|
Future<String> sendCallCandidates(
|
||||||
|
String callId,
|
||||||
|
List<Map<String, dynamic>> candidates, {
|
||||||
|
int version = 0,
|
||||||
|
String txid,
|
||||||
|
}) async {
|
||||||
|
if (txid == null) txid = "txid${DateTime.now().millisecondsSinceEpoch}";
|
||||||
|
final Map<String, dynamic> response = await client.jsonRequest(
|
||||||
|
type: HTTPType.PUT,
|
||||||
|
action: "/client/r0/rooms/$id/send/m.call.candidates/$txid",
|
||||||
|
data: {
|
||||||
|
"call_id": callId,
|
||||||
|
"candidates": candidates,
|
||||||
|
"version": version,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return response["event_id"];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This event is sent by the callee when they wish to answer the call.
|
||||||
|
/// [callId] is a unique identifier for the call.
|
||||||
|
/// [version] is the version of the VoIP specification this message adheres to. This specification is version 0.
|
||||||
|
/// [type] The type of session description. Must be 'answer'.
|
||||||
|
/// [sdp] The SDP text of the session description.
|
||||||
|
Future<String> answerCall(String callId, String sdp,
|
||||||
|
{String type = "answer", int version = 0, String txid}) async {
|
||||||
|
if (txid == null) txid = "txid${DateTime.now().millisecondsSinceEpoch}";
|
||||||
|
final Map<String, dynamic> response = await client.jsonRequest(
|
||||||
|
type: HTTPType.PUT,
|
||||||
|
action: "/client/r0/rooms/$id/send/m.call.answer/$txid",
|
||||||
|
data: {
|
||||||
|
"call_id": callId,
|
||||||
|
"answer": {"sdp": sdp, "type": type},
|
||||||
|
"version": version,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return response["event_id"];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This event is sent by the callee when they wish to answer the call.
|
||||||
|
/// [callId] The ID of the call this event relates to.
|
||||||
|
/// [version] is the version of the VoIP specification this message adheres to. This specification is version 0.
|
||||||
|
Future<String> hangupCall(String callId,
|
||||||
|
{int version = 0, String txid}) async {
|
||||||
|
if (txid == null) txid = "txid${DateTime.now().millisecondsSinceEpoch}";
|
||||||
|
final Map<String, dynamic> response = await client.jsonRequest(
|
||||||
|
type: HTTPType.PUT,
|
||||||
|
action: "/client/r0/rooms/$id/send/m.call.hangup/$txid",
|
||||||
|
data: {
|
||||||
|
"call_id": callId,
|
||||||
|
"version": version,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return response["event_id"];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PushRuleState { notify, mentions_only, dont_notify }
|
enum PushRuleState { notify, mentions_only, dont_notify }
|
||||||
|
|
23
lib/src/utils/turn_server_credentials.dart
Normal file
23
lib/src/utils/turn_server_credentials.dart
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/// Credentials for the client to use when initiating calls.
|
||||||
|
class TurnServerCredentials {
|
||||||
|
/// The username to use.
|
||||||
|
final String username;
|
||||||
|
|
||||||
|
/// The password to use.
|
||||||
|
final String password;
|
||||||
|
|
||||||
|
/// A list of TURN URIs
|
||||||
|
final List<String> uris;
|
||||||
|
|
||||||
|
/// The time-to-live in seconds
|
||||||
|
final int ttl;
|
||||||
|
|
||||||
|
const TurnServerCredentials(
|
||||||
|
this.username, this.password, this.uris, this.ttl);
|
||||||
|
|
||||||
|
TurnServerCredentials.fromJson(Map<String, dynamic> json)
|
||||||
|
: username = json['username'],
|
||||||
|
password = json['password'],
|
||||||
|
uris = json['uris'].cast<String>(),
|
||||||
|
ttl = json['ttl'];
|
||||||
|
}
|
Loading…
Reference in a new issue