diff --git a/deltachat-jsonrpc/src/api.rs b/deltachat-jsonrpc/src/api.rs index fe6d2e744..ea847ddb8 100644 --- a/deltachat-jsonrpc/src/api.rs +++ b/deltachat-jsonrpc/src/api.rs @@ -2068,6 +2068,40 @@ impl CommandApi { .map(|msg_id| msg_id.to_u32())) } + /// Starts an outgoing call. + async fn place_outgoing_call( + &self, + account_id: u32, + chat_id: u32, + place_call_info: String, + ) -> Result { + let ctx = self.get_context(account_id).await?; + let msg_id = ctx + .place_outgoing_call(ChatId::new(chat_id), place_call_info) + .await?; + Ok(msg_id.to_u32()) + } + + /// Accepts an incoming call. + async fn accept_incoming_call( + &self, + account_id: u32, + msg_id: u32, + accept_call_info: String, + ) -> Result<()> { + let ctx = self.get_context(account_id).await?; + ctx.accept_incoming_call(MsgId::new(msg_id), accept_call_info) + .await?; + Ok(()) + } + + /// Ends incoming or outgoing call. + async fn end_call(&self, account_id: u32, msg_id: u32) -> Result<()> { + let ctx = self.get_context(account_id).await?; + ctx.end_call(MsgId::new(msg_id)).await?; + Ok(()) + } + /// Makes an HTTP GET request and returns a response. /// /// `url` is the HTTP or HTTPS URL. diff --git a/deltachat-rpc-client/src/deltachat_rpc_client/chat.py b/deltachat-rpc-client/src/deltachat_rpc_client/chat.py index fa4006e0f..6f3facdc2 100644 --- a/deltachat-rpc-client/src/deltachat_rpc_client/chat.py +++ b/deltachat-rpc-client/src/deltachat_rpc_client/chat.py @@ -289,3 +289,8 @@ class Chat: f.write(vcard.encode()) f.flush() self._rpc.send_msg(self.account.id, self.id, {"viewtype": ViewType.VCARD, "file": f.name}) + + def place_outgoing_call(self, place_call_info: str) -> Message: + """Starts an outgoing call.""" + msg_id = self._rpc.place_outgoing_call(self.account.id, self.id, place_call_info) + return Message(self.account, msg_id) diff --git a/deltachat-rpc-client/src/deltachat_rpc_client/const.py b/deltachat-rpc-client/src/deltachat_rpc_client/const.py index 6e62142e9..522fd4ab9 100644 --- a/deltachat-rpc-client/src/deltachat_rpc_client/const.py +++ b/deltachat-rpc-client/src/deltachat_rpc_client/const.py @@ -73,6 +73,10 @@ class EventType(str, Enum): CHATLIST_ITEM_CHANGED = "ChatlistItemChanged" ACCOUNTS_CHANGED = "AccountsChanged" ACCOUNTS_ITEM_CHANGED = "AccountsItemChanged" + INCOMING_CALL = "IncomingCall" + INCOMING_CALL_ACCEPTED = "IncomingCallAccepted" + OUTGOING_CALL_ACCEPTED = "OutgoingCallAccepted" + CALL_ENDED = "CallEnded" CONFIG_SYNCED = "ConfigSynced" WEBXDC_REALTIME_DATA = "WebxdcRealtimeData" WEBXDC_REALTIME_ADVERTISEMENT_RECEIVED = "WebxdcRealtimeAdvertisementReceived" diff --git a/deltachat-rpc-client/src/deltachat_rpc_client/message.py b/deltachat-rpc-client/src/deltachat_rpc_client/message.py index 4fbad3975..2eda3c854 100644 --- a/deltachat-rpc-client/src/deltachat_rpc_client/message.py +++ b/deltachat-rpc-client/src/deltachat_rpc_client/message.py @@ -102,3 +102,11 @@ class Message: def send_webxdc_realtime_data(self, data) -> None: """Send data to the realtime channel.""" yield self._rpc.send_webxdc_realtime_data.future(self.account.id, self.id, list(data)) + + def accept_incoming_call(self, accept_call_info): + """Accepts an incoming call.""" + self._rpc.accept_incoming_call(self.account.id, self.id, accept_call_info) + + def end_call(self): + """Ends incoming or outgoing call.""" + self._rpc.end_call(self.account.id, self.id) diff --git a/deltachat-rpc-client/tests/test_calls.py b/deltachat-rpc-client/tests/test_calls.py new file mode 100644 index 000000000..ea1eb9a84 --- /dev/null +++ b/deltachat-rpc-client/tests/test_calls.py @@ -0,0 +1,25 @@ +from deltachat_rpc_client import EventType, Message + + +def test_calls(acfactory) -> None: + alice, bob = acfactory.get_online_accounts(2) + + place_call_info = "offer" + accept_call_info = "answer" + + alice_contact_bob = alice.create_contact(bob, "Bob") + alice_chat_bob = alice_contact_bob.create_chat() + outgoing_call_message = alice_chat_bob.place_outgoing_call(place_call_info) + + incoming_call_event = bob.wait_for_event(EventType.INCOMING_CALL) + assert incoming_call_event.place_call_info == place_call_info + incoming_call_message = Message(bob, incoming_call_event.msg_id) + + incoming_call_message.accept_incoming_call(accept_call_info) + outgoing_call_accepted_event = alice.wait_for_event(EventType.OUTGOING_CALL_ACCEPTED) + assert outgoing_call_accepted_event.accept_call_info == accept_call_info + + outgoing_call_message.end_call() + + end_call_event = bob.wait_for_event(EventType.CALL_ENDED) + assert end_call_event.msg_id == outgoing_call_message.id