Skip to content

Commit

Permalink
feat(calls): add support for sending Matrix RTC call notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanceriu committed May 18, 2024
1 parent cbb92ca commit 21e4009
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 6 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ ruma = { version = "0.10.0", features = [
"compat-tag-info",
"unstable-msc3401",
"unstable-msc3266",
"unstable-msc4075"
] }
ruma-common = { version = "0.13.0" }
once_cell = "1.16.0"
Expand Down
13 changes: 12 additions & 1 deletion bindings/matrix-sdk-ffi/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ use ruma::events::{
RedactedStateEventContent, StaticStateEventContent, SyncMessageLikeEvent, SyncStateEvent,
};

use crate::{room_member::MembershipState, ruma::MessageType, ClientError};
use crate::{
room_member::MembershipState,
ruma::{MessageType, NotifyType},
ClientError,
};

#[derive(uniffi::Object)]
pub struct TimelineEvent(pub(crate) AnySyncTimelineEvent);
Expand Down Expand Up @@ -119,6 +123,7 @@ pub enum MessageLikeEventContent {
CallInvite,
CallHangup,
CallCandidates,
CallNotify { notify_type: NotifyType },
KeyVerificationReady,
KeyVerificationStart,
KeyVerificationCancel,
Expand All @@ -143,6 +148,12 @@ impl TryFrom<AnySyncMessageLikeEvent> for MessageLikeEventContent {
AnySyncMessageLikeEvent::CallInvite(_) => MessageLikeEventContent::CallInvite,
AnySyncMessageLikeEvent::CallHangup(_) => MessageLikeEventContent::CallHangup,
AnySyncMessageLikeEvent::CallCandidates(_) => MessageLikeEventContent::CallCandidates,
AnySyncMessageLikeEvent::CallNotify(content) => {
let original_content = get_message_like_event_original_content(content)?;
MessageLikeEventContent::CallNotify {
notify_type: original_content.notify_type.into(),
}
}
AnySyncMessageLikeEvent::KeyVerificationReady(_) => {
MessageLikeEventContent::KeyVerificationReady
}
Expand Down
57 changes: 56 additions & 1 deletion bindings/matrix-sdk-ffi/src/room.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use ruma::{
api::client::room::report_content,
assign,
events::{
call::notify,
room::{
avatar::ImageInfo as RumaAvatarImageInfo,
power_levels::RoomPowerLevels as RumaPowerLevels, MediaSource,
Expand All @@ -30,7 +31,7 @@ use crate::{
event::{MessageLikeEventType, StateEventType},
room_info::RoomInfo,
room_member::RoomMember,
ruma::ImageInfo,
ruma::{ImageInfo, Mentions, NotifyType},
timeline::{EventTimelineItem, FocusEventError, ReceiptType, Timeline},
utils::u64_to_uint,
TaskHandle,
Expand Down Expand Up @@ -644,6 +645,48 @@ impl Room {
let event_id = EventId::parse(event_id)?;
Ok(self.inner.matrix_to_event_permalink(event_id).await?.to_string())
}

/// This will only send a call notification event if appropriate.
///
/// This function is supposed to be called whenever the user creates a room
/// call. It will send a `m.call.notify` event if:
/// - there is not yet a running call.
/// It will configure the notify type: ring or notify based on:
/// - is this a DM room -> ring
/// - is this a group with more than one other member -> notify
pub async fn send_call_notification_if_needed(&self) -> Result<(), ClientError> {
self.inner.send_call_notification_if_needed().await?;
Ok(())
}

/// Send a call notification event in the current room.
///
/// This is only supposed to be used in **custom** situations where the user
/// explicitly chooses to send a `m.call.notify` event to invite/notify
/// someone explicitly in unusual conditions. The default should be to
/// use `send_call_notification_if_necessary` just before a new room call is
/// created/joined.
///
/// One example could be that the UI allows to start a call with a subset of
/// users of the room members first. And then later on the user can
/// invite more users to the call.
pub async fn send_call_notification(
&self,
call_id: String,
application: RtcApplicationType,
notify_type: NotifyType,
mentions: Mentions,
) -> Result<(), ClientError> {
self.inner
.send_call_notification(
call_id,
application.into(),
notify_type.into(),
mentions.into(),
)
.await?;
Ok(())
}
}

/// Generates a `matrix.to` permalink to the given room alias.
Expand Down Expand Up @@ -770,3 +813,15 @@ impl TryFrom<ImageInfo> for RumaAvatarImageInfo {
}))
}
}

#[derive(uniffi::Enum)]
pub enum RtcApplicationType {
Call,
}
impl From<RtcApplicationType> for notify::ApplicationType {
fn from(value: RtcApplicationType) -> Self {
match value {
RtcApplicationType::Call => notify::ApplicationType::Call,
}
}
}
26 changes: 26 additions & 0 deletions bindings/matrix-sdk-ffi/src/ruma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use matrix_sdk::attachment::{
use ruma::{
assign,
events::{
call::notify::NotifyType as RumaNotifyType,
location::AssetType as RumaAssetType,
poll::start::PollKind as RumaPollKind,
room::{
Expand Down Expand Up @@ -375,6 +376,31 @@ impl From<RumaMessageType> for MessageType {
}
}

#[derive(Clone, uniffi::Enum)]
pub enum NotifyType {
Ring,
Notify,
}

impl From<RumaNotifyType> for NotifyType {
fn from(val: RumaNotifyType) -> Self {
match val {
RumaNotifyType::Notify => Self::Notify,
RumaNotifyType::Ring => Self::Ring,
_ => Self::Notify,
}
}
}

impl From<NotifyType> for RumaNotifyType {
fn from(value: NotifyType) -> Self {
match value {
NotifyType::Ring => RumaNotifyType::Ring,
NotifyType::Notify => RumaNotifyType::Notify,
}
}
}

#[derive(Clone, uniffi::Record)]
pub struct EmoteMessageContent {
pub body: String,
Expand Down
1 change: 1 addition & 0 deletions crates/matrix-sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Additions:
outbound session for that room. Can be used by clients as a dev tool like the `/discardsession` command.
- Add a new `LinkedChunk` data structure to represents all events per room ([#3166](https://github.com/matrix-org/matrix-rust-sdk/pull/3166)).
- 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()`
- Add `send_call_notification` and `send_call_notification_if_needed` methods. This allows to implement sending ring events on call start.

# 0.7.0

Expand Down
62 changes: 58 additions & 4 deletions crates/matrix-sdk/src/room/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ use ruma::{
},
assign,
events::{
call::notify::{ApplicationType, CallNotifyEventContent, NotifyType},
direct::DirectEventContent,
marked_unread::MarkedUnreadEventContent,
receipt::{Receipt, ReceiptThread, ReceiptType},
Expand All @@ -68,10 +69,11 @@ use ruma::{
space::{child::SpaceChildEventContent, parent::SpaceParentEventContent},
tag::{TagInfo, TagName},
typing::SyncTypingEvent,
AnyRoomAccountDataEvent, AnyTimelineEvent, EmptyStateKey, MessageLikeEventContent,
MessageLikeEventType, RedactContent, RedactedStateEventContent, RoomAccountDataEvent,
RoomAccountDataEventContent, RoomAccountDataEventType, StateEventContent, StateEventType,
StaticEventContent, StaticStateEventContent, SyncStateEvent,
AnyRoomAccountDataEvent, AnyTimelineEvent, EmptyStateKey, Mentions,
MessageLikeEventContent, MessageLikeEventType, RedactContent, RedactedStateEventContent,
RoomAccountDataEvent, RoomAccountDataEventContent, RoomAccountDataEventType,
StateEventContent, StateEventType, StaticEventContent, StaticStateEventContent,
SyncStateEvent,
},
push::{Action, PushConditionRoomCtx},
serde::Raw,
Expand Down Expand Up @@ -2619,6 +2621,58 @@ impl Room {
(maybe_room.unwrap(), drop_handles)
})
}

/// This will only send a call notification event if appropriate.
///
/// This function is supposed to be called whenever the user creates a room
/// call. It will send a `m.call.notify` event if:
/// - there is not yet a running call.
/// It will configure the notify type: ring or notify based on:
/// - is this a DM room -> ring
/// - is this a group with more than one other member -> notify
pub async fn send_call_notification_if_needed(&self) -> Result<()> {
if self.has_active_room_call() {
return Ok(());
}

self.send_call_notification(
self.room_id().to_string().to_owned(),
ApplicationType::Call,
if self.is_direct().await.unwrap_or(false) {
NotifyType::Ring
} else {
NotifyType::Notify
},
Mentions::with_room_mention(),
)
.await?;

Ok(())
}

/// Send a call notification event in the current room.
///
/// This is only supposed to be used in **custom** situations where the user
/// explicitly chooses to send a `m.call.notify` event to invite/notify
/// someone explicitly in unusual conditions. The default should be to
/// use `send_call_notification_if_needed` just before a new room call is
/// created/joined.
///
/// One example could be that the UI allows to start a call with a subset of
/// users of the room members first. And then later on the user can
/// invite more users to the call.
pub async fn send_call_notification(
&self,
call_id: String,
application: ApplicationType,
notify_type: NotifyType,
mentions: Mentions,
) -> Result<()> {
let call_notify_event_content =
CallNotifyEventContent::new(call_id, application, notify_type, mentions);
self.send(call_notify_event_content).await?;
Ok(())
}
}

/// Details of the (latest) invite.
Expand Down

0 comments on commit 21e4009

Please sign in to comment.