# Tài liệu hướng dẫn xử lý VOIP call/callkit
###### tags: `voip` `callkit` `apns`
> Tài liệu này nhằm mục đích cung cấp khái niệm, mô tả luồng gọi voip, các setting, tài liệu kham khảo
## :memo: Khái niệm cơ bản
### 1. Callkit
- Là framework của iOS để tương tác với hệ thống iOS nhằm xử lý hiển thị cuộc gọi đến.
- Có thể đổ chuông ngay cả khi app đã bị kill
- Khởi tạo app, webRTC ngay khi bấm nút Accept.
- Xử lý call API khi bấm nút decline
| Lock screen | Banner |
| -------- | -------- |
| <img src="https://camo.githubusercontent.com/4617553e03a372a5b059bc53d48c9dfc8167848682884accbfdce9174213c142/68747470733a2f2f646576656c6f706572732e636f6e6e65637479637562652e636f6d2f646f63732f5f696d616765732f636f64655f73616d706c65732f666c75747465722f6261636b67726f756e645f63616c6c5f696f735f6c6f636b65642e504e47" alt="drawing" width="200"/> | <img src="https://camo.githubusercontent.com/91b87d69bfce04dc36135ca1d62f7af0c382610d5b8d1501f7536522b56e0c89/68747470733a2f2f646576656c6f706572732e636f6e6e65637479637562652e636f6d2f646f63732f5f696d616765732f636f64655f73616d706c65732f666c75747465722f6261636b67726f756e645f63616c6c5f696f732e504e47" alt="drawing" width="200"/> |
### 2.Android sử dụng Receiver, Service và Activty để xử lý phần này.
| Lock screen | Banner |
| -------- | -------- |
| <img src="https://camo.githubusercontent.com/f0bce3cd938e644bc10370c519ea4aa5bdeb430d3b74cd096dc466a4f79e638b/68747470733a2f2f646576656c6f706572732e636f6e6e65637479637562652e636f6d2f646f63732f5f696d616765732f636f64655f73616d706c65732f666c75747465722f6261636b67726f756e645f63616c6c5f616e64726f69645f6c6f636b65642e706e67" alt="drawing" width="200"/> | <img src="https://camo.githubusercontent.com/64cc7ff4f0fef499dceb35835b01b288b0f085696b0ae579f8cf5be1d1e6f3eb/68747470733a2f2f646576656c6f706572732e636f6e6e65637479637562652e636f6d2f646f63732f5f696d616765732f636f64655f73616d706c65732f666c75747465722f6261636b67726f756e645f63616c6c5f616e64726f69642e706e67" alt="drawing" width="200"/> |
### 3. iOS VoIP push
- Là 1 channel push khác channel push bình thường. Chỉ dùng để xử lý show incoming call screen.
## :memo: Cài đặt
### 1. Cài đặt iOS
#### Cài đặt Onesingal
- [https://documentation.onesignal.com/docs/ios-sdk-setup](https://documentation.onesignal.com/docs/ios-sdk-setup)
**KEY_ID**: `4cd1a3e3-a7d0-4229-afd5-9cdd58a4b35a`
#### Tạo certificate
- [https://documentation.onesignal.com/docs/voip-notifications](https://documentation.onesignal.com/docs/voip-notifications)
<img src="https://developer.apple.com/library/archive/documentation/Performance/Conceptual/EnergyGuide-iOS/Art/voip_certificate_creation_2x.png" alt="drawing" width="400"/>
#### Cấu hình VoIP trên project xCode
- [https://developer.apple.com/library/archive/documentation/Performance/Conceptual/EnergyGuide-iOS/OptimizeVoIP.html#//apple_ref/doc/uid/TP40015243-CH30](https://developer.apple.com/library/archive/documentation/Performance/Conceptual/EnergyGuide-iOS/OptimizeVoIP.html#//apple_ref/doc/uid/TP40015243-CH30)
<img src="https://developer.apple.com/library/archive/documentation/Performance/Conceptual/EnergyGuide-iOS/Art/xcode_project_capabilities_backgroundmodes_2x.png" alt="drawing" width="400"/>
#### Copy code dưới đây vào xcode project.
- [https://github.com/ConnectyCube/connectycube-flutter-call-kit/tree/master/ios/Classes](https://github.com/ConnectyCube/connectycube-flutter-call-kit/tree/master/ios/Classes)
### 2. Cài đặt cho Android
#### Cài đặt Onesingal
- [https://documentation.onesignal.com/docs/android-sdk-setup](https://documentation.onesignal.com/docs/android-sdk-setup)
**KEY_ID**: `4cd1a3e3-a7d0-4229-afd5-9cdd58a4b35a`
:::info
**Note**: Sau khi login cần setExternalUserId, lý do hệ thống sẽ push theo Id của user tới tất cả các thiết bị mà user đang login. Tương tự cần xóa khi logout để tránh bị push bị đang chưa login app.
:::
```
String externalUserId = "123456789"; // You will supply the external user id to the OneSignal SDK
OneSignal.setExternalUserId(externalUserId);
```
#### Copy sender ID và Sever key từ Firebase lên Onesignal (Đã làm hộ Android)
- Từ Firebase: [https://console.firebase.google.com/project/demowebrtc2/settings/cloudmessaging](https://console.firebase.google.com/project/demowebrtc2/settings/cloudmessaging)
- Lên: [https://dashboard.onesignal.com/apps/4cd1a3e3-a7d0-4229-afd5-9cdd58a4b35a/settings/configure/google-android](https://dashboard.onesignal.com/apps/4cd1a3e3-a7d0-4229-afd5-9cdd58a4b35a/settings/configure/google-android)

#### Copy code dưới đây vào project. Sau đó sẽ có thể cần modify 1 chút để phù hợp với APP
- [https://github.com/ConnectyCube/connectycube-flutter-call-kit/tree/master/android](https://github.com/ConnectyCube/connectycube-flutter-call-kit/tree/master/android)
### 3. Cài đặt phía backend
#### API key
`YzQ0ZTU4MDQtZDhjMi00ZDkyLThlNmYtZDJhN2NiZDFiYWI2`
#### Tạo push thông thường (Android)
```javascript
var sendNotification = function(data) {
var headers = {
"Content-Type": "application/json; charset=utf-8",
"Authorization": "Basic YzQ0ZTU4MDQtZDhjMi00ZDkyLThlNmYtZDJhN2NiZDFiYWI2"
};
var options = {
host: "onesignal.com",
port: 443,
path: "/api/v1/notifications",
method: "POST",
headers: headers
};
var https = require('https');
var req = https.request(options, function(res) {
res.on('data', function(data) {
console.log("Response:");
console.log(JSON.parse(data));
});
});
req.on('error', function(e) {
console.log("ERROR:");
console.log(e);
});
req.write(JSON.stringify(data));
req.end();
};
var iOSMessage = {
app_id: "4cd1a3e3-a7d0-4229-afd5-9cdd58a4b35a",
contents: {"en": "Pharmatist"},
data: {
session_id: "982cf533-7b1b-4cf6-a6e0-004aab68c503",
caller_id: "1234",
caller_name: "Pharmatist",
call_type: "1",
call_opponents: "1"
},
apns_push_type_override: "voip",
include_external_user_ids: ["ios_1"],
isAndroid: false
}
var androidMessage = {,
app_id: "4cd1a3e3-a7d0-4229-afd5-9cdd58a4b35a",
contents: {"en": "Pharmatist"},
data: {
session_id: "982cf533-7b1b-4cf6-a6e0-004aab68c503",
caller_id: "1234",
caller_name: "Pharmatist",
call_type: "1",
call_opponents: "1"
},
channel_for_external_user_ids: "push",
include_external_user_ids: ["6392d91a-b206-4b7b-a620-cd68e32c3a76"],
isIos: false
};
// send voip for iOS devices
sendNotification(iOSMessage);
// send notification for Android devices
sendNotification(androidMessage);
```
**app_id**: Không đổi
**session_id**: UUID Được gửi lên từ web khi bắt đầu cuộc gọi.
**caller_id**: Id của người bắt đầu cuộc gọi, gửi lên từ app
**caller_name**: Tên của người gọi, gửi lên từ app
**call_type**: Không đổi
**call_opponents**: Không đổi
**channel_for_external_user_ids**: Không đổi
**include_external_user_ids**: Mảng user nhận cuộc gọi đến.
## UML diagrams
```sequence
FE->BE: API create notification
BE->OneSignal: Notifícation ios/Android
OneSignal->Phone: Push APNS/FCM
FE->Firestore: Send offer/cancel/hangup
Firestore-->>Phone: Forward offer/cancel/hangup
Phone->Firestore: Send state ring/answer/decline/hangup
Firestore-->>FE: Forward state ring/answer/decline/hangup
FE->Phone: Voip Call
Phone-->>FE: Voip Call
```
- Auto-generated Table of Content
[ToC]
:::warning
Tài liệu mang tính chất tham khảo, trong quá trình thực hiện task có thể sẽ cần update.
:::