Penjelasan tentang cara memulai cepat

Apa yang Twilio lakukan?

Itu melakukan semua pekerjaan berat dalam mengelola pengguna di sebuah ruangan dan mengirimkan trek video dan audio di antara mereka. Pada dasarnya yang perlu kita lakukan hanyalah…

  1. Siapkan UI dan lingkungan untuk koneksi
  2. Menangani acara pengguna

Cara menggunakan Video yang Dapat Diprogram Twilio

Segala sesuatu di artikel ini diambil dari dokumentasi Twilio dan proyek mulai cepat.

Pertama kita tambahkan SDK Twilio yang disediakan. Ini mencakup semua fungsi dan objek yang diperlukan.

// inside our app's build.gradle
// Twilio video sdk
implementation 'com.twilio:video-android:$version'

Atur tampilan tampilan

Kami kemudian dapat menggunakan videoView dari SDK untuk menampilkan video di layar

import com.twilio.video.VideoView;

Versi xmlnya adalah

<com.twilio.video.VideoView
    android:id="@+id/primary_video_view"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:keepScreenOn="true" />

dan versi kodenya adalah

VideoView v = new VideoView(context);
v.setKeepScreenOn(true);

Jaga agar perangkat tetap terjaga

Perhatikan saya memasang atribut setKeepScreenon karena kemungkinan besar kita tidak ingin ponsel tertidur selama panggilan video. Sangat mudah bahwa keepScreenOn dapat digunakan dengan tampilan anak mana pun dan akan bekerja dengan cara yang sama seperti pada tampilan induk.

Menghubungkan ke Ruangan

Buat Token Akses

Setiap pengguna diharuskan menggunakan Token Akses untuk terhubung ke suatu ruangan. Ini unik untuk setiap pengguna di setiap ruang pertemuan. Langkah ini biasanya dilakukan di backend.

// taken from https://www.twilio.com/docs/iam/access-tokens?code-sample=code-creating-an-access-token-video-2&code-language=Java&code-sdk-version=7.x
import com.twilio.jwt.accesstoken.AccessToken;
import com.twilio.jwt.accesstoken.VideoGrant;

public class TokenGenerator {

  public static void main(String[] args) {
    // Required for all types of tokens
    String twilioAccountSid = "ACxxxxxxxxxxxx";
    String twilioApiKey = "SKxxxxxxxxxxxx";
    String twilioApiSecret = "xxxxxxxxxxxxxx";

    // Required for Video
    String identity = "user";

    // Create Video grant
    VideoGrant grant = new VideoGrant().setRoom("cool room");

    // Create access token
    AccessToken token = new AccessToken.Builder(
      twilioAccountSid,
      twilioApiKey,
      twilioApiSecret
    ).identity(identity).grant(grant).build();

    System.out.println(token.toJwt());
  }
}

Kemudian di aplikasi front end kita, kita dapat terhubung ke ruangan menggunakan token akses. RoomName sudah ditentukan saat membuat token akses, jadi argumen di sini tidak akan memengaruhi ruangan mana yang sebenarnya akan kita sambungkan.

// taken from https://www.twilio.com/docs/video/android-getting-started
public void connectToRoom(String roomName) {
  ConnectOptions connectOptions = new ConnectOptions.Builder(accessToken)
    .roomName(roomName)
    .audioTracks(localAudioTracks)
    .videoTracks(localVideoTracks)
    .dataTracks(localDataTracks)
    .build();
  room = Video.connect(context, connectOptions, roomListener);
}

Buat trek video dan audio lokal

Agar connectToRoom() berfungsi, Kita perlu membagikan video dan suara kita kepada peserta lain melalui trek.

private void createAudioAndVideoTracks() {
    // Share your microphone
    localAudioTrack = LocalAudioTrack.create(this, true, LOCAL_AUDIO_TRACK_NAME);

    // Share your camera
    cameraCapturerCompat = new CameraCapturerCompat(this, getAvailableCameraSource());
    localVideoTrack = LocalVideoTrack.create(this,
            true,
            cameraCapturerCompat.getVideoCapturer(),
            LOCAL_VIDEO_TRACK_NAME);
    primaryVideoView.setMirror(true);
    localVideoTrack.addRenderer(primaryVideoView);
    localVideoView = primaryVideoView;
}

Minta izin untuk mikrofon dan kamera

Dalam manifes kita, kita akan membutuhkan semua ini.

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

Lalu akhirnya kami bisa memeriksa dan meminta izin.

