Skip to content

Commit ac7c4c2

Browse files
committed
feat(calls): add support for sending Matrix RTC call notifications
1 parent d7a8877 commit ac7c4c2

File tree

6 files changed

+154
-6
lines changed

6 files changed

+154
-6
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ ruma = { version = "0.10.1", features = [
4848
"compat-tag-info",
4949
"unstable-msc3401",
5050
"unstable-msc3266",
51+
"unstable-msc4075"
5152
] }
5253
ruma-common = { version = "0.13.0" }
5354
once_cell = "1.16.0"

bindings/matrix-sdk-ffi/src/event.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ use ruma::events::{
55
RedactedStateEventContent, StaticStateEventContent, SyncMessageLikeEvent, SyncStateEvent,
66
};
77

8-
use crate::{room_member::MembershipState, ruma::MessageType, ClientError};
8+
use crate::{
9+
room_member::MembershipState,
10+
ruma::{MessageType, NotifyType},
11+
ClientError,
12+
};
913

1014
#[derive(uniffi::Object)]
1115
pub struct TimelineEvent(pub(crate) AnySyncTimelineEvent);
@@ -119,6 +123,7 @@ pub enum MessageLikeEventContent {
119123
CallInvite,
120124
CallHangup,
121125
CallCandidates,
126+
CallNotify { notify_type: NotifyType },
122127
KeyVerificationReady,
123128
KeyVerificationStart,
124129
KeyVerificationCancel,
@@ -143,6 +148,12 @@ impl TryFrom<AnySyncMessageLikeEvent> for MessageLikeEventContent {
143148
AnySyncMessageLikeEvent::CallInvite(_) => MessageLikeEventContent::CallInvite,
144149
AnySyncMessageLikeEvent::CallHangup(_) => MessageLikeEventContent::CallHangup,
145150
AnySyncMessageLikeEvent::CallCandidates(_) => MessageLikeEventContent::CallCandidates,
151+
AnySyncMessageLikeEvent::CallNotify(content) => {
152+
let original_content = get_message_like_event_original_content(content)?;
153+
MessageLikeEventContent::CallNotify {
154+
notify_type: original_content.notify_type.into(),
155+
}
156+
}
146157
AnySyncMessageLikeEvent::KeyVerificationReady(_) => {
147158
MessageLikeEventContent::KeyVerificationReady
148159
}

bindings/matrix-sdk-ffi/src/room.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use ruma::{
1212
api::client::room::report_content,
1313
assign,
1414
events::{
15+
call::notify,
1516
room::{
1617
avatar::ImageInfo as RumaAvatarImageInfo,
1718
power_levels::RoomPowerLevels as RumaPowerLevels, MediaSource,
@@ -30,7 +31,7 @@ use crate::{
3031
event::{MessageLikeEventType, StateEventType},
3132
room_info::RoomInfo,
3233
room_member::RoomMember,
33-
ruma::ImageInfo,
34+
ruma::{ImageInfo, Mentions, NotifyType},
3435
timeline::{EventTimelineItem, FocusEventError, ReceiptType, Timeline},
3536
utils::u64_to_uint,
3637
TaskHandle,
@@ -644,6 +645,48 @@ impl Room {
644645
let event_id = EventId::parse(event_id)?;
645646
Ok(self.inner.matrix_to_event_permalink(event_id).await?.to_string())
646647
}
648+
649+
/// This will only send a call notification event if appropriate.
650+
///
651+
/// This function is supposed to be called whenever the user creates a room
652+
/// call. It will send a `m.call.notify` event if:
653+
/// - there is not yet a running call.
654+
/// It will configure the notify type: ring or notify based on:
655+
/// - is this a DM room -> ring
656+
/// - is this a group with more than one other member -> notify
657+
pub async fn send_call_notification_if_needed(&self) -> Result<(), ClientError> {
658+
self.inner.send_call_notification_if_needed().await?;
659+
Ok(())
660+
}
661+
662+
/// Send a call notification event in the current room.
663+
///
664+
/// This is only supposed to be used in **custom** situations where the user
665+
/// explicitly chooses to send a `m.call.notify` event to invite/notify
666+
/// someone explicitly in unusual conditions. The default should be to
667+
/// use `send_call_notification_if_necessary` just before a new room call is
668+
/// created/joined.
669+
///
670+
/// One example could be that the UI allows to start a call with a subset of
671+
/// users of the room members first. And then later on the user can
672+
/// invite more users to the call.
673+
pub async fn send_call_notification(
674+
&self,
675+
call_id: String,
676+
application: RtcApplicationType,
677+
notify_type: NotifyType,
678+
mentions: Mentions,
679+
) -> Result<(), ClientError> {
680+
self.inner
681+
.send_call_notification(
682+
call_id,
683+
application.into(),
684+
notify_type.into(),
685+
mentions.into(),
686+
)
687+
.await?;
688+
Ok(())
689+
}
647690
}
648691

649692
/// Generates a `matrix.to` permalink to the given room alias.
@@ -770,3 +813,15 @@ impl TryFrom<ImageInfo> for RumaAvatarImageInfo {
770813
}))
771814
}
772815
}
816+
817+
#[derive(uniffi::Enum)]
818+
pub enum RtcApplicationType {
819+
Call,
820+
}
821+
impl From<RtcApplicationType> for notify::ApplicationType {
822+
fn from(value: RtcApplicationType) -> Self {
823+
match value {
824+
RtcApplicationType::Call => notify::ApplicationType::Call,
825+
}
826+
}
827+
}

bindings/matrix-sdk-ffi/src/ruma.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use matrix_sdk::attachment::{
2121
use ruma::{
2222
assign,
2323
events::{
24+
call::notify::NotifyType as RumaNotifyType,
2425
location::AssetType as RumaAssetType,
2526
poll::start::PollKind as RumaPollKind,
2627
room::{
@@ -375,6 +376,31 @@ impl From<RumaMessageType> for MessageType {
375376
}
376377
}
377378

379+
#[derive(Clone, uniffi::Enum)]
380+
pub enum NotifyType {
381+
Ring,
382+
Notify,
383+
}
384+
385+
impl From<RumaNotifyType> for NotifyType {
386+
fn from(val: RumaNotifyType) -> Self {
387+
match val {
388+
RumaNotifyType::Notify => Self::Notify,
389+
RumaNotifyType::Ring => Self::Ring,
390+
_ => Self::Notify,
391+
}
392+
}
393+
}
394+
395+
impl From<NotifyType> for RumaNotifyType {
396+
fn from(value: NotifyType) -> Self {
397+
match value {
398+
NotifyType::Ring => RumaNotifyType::Ring,
399+
NotifyType::Notify => RumaNotifyType::Notify,
400+
}
401+
}
402+
}
403+
378404
#[derive(Clone, uniffi::Record)]
379405
pub struct EmoteMessageContent {
380406
pub body: String,

crates/matrix-sdk/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Additions:
2525
outbound session for that room. Can be used by clients as a dev tool like the `/discardsession` command.
2626
- Add a new `LinkedChunk` data structure to represents all events per room ([#3166](https://github.com/matrix-org/matrix-rust-sdk/pull/3166)).
2727
- Add new methods for tracking (on device only) the user's recently visited rooms called `Account::track_recently_visited_room(roomId)` and `Account::get_recently_visited_rooms()`
28+
- Add `send_call_notification` and `send_call_notification_if_needed` methods. This allows to implement sending ring events on call start.
2829

2930
# 0.7.0
3031

crates/matrix-sdk/src/room/mod.rs

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ use ruma::{
5151
},
5252
assign,
5353
events::{
54+
call::notify::{ApplicationType, CallNotifyEventContent, NotifyType},
5455
direct::DirectEventContent,
5556
marked_unread::MarkedUnreadEventContent,
5657
receipt::{Receipt, ReceiptThread, ReceiptType},
@@ -68,10 +69,11 @@ use ruma::{
6869
space::{child::SpaceChildEventContent, parent::SpaceParentEventContent},
6970
tag::{TagInfo, TagName},
7071
typing::SyncTypingEvent,
71-
AnyRoomAccountDataEvent, AnyTimelineEvent, EmptyStateKey, MessageLikeEventContent,
72-
MessageLikeEventType, RedactContent, RedactedStateEventContent, RoomAccountDataEvent,
73-
RoomAccountDataEventContent, RoomAccountDataEventType, StateEventContent, StateEventType,
74-
StaticEventContent, StaticStateEventContent, SyncStateEvent,
72+
AnyRoomAccountDataEvent, AnyTimelineEvent, EmptyStateKey, Mentions,
73+
MessageLikeEventContent, MessageLikeEventType, RedactContent, RedactedStateEventContent,
74+
RoomAccountDataEvent, RoomAccountDataEventContent, RoomAccountDataEventType,
75+
StateEventContent, StateEventType, StaticEventContent, StaticStateEventContent,
76+
SyncStateEvent,
7577
},
7678
push::{Action, PushConditionRoomCtx},
7779
serde::Raw,
@@ -2627,6 +2629,58 @@ impl Room {
26272629
(maybe_room.unwrap(), drop_handles)
26282630
})
26292631
}
2632+
2633+
/// This will only send a call notification event if appropriate.
2634+
///
2635+
/// This function is supposed to be called whenever the user creates a room
2636+
/// call. It will send a `m.call.notify` event if:
2637+
/// - there is not yet a running call.
2638+
/// It will configure the notify type: ring or notify based on:
2639+
/// - is this a DM room -> ring
2640+
/// - is this a group with more than one other member -> notify
2641+
pub async fn send_call_notification_if_needed(&self) -> Result<()> {
2642+
if self.has_active_room_call() {
2643+
return Ok(());
2644+
}
2645+
2646+
self.send_call_notification(
2647+
self.room_id().to_string().to_owned(),
2648+
ApplicationType::Call,
2649+
if self.is_direct().await.unwrap_or(false) {
2650+
NotifyType::Ring
2651+
} else {
2652+
NotifyType::Notify
2653+
},
2654+
Mentions::with_room_mention(),
2655+
)
2656+
.await?;
2657+
2658+
Ok(())
2659+
}
2660+
2661+
/// Send a call notification event in the current room.
2662+
///
2663+
/// This is only supposed to be used in **custom** situations where the user
2664+
/// explicitly chooses to send a `m.call.notify` event to invite/notify
2665+
/// someone explicitly in unusual conditions. The default should be to
2666+
/// use `send_call_notification_if_needed` just before a new room call is
2667+
/// created/joined.
2668+
///
2669+
/// One example could be that the UI allows to start a call with a subset of
2670+
/// users of the room members first. And then later on the user can
2671+
/// invite more users to the call.
2672+
pub async fn send_call_notification(
2673+
&self,
2674+
call_id: String,
2675+
application: ApplicationType,
2676+
notify_type: NotifyType,
2677+
mentions: Mentions,
2678+
) -> Result<()> {
2679+
let call_notify_event_content =
2680+
CallNotifyEventContent::new(call_id, application, notify_type, mentions);
2681+
self.send(call_notify_event_content).await?;
2682+
Ok(())
2683+
}
26302684
}
26312685

26322686
/// Details of the (latest) invite.

0 commit comments

Comments
 (0)