Hướng dẫn xây dựng ứng dụng gọi video 1-1 trên nền tảng Android với Stringee Call API
Tổng quan về Stringee Call API
Stringee Call API là cách dễ nhất để xây dựng các ứng dụng thoại chất lượng cao trên Đám mây. Với Call API của Stringee, bạn có thể:
Xây dựng ứng dụng mở rộng quy mô với các công nghệ web bạn chọn. Mua số điện thoại động. Mở rộng cơ sở hạ tầng của bạn với Giao diện SIP. Kiểm soát luồng cuộc gọi trong JSON bằng Đối tượng điều khiển cuộc gọi Stringee. (SCCO): Thực hiện cuộc gọi giữa ứng dụng với ứng dụng (cuộc gọi ngang hàng) HOẶC cuộc gọi từ ứng dụng tới điện thoại (cuộc gọi đi). Nhận và quản lý cuộc gọi điện thoại (cuộc gọi đến): chuyển cuộc gọi đến ứng dụng, từ chối cuộc gọi, ghi âm, v.v. Ghi âm và lưu trữ cuộc gọi. Tạo cuộc gọi hội nghị.
Chuẩn bị
Trước khi bạn có thể dùng Stringee Call API để tạo và nhận cuộc gọi video, bạn cần :
-
Tạo tài khoản Stringee miễn phí tại đây
-
Tạo project trên Stringee Dashboard
- Cấu hình answer_url
-
Để hiểu rõ hơn về answer_url, bạn xem tại đây. Bạn có thể tham khảo cách tạo answer_url tại đây
-
Để có thể thực hiện cuộc gọi bạn cần cấu hình answer_url vào project của bạn như sau:
Nếu bạn chưa có sẵn answer_url, bạn có thể sử dụng Project's answer_url sau để đẩy nhanh quá trình:
https://developer.stringee.com/scco_helper/simple_project_answer_url?record=false&appToPhone=auto&recordFormat=mp3
(Source code: https://github.com/stringeecom/server-samples/blob/master/answer_url/php/project_answer_url.php) Khi xây dựng ứng dụng, bạn nên có answer_url của riêng mình.
Tích hợp Stringee SDK
Chuẩn bị
- Tạo một project Android với minSdkVersion >= 16.
- Tạo class MainActivity làm màn hình chính để thực hiện việc kết nối đến Stringee Server.
- Tạo class CallActivity để hiển thị màn hình của cuộc gọi.
Cài đặt Stringee SDK
Stringee Android SDK được phân phối dưới dạng AAR và có thể được thêm vào dự án của bạn bằng cách tham chiếu AAR từ xa với Maven.
-
Mở file build.gradle và thêm các dòng sau:
buildscript { repositories { ... mavenCentral() } } ... allprojects { repositories { ... mavenCentral() } }
-
Mở file app/build.gradle và thêm các dòng sau:
android { ... compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { ... implementation 'com.stringee.sdk.android:stringee-android-sdk:2.0' implementation 'com.android.volley:volley:1.2.1' }
Chỉnh sửa Permissions và proguard
Permissions
Stringee Android SDK yêu cầu một số permissions, mở file AndroidManifest.xml và thêm các dòng sau:
/// permission cho việc kết nối internet
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
// permission cho cuộc gọi
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
// Nếu sử dụng class StringeeAudioManager của Stringee quản lý phát âm thanh thì cần thêm các permission này
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> // permission này mới thêm trên Android SDK version 31
Ghi chú:
- Bạn bắt buộc phải cấp đủ quyền trước khi thực hiện cuộc gọi, trước khi thực hiện cuộc gọi bạn bắt buộc yêu cầu các quyền sau: RECORD_AUDIO, CAMERA
- Với việc sử dụng class StringeeAudioManager bạn cần cấp thêm quyền BLUETOOTH_CONNECT đối với Android SDK version 31 trở lên
ProGuard
Nếu project của bạn sử dụng ProGuard, bạn cần thêm các cài đặt sau vào file proguard-rules.pro để đảm bảo khi build ra bản release Stringee SDK có thể chạy được chính xác:
-dontwarn org.webrtc.**
-keep class org.webrtc.** { *; }
-dontwarn org.apache.http.**
-keep class com.stringee.** { *; }
Kết nối Stringee server
Để kết nối đến Stringee Server, bạn cần có access_token. Trong quá trình xây dựng ứng dụng, access_token nên được tạo ra từ server của bạn, bạn có thể tìm hiểu thêm về authentication ở đây: Client authentication, và code mẫu tạo access_token: https://github.com/stringeecom/server-samples/tree/master/access_token.
Để tiết kiệm thời gian, chúng tôi sẽ hard code access_token ở trong ứng dụng:
- Ở class MainActivity, khởi tạo một biến để chứa access_token.
public class MainActivity extends AppCompatActivity { private String token = "access_token";
- Lấy access_token và hard code dữ liệu : Để làm điều đó, chúng tôi đã cung cấp sẵn tool để sinh ra access_token, bạn truy cập vào Dashboard -> Tools -> Generate Access token và sinh access_token của bạn.
Tiếp theo, chúng ta sẽ kết nối đến Stringee Server. Bạn cần phải kết nối được đến Stringee Server trước thì mới có thể thực hiệc được cuộc gọi.
-
Thêm đối tượng StringeeClient vào class MainActivity.
private StringeeClient client;
-
Khởi tạo đối tượng StringeeClient và lắng nghe sự kiện từ StringeeConnectionListener để giao tiếp với Stringee Server:
client = new StringeeClient(this); // Lắng nghe sự kiện của StringeeClient client.setConnectionListener(new StringeeConnectionListener() { @Override public void onConnectionConnected(final StringeeClient stringeeClient, boolean isReconnecting) { } @Override public void onConnectionDisconnected(StringeeClient stringeeClient, boolean isReconnecting) { } @Override public void onIncomingCall(final StringeeCall stringeeCall) { } @Override public void onIncomingCall2(StringeeCall2 stringeeCall2) { } @Override public void onConnectionError(StringeeClient stringeeClient, final StringeeError stringeeError) { } @Override public void onRequestNewToken(StringeeClient stringeeClient) { } @Override public void onCustomMessage(String s, JSONObject jsonObject) { } @Override public void onTopicMessage(String s, JSONObject jsonObject) { } });
- Khi client kết nối thành công đến Stringee Server, hàm onConnectionConnected(StringeeClient stringeeClient, boolean isReconnecting) được gọi đến.
- Khi client mất kết nối với Stringee Server, hàm onConnectionDisconnected(StringeeClient stringeeClient, boolean isReconnecting) được gọi đến.
- Khi client kết nối thất bại đến Stringee Server, hàm onConnectionError(StringeeClient stringeeClient, StringeeError stringeeError) được gọi đến.
- Khi access_token hết hạn, hàm onRequestNewToken(StringeeClient stringeeClient) được gọi đến. Bạn sẽ cần tạo lại access_token mới và kết nối lại.
- Khi client nhận được cuộc gọi đến, ở đây chúng ta dùng đối tượng StringeeCall2 để thực hiện cuộc gọi video nên hàm onIncomingCall2(StringeeCall2 stringeeCall2) được gọi đến.
- Nếu bạn sử dụng On-Premise Server, bạn cần thêm những dòng sau để có thể kết nối được:
import com.stringee.common.SocketAddress; import java.util.ArrayList; import java.util.List; ... List<SocketAddress> socketAddressList = new ArrayList<>(); socketAddressList.add(new SocketAddress("ip", port)); client.setHost(socketAddressList);
- ip: ip của server của bạn ở dạng String.
- port: port của server của bạn ở dạng int.
Ghi chú: Bạn cần phải setHost trước khi kết nối.
- Kết nối đến Stringee Server bằng access_token được tạo ra ở trên:
client.connect(token);
Xử lý logic cuộc gọi
Sau khi kết nối đến Stringee Server, bạn cần thực hiện các bước sau:
- Thêm đối tượng stringeeCall2 vào class CallActivity:
private StringeeCall2 stringeeCall2; // Class StringeeAudioManager dùng để quản lý âm thanh private StringeeAudioManager audioManager;
- Lắng nghe sự kiện của cuộc gọi:
// Lắng nghe sự kiện của cuộc gọi stringeeCall2.setCallListener(new StringeeCall2.StringeeCallListener() { @Override public void onSignalingStateChange(StringeeCall2 stringeeCall, StringeeCall2.SignalingState signalingState, String reason, int sipCode, String sipReason) { } @Override public void onError(StringeeCall2 stringeeCall2, int code, String description) { } @Override public void onHandledOnAnotherDevice(StringeeCall2 stringeeCall2, StringeeCall2.SignalingState signalingState, String description) { } @Override public void onMediaStateChange(StringeeCall2 stringeeCall2, StringeeCall2.MediaState mediaState) { } @Override public void onLocalStream(StringeeCall2 stringeeCall2) { } @Override public void onRemoteStream(StringeeCall2 stringeeCall2) { } @Override public void onVideoTrackAdded(StringeeVideoTrack stringeeVideoTrack) { } @Override public void onVideoTrackRemoved(StringeeVideoTrack stringeeVideoTrack) { } @Override public void onCallInfo(StringeeCall2 stringeeCall2, JSONObject callInfo) { } @Override public void onTrackMediaStateChange(String from, MediaType mediaType, boolean enable) { } }); // Khởi tạo audioManager để quản lý việc phát âm thanh audioManager = StringeeAudioManager.create(this); audioManager.start(new StringeeAudioManager.AudioManagerEvents() { @Override public void onAudioDeviceChanged(StringeeAudioManager.AudioDevice selectedAudioDevice, Set<StringeeAudioManager.AudioDevice> availableAudioDevices) { // Mọi thay đổi thiết bị âm thanh sẽ nhận được ở đây } }); audioManager.setSpeakerphoneOn(true); // false: loa trong, true: loa ngoài
- Khi tạo/trả lời cuộc gọi thất bại, hàm onError(StringeeCall stringeeCall, int code, String description) được gọi đến.
- Khi tạo/trả lời cuộc gọi thành công, cuộc gọi sẽ đi qua rất nhiều trạng thái như là: CALLING, RINGING, ANSWERED, ENDED, BUSY. Mỗi lần trạng thái của cuộc gọi thay đổi, hàm onSignalingStateChange(StringeeCall call, StringeeCall.SignalingState signalingState, String reason, int sipCode, String sipReason) được gọi đến.
- Khi media stream của cuộc gọi đã kết nối hoặc mất kết nối, hàm onMediaStateChange(StringeeCall stringeeCall, StringeeCall.MediaState mediaState) được gọi đến.
- Khi cuộc gọi được xử lý trên thiết bị khác, hàm onHandledOnAnotherDevice(StringeeCall stringeeCall, StringeeCall.SignalingState signalingState, String description) được gọi đến.
- Một cuộc gọi thực sự được thành công khi trạng thái của media là MediaState.CONNECTED.
Tạo cuộc gọi đi
Để tạo cuộc gọi đi bạn cần thực hiện các bước sau:
- Khởi tạo stringeeCall2:
stringeeCall2 = new StringeeCall2(MainActivity.this, client, from, to); stringeeCall2.setVideoCall(true); // false: Audio Call, true: Video Call
- client: Đối tượng StringeeClient đã được khởi tạo và dùng để connect đến Stringee Server trước đó. Cần đảm bảo đã kết nối đến Stringee Server thành công và vẫn đang giữ kết nối .
- from: id của người gọi.
- to: is của người nhận.
- Mặc định là cuộc gọi thoại nên nếu bạn muốn khởi tạo cuộc gọi video bạn cần gọi hàm** setVideoCall(true)** trước khi gọi hàm makeCall() và sau khi khởi tạo StringeeCall2.
- Thực hiện cuộc gọi:
// Khởi tạo cuộc gọi stringeeCall2.makeCall();
Trả lời cuộc gọi
Để có thể trả lời được cuộc gọi đến, bạn làm theo những bước sau:
-
Xử lý nhận cuộc gọi ở hàm onIncomingCall2(StringeeCall2 stringeeCall2) thuộc StringeeConnectionListener.
@Override public void onIncomingCall2(StringeeCall2 stringeeCall2) { callsMap.put(stringeeCall2.getCallId(), stringeeCall2); Intent intent = new Intent(MainActivity.this, CallActivity.class); intent.putExtra("call_id", stringeeCall2.getCallId()); startActivity(intent); }
Lưu trữ stringeeCall2 vào đối tượng HashMap() với khóa là callId. Sau đó gửi callId của cuộc gọi sang class CallActivity.
-
Gán StringeeCall2 từ callsMap:
String callId = getIntent().getStringExtra("call_id"); stringeeCall2 = callsMap.get(callId);
-
Gửi tín hiệu RINGING:
Như việc khởi tạo cuộc gọi, ta cần lắng nghe các sự kiện của cuộc gọi
// Gửi tín hiệu RINGING stringeeCall2.ringing(new StatusListener() { @Override public void onSuccess() { } });
-
Trả lời và bắt đầu cuộc gọi:
stringeeCall2.answer();
Hiển thị video
Stringee Android SDK hiển thị video của người gọi và người nhận dưới dạng đối tượng View. Bạn có thể thêm chúng như là con của một đối tượng ViewGroup ở ứng dụng. Ở sample, chúng tôi sử dụng đối tượng FrameLayout làm vùng chứa cho video của người gọi và người nhận:
-
Mở file app/res/layout/activity_call.xml và thêm các dòng sau:
<FrameLayout android:id="@+id/v_remote" android:layout_width="match_parent" android:layout_height="match_parent" /> <FrameLayout android:id="@+id/v_local" android:layout_width="80dp" android:layout_height="120dp" android:layout_alignParentRight="true" android:layout_margin="10dp" />
-
Khai báo vLocal and vRemote trong class CallActivity.
private FrameLayout vLocal; private FrameLayout vRemote; ... vLocal = findViewById(R.id.v_local); vRemote = findViewById(R.id.v_remote);
-
Hiển thị video:
Sau khi nhận được sự kiện onLocalStream(StringeeCall2 stringeeCall2), ta có thể thêm video của mình vào vLocal:
@Override public void onLocalStream(StringeeCall2 stringeeCall2) { runOnUiThread(new Runnable() { @Override public void run() { if (stringeeCall2.isVideoCall()) { vLocal.addView(stringeeCall2.getLocalView()); stringeeCall2.renderLocalView(true); } } }); }
Tương tự như onLocalStream, ta có thể thêm video của người bên kia vào vRemote sau khi nhận được event onRemoteStream(StringeeCall2 stringeeCall2):
@Override public void onRemoteStream(StringeeCall2 stringeeCall2) { runOnUiThread(new Runnable() { @Override public void run() { if (stringeeCall2.isVideoCall()) { vRemote.addView(stringeeCall2.getRemoteView()); stringeeCall2.renderRemoteView(false); } } }); }
Việc thêm view của video cần được thực hiện dưới background UI thread để có thể giao tiếp được với UI components.
Một số tính năng trong cuộc gọi
Ngừng cuộc gọi
Ngừng cuộc gọi và giải phóng tài nguyên của cuộc gọi:
stringeeCall2.hangup();
// Nếu sử dụng StringeeAudioManager, cần gọi hàm này để đưa trạng thái của audio về như lúc trước khi vào cuộc gọi
audioManager.stop();
Từ chối cuộc gọi
Từ chối cuộc gọi:
stringeeCall2.reject();
// Nếu sử dụng StringeeAudioManager, cần gọi hàm này để đưa trạng thái của audio về như lúc trước khi vào cuộc gọi
audioManager.stop();
Tắt tiếng
Tắt tiếng của mình:
bool mute = true // true: tắt, false: mở
stringeeCall2.mute(true);
Chuyển đổi loa
Chuyển đổi giữa loa trong và loa ngoài bằng StringeeAudioManager:
bool isSpeaker = true // true: loa ngoài, false: loa trong
audioManager.setSpeakerphoneOn(isSpeaker);
Đổi camera
Đổi trước và sau camera của mình:
stringeeCall2.switchCamera(new StatusListener() {
@Override
public void onSuccess() {
}
});
Tắt/Mở video
Tắt/Mở video:
bool enableVideo = true // true: mở, false: tắt
stringeeCall2.enableVideo(enableVideo);
Chạy app
Bây giờ ứng dụng của bạn có thể chạy được trên thiết bị. Bạn có thể tham khảo sample phiên bản đầy đủ ở đây
Kết luận
Trên đây là hướng dẫn xây dựng ứng dụng gọi video 1-1 trên nền tảng Android với Stringee Call API. Hy vọng bạn có thể tự mình thiết lập một ứng dụng gọi video theo như hướng dẫn của Stringee. Ngoài ra, bạn có thể học cách xây dựng ứng dụng gọi video trên nền tảng iOS tại đây.
All rights reserved