private boolean checkPermissionForCameraAndMicrophone() {
        int resultCamera = ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA);
        int resultMic = ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO);
        return resultCamera == PackageManager.PERMISSION_GRANTED &&
                resultMic == PackageManager.PERMISSION_GRANTED;
    }

    private void requestPermissionForCameraAndMicrophone() {

            // request permission in fragment
            requestPermissions(
                    new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO},
                    CAMERA_MIC_PERMISSION_REQUEST_CODE);

    }

Dan kita perlu menangkap peristiwa tersebut ketika izin diberikan

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

    if (requestCode == CAMERA_MIC_PERMISSION_REQUEST_CODE && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED
    ) {
        Toast.makeText(context, "Permission granted", Toast.LENGTH_LONG).show();
    }
}

Menangani Acara Pengguna

Twilio akan melaporkan kejadian seperti peserta terhubung, terputus melalui panggilan balik. Kita harus menyediakan antarmuka roomListener() saat kita terhubung ke sebuah ruangan.

Selain mengatur pendengar untuk ruangan tersebut, kita juga harus memasang pendengar untuk setiap peserta di ruangan tersebut. Pendengar ini akan melacak status video dan audio peserta tertentu.

Kita dapat melihat metode lengkap untuk panggilan balik ini dengan membaca contoh memulai cepat Twilio.

Di bawah ini adalah contoh untuk roomListener(), yang ingin kita lakukan di sini adalah segera setelah onConnected() dipanggil, kita mengumpulkan semua peserta dalam ruangan dan melampirkan remoteParticipantListener() ke masing-masing peserta.

Tentu saja, kita juga perlu melampirkan pendengar ke setiap peserta yang bergabung dalam ruangan tersebut di masa mendatang.

private Room.Listener roomListener() {
    return new Room.Listener() {
        @Override
        public void onConnected(Room room) {
            Toast.makeText(MainActivity.this, "Connected to room " + room.getName(), Toast.LENGTH_LONG).show();

            localParticipant = room.getLocalParticipant();

            List<RemoteParticipant> remoteParticipants = room.getRemoteParticipants();

            for (RemoteParticipant remoteParticipant : remoteParticipants) {

                addRemoteParticipant(remoteParticipant);
            }

            // adding the participant does not mean their video track is ready to be subscribed
            // display the videos in the onVideoTrackSubscribed callback
        }

        @Override
        public void onParticipantConnected(Room room, RemoteParticipant remoteParticipant) {
            addRemoteParticipant(remoteParticipant);
        }

        @Override
        public void onParticipantDisconnected(Room room, RemoteParticipant remoteParticipant) {
            removeRemoteParticipant(remoteParticipant);
        }
}

Karena ini adalah antarmuka Java, kita harus menyelesaikan semua metode yang diperlukan. Namun untungnya nama metodenya cukup jelas dan logika untuk menampilkan dan menghapus video peserta dari UI sangatlah mudah.

Di bawah ini adalah contoh panggilan balik remoteParticipantListener(). Ingat ini adalah pendengar untuk setiap peserta, jadi perbarui tampilan yang benar untuk peserta yang benar.

// add listener to each participant when you joined a room

@SuppressLint("SetTextI18n")
private RemoteParticipant.Listener remoteParticipantListener() {
    return new RemoteParticipant.Listener() {
        @Override
        public void onAudioTrackPublished(RemoteParticipant remoteParticipant,
                                          RemoteAudioTrackPublication remoteAudioTrackPublication) {
            Log.i(TAG, String.format("onAudioTrackPublished: " +
                            "[RemoteParticipant: identity=%s], " +
                            "[RemoteAudioTrackPublication: sid=%s, enabled=%b, " +
                            "subscribed=%b, name=%s]",
                    remoteParticipant.getIdentity(),
                    remoteAudioTrackPublication.getTrackSid(),
                    remoteAudioTrackPublication.isTrackEnabled(),
                    remoteAudioTrackPublication.isTrackSubscribed(),
                    remoteAudioTrackPublication.getTrackName()));
        }

        @Override
        public void onAudioTrackUnpublished(RemoteParticipant remoteParticipant,
                                            RemoteAudioTrackPublication remoteAudioTrackPublication) {
            Log.i(TAG, String.format("onAudioTrackUnpublished: " +
                            "[RemoteParticipant: identity=%s], " +
                            "[RemoteAudioTrackPublication: sid=%s, enabled=%b, " +
                            "subscribed=%b, name=%s]",
                    remoteParticipant.getIdentity(),
                    remoteAudioTrackPublication.getTrackSid(),
                    remoteAudioTrackPublication.isTrackEnabled(),
                    remoteAudioTrackPublication.isTrackSubscribed(),
                    remoteAudioTrackPublication.getTrackName()));
        }
......

Bersihkan dan lepaskan sumber daya

Terakhir ingatlah untuk menangani penyambungan kembali dan pemutusan hubungan sesuai dengan siklus hidup aktivitas kita.

Jika beberapa aplikasi lain dengan prioritas lebih tinggi mengganggu aplikasi kita atau pengguna mematikan layar secara manual dengan mengklik tombol daya, kita harus memutuskan sambungan dari ruangan. Karena pengguna mungkin tidak kembali dan Twilio akan terus menghitung menit layanan dan menagih uang.

Oleh karena itu, metode onPause() kita harus meminimalkan pemutusan sambungan dari ruangan dan melepaskan sumber daya kamera dan mikrofon ponsel kita.

@Override
public void onPause(){
    super.onPause();


    /*
     * Release the local video track before going in the background. This ensures that the
     * camera can be used by other applications while this app is in the background.
     */
    if (localVideoTrack != null) {
        /*
         * If this local video track is being shared in a Room, unpublish from room before
         * releasing the video track. Participants will be notified that the track has been
         * unpublished.
         */
        if (localParticipant != null) {
            localParticipant.unpublishTrack(localVideoTrack);
        }

        localVideoTrack.release();
        localVideoTrack = null;
    }

    /*
     * Always disconnect from the room before leaving the Activity to
     * ensure any memory allocated to the Room resource is freed.
     */
    if (room != null && room.getState() != Room.State.DISCONNECTED) {
        room.disconnect();
        clearVideoDisplays();
    }
|

Dan di onResume()kami akan menghubungkan kembali pengguna ke ruangan jika pengguna kembali ke aktivitas kami.

Cara mengeluarkan suara ke perangkat yang berbeda

Jika pengguna memasang bug telinga atau terhubung ke headphone Bluetooth, aplikasi kita perlu mendeteksi peristiwa ini dan merutekan trek suara ke perangkat itu.

Perpustakaan AudioSwitch Twilio memungkinkan kita melakukan itu.

Perpustakaan akan secara otomatis memilih perangkat berdasarkan prioritas berikut: BluetoothHeadset -> WiredHeadset -> Earpiece -> Speakerphone.

Jika kami melakukan aplikasi konferensi video, kami lebih memilih speaker ponsel daripada lubang suara. Kita dapat mengatur urutan prioritas di konstruktor.

List<Class<? extends AudioDevice>> preferredDevices = new ArrayList<>();
preferredDevices.add(BluetoothHeadset.class);
preferredDevices.add(WiredHeadset.class);
preferredDevices.add(Speakerphone.class);
AudioSwitch audioSwitch = new AudioSwitch(context, false, focusChange -> {}, preferredDevices);
  1. buat objek audioSwitch dengan daftar prioritas
  2. daftarkan panggilan balik audioSwitch.start() sebelum panggilan aktif
  3. panggil audioSwitch.activate() saat connectToRoom
  4. panggil audioSwitch.deactive() saat terputus dari ruangan
  5. panggil audioSwitch.stop() di onDestroy()

Cara mengubah layar menjadi hitam ketika peserta lain menonaktifkan videonya

Anda mungkin memperhatikan layar Anda akan menampilkan bingkai terakhir peserta lain yang dibekukan saat dia menonaktifkan videonya. Cara yang lebih ideal untuk menangani hal ini adalah dengan menampilkan layar hitam.

Saya tidak menemukan pengaturan apa pun untuk mengubah layar menjadi hitam secara otomatis. Jadi akhirnya saya membuat tata letak batasan dengan latar belakang disetel menjadi hitam. Awalnya tandai visibilitasnya ke GONE, dan ketika peserta menonaktifkan panggilan balik video, saya mengatur tampilan kembali ke Terlihat untuk menutupi bingkai terakhir yang dibekukan.

Cara mendeteksi speaker utama

Suatu saat kita mungkin ingin menanggapi seorang pembicara. Seperti menempatkan video peserta yang berbicara saat ini ke jendela utama.

Twilio memberi kami pengaturan enableDominantSpeaker untuk mendeteksi peristiwa ini.

Lihat https://www.twilio.com/docs/video/detecting-dominant-speaker untuk mengaktifkan pengaturan ini di connectOptions.

Sekarang kita memiliki onDominantSpeakerChanged panggilan balik.

Bagaimana menghindari mendengar gema

Saya memang mengalami masalah gema audio antara Samsung dan iPhone. Seorang pengguna akan mendengar suaranya kembali dari perangkat.

Menerapkan pengaturan yang disarankan dari https://github.com/twilio/video-quickstart-android#troubleshooting-audio memperbaiki masalah ini.