Рубрики
Без рубрики

Как: Создать приложение для видеочата на Android

В этом руководстве мы создадим базовое приложение для видеочата за 10 простых шагов, используя Agora.io Видео SDK для… С тегами android, java, agora io.

В этом руководстве мы создадим базовое приложение для видеочата за 10 простых шагов, используя Agora.io Video SDK для Android.

Обновлено: 24 мая 2021 г. Этот учебник и проект были обновлены для использования версии v3.4.1 Agora Video для Android SDK

Предпосылки

Шаг 1: Agora.io Счет

Как только вы завершите процесс регистрации, вы будете перенаправлены на панель мониторинга. Откройте вкладку “Проекты” на левой панели навигации, чтобы увидеть идентификатор приложения вашего проекта по умолчанию.

Шаг 2: Создайте приложение для Android

В Android Studio создайте новое приложение с одним действием.

Шаг 3: Интеграция Agora SDK

Есть два способа добавить Agora Video SDK в ваш проект. Вы можете использовать Центр или вы можете вручную добавить SDK. Для этого проекта мы добавим проект с помощью Center.

Добавьте следующую строку в свой уровень проекта build.gradle :

allprojects {
    repositories {
        ...
        maven { url 'https://www.jitpack.io' }
        ...
    }
}

Добавьте следующую строку в файл /app/build.gradle вашего проекта:

dependencies {
    ...
    //Agora RTC SDK for video call
    implementation 'com.github.agorabuilder:native-full-sdk:3.4.1'
}

Настройка идентификатора ПРИЛОЖЕНИЯ Agora ###

Далее, пришло время добавить свой Agora.io Идентификатор приложения (см. Шаг 1) в проекта Android Strings.xml (app/src/main/res/values/Strings.xml ) .


    Agora-Android-Video-Tutorial
    <#YOUR APP ID#>

Следующим шагом будет добавление соответствующих разрешений в Manifest.xml









Последний шаг – предотвратить запутывание классов Agora, хотя это может показаться сложным, на самом деле все просто. В proguard-rules.pro файл, добавить:

-keep class io.agora.**{*;}

записка: Убедитесь, что плагин Android NDK установлен и настроен для этого проекта

Шаг 4: Настройка Просмотры

Теперь, когда у нас есть Agora.io SDK интегрирован, давайте настроим наш пользовательский интерфейс. Я пройдусь по этой части, поскольку мы будем использовать стандартные элементы пользовательского интерфейса.

В приведенном примере я решил использовать ImageView вместо Button для различных элементов пользовательского интерфейса. Либо работает, важно отметить, что существуют функции, на которые мы ссылаемся с помощью свойства onClick .

Шаг 5: Проверка разрешений

Я знаю, о чем вы, должно быть, думаете… “Разве мы уже не настроили разрешения?” Ранее мы сообщали Манифесту приложений, какие разрешения планирует использовать наше приложение, но мы все равно должны явно запросить у пользователя предоставление этих разрешений. Не волнуйтесь, это последний шаг в запуске шаблонного проекта, и он проходит безболезненно.

Во-первых, давайте объявим, какие разрешения мы хотим запросить.

// Permissions
private static final int PERMISSION_REQ_ID = 22;
private static final String[] REQUESTED_PERMISSIONS = {Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA};

Далее мы настроим пару функций, которые помогут нам. Сначала мы добавим метод, который будет запрашивать разрешения для заданной строки разрешений и кода.

public boolean checkSelfPermission(String permission, int requestCode) {
    if (ContextCompat.checkSelfPermission(this,
            permission)
            != PackageManager.PERMISSION_GRANTED) {

        ActivityCompat.requestPermissions(this,
                REQUESTED_PERMISSIONS,
                requestCode);
        return false;
    }
    return true;
}

Далее у нас есть метод обратного вызова, который будет вызван после того, как пользователь ответит на запрос запроса разрешений.

@Override
public void onRequestPermissionsResult(int requestCode,
                                       @NonNull String permissions[], @NonNull int[] grantResults) {
    Log.i(LOG_TAG, "onRequestPermissionsResult " + grantResults[0] + " " + requestCode);

    switch (requestCode) {
        case PERMISSION_REQ_ID: {
            if (grantResults[0] != PackageManager.PERMISSION_GRANTED || grantResults[1] != PackageManager.PERMISSION_GRANTED) {
                Log.i(LOG_TAG, "Need permissions " + Manifest.permission.RECORD_AUDIO + "/" + Manifest.permission.CAMERA);
                break;
            }
            // if permission granted, initialize the engine
            initAgoraEngine();
            break;
        }
    }
}

Наконец, в onCreate нашего класса мы проверяем, были ли предоставлены ваши разрешения, и если нет, то вышеуказанные методы будут обрабатывать запросы.

Шаг 6: Инициализация Agora.io SDK

Теперь, когда у нас есть свое мнение, мы готовы инициализировать Agora.io SDK, настройте профиль пользователя и установите настройки качества видео.

На предыдущем шаге вы, возможно, заметили, что есть пара мест, которые я вызываю initAgoraEngine() . Прежде чем мы сможем погрузиться в инициализацию, нам нужно убедиться, что наша активность имеет доступ к экземпляру Agora.io Двигатель Rtc .

В рамках нашей Основной деятельности Класс, нам нужно объявить свойство класса для хранения нашего экземпляра Rtc Engine.

private RtcEngine mRtcEngine;

Теперь пришло время для инициализации! После всех стандартных настроек мы, наконец, подошли к тому этапу, на котором мы можем начать играть с Agora.io двигатель!

Идите дальше и объявите свой метод initAgoraEngine внутри вашего класса. В рамках этой функции мы создадим новый экземпляр Rtc Engine , используя базовый контекст, Agora AppID ((((объявленный выше) и экземпляр RtcEngineEventHandler (мы вернемся к этому немного позже) .

private void initAgoraEngine() {
    try {
        mRtcEngine = RtcEngine.create(getBaseContext(), getString(R.string.agora_app_id), mRtcEventHandler);
    } catch (Exception e) {
        Log.e(LOG_TAG, Log.getStackTraceString(e));

        throw new RuntimeException("NEED TO check rtc sdk init fatal error\n" + Log.getStackTraceString(e));
    }
    setupSession();
}

Как только у нас появится наш новый экземпляр, пришло время настроить сеанс нашего пользователя. Здесь мы можем настроить профиль канала на Общение, так как это видеочат, а не трансляция. Здесь же мы настраиваем настройки нашего видеокодера.

private void setupSession() {
    mRtcEngine.setChannelProfile(Constants.CHANNEL_PROFILE_COMMUNICATION);

    mRtcEngine.enableVideo();

    mRtcEngine.setVideoEncoderConfiguration(new VideoEncoderConfiguration(VideoEncoderConfiguration.VD_1920x1080, VideoEncoderConfiguration.FRAME_RATE.FRAME_RATE_FPS_30,
            VideoEncoderConfiguration.STANDARD_BITRATE,
            VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_FIXED_PORTRAIT));
}

Шаг 7: Подключение видеопотоков

Прежде чем мы сможем присоединиться к вызову просмотра, нам нужно иметь возможность представить локальный видеопоток пользователю с помощью элементов пользовательского интерфейса, которые мы настроили ранее (Шаг 4) .

В первой строке мы получаем ссылку на элемент пользовательского интерфейса, который будет выступать в качестве нашего родительского представления для нашего видеопотока. Второй шаг заключается в использовании Rtc Engine для создания SurfaceView , который будет отображать поток с фронтальной камеры, мы также устанавливаем новую VideoSurface для отображения поверх ее родительского вида. Следующим шагом будет добавление Video Surface в качестве подвида элемента пользовательского интерфейса. Наконец, мы передаем Video Surface движку как часть объекта Video Canvas . Мы оставляем параметр uid пустым, чтобы SDK мог обрабатывать создание динамического идентификатора для каждого пользователя.

private void setupLocalVideoFeed() {
  FrameLayout videoContainer = findViewById(R.id.floating_video_container);
  SurfaceView videoSurface = RtcEngine.CreateRendererView(getBaseContext()); 
  videoSurface.setZOrderMediaOverlay(true);
  videoContainer.addView(videoSurface);
  mRtcEngine.setupLocalVideo(new VideoCanvas(videoSurface, VideoCanvas.RENDER_MODE_FIT, 0));
}

Теперь, когда у нас есть настройка локальной видеопотока, нам нужно использовать аналогичную функцию для подключения нашего удаленного видеопотока.

private void setupRemoteVideoStream(int uid) {
  FrameLayout videoContainer = findViewById(R.id.bg_video_container);
  SurfaceView videoSurface = RtcEngine.CreateRendererView(getBaseContext());
  videoContainer.addView(videoSurface);
  mRtcEngine.setupRemoteVideo(new VideoCanvas(videoSurface, VideoCanvas.RENDER_MODE_FIT, uid));
  mRtcEngine.setRemoteSubscribeFallbackOption(io.agora.rtc.Constants.STREAM_FALLBACK_OPTION_AUDIO_ONLY);
}

Основное отличие удаленного видео от локального заключается в параметре user id , который передается движку как часть объекта VideoCanvas , который передается движку. Последняя строка устанавливает резервную опцию на случай ухудшения качества видео, движок вернется только к аудио.

Шаг 8: Настройка обработчика событий SDK

Ранее я сделал ссылку на обработчик событий Rtc Engine , и теперь пришло время объявить его как свойство нашего MainActivity Класс. Движок будет вызывать эти методы из обработчика событий Rtc Engine/| .

// Handle SDK Events
private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
    @Override
    public void onUserJoined(final int uid, int elapsed) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // set first remote user to the main bg video container
                setupRemoteVideoStream(uid);
            }
        });
    }

    // remote user has left channel
    @Override
    public void onUserOffline(int uid, int reason) { // Tutorial Step 7
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                onRemoteUserLeft();
            }
        });
    }

    // remote user has toggled their video
     @Override
     public void onRemoteVideoStateChanged(final int uid, final int state, int reason, int elapsed) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                onRemoteUserVideoToggle(uid, state);
            }
        });
    }
};

Каждое событие запускает несколько довольно простых функций, включая ту, которую мы написали на предыдущем шаге. В интересах сохранения этой краткости я приведу приведенный ниже код, но не буду давать подробную разбивку.

private void onRemoteUserVideoToggle(int uid, int state) {
    FrameLayout videoContainer = findViewById(R.id.bg_video_container);

    SurfaceView videoSurface = (SurfaceView) videoContainer.getChildAt(0);
    videoSurface.setVisibility(state == 0 ? View.GONE : View.VISIBLE);

    // add an icon to let the other user know remote video has been disabled
    if(state == 0){
        ImageView noCamera = new ImageView(this);
        noCamera.setImageResource(R.drawable.video_disabled);
        videoContainer.addView(noCamera);
    } else {
        ImageView noCamera = (ImageView) videoContainer.getChildAt(1);
        if(noCamera != null) {
            videoContainer.removeView(noCamera);
        }
    }
}

private void onRemoteUserLeft() {
    removeVideo(R.id.bg_video_container);
}

private void removeVideo(int containerID) {
    FrameLayout videoContainer = findViewById(containerID);
    videoContainer.removeAllViews();
}

Шаг 9: Присоединение к каналам и выход из них

Я знаю, о чем ты думаешь, ШАГ 9?!! Не волнуйтесь, следующие два шага действительно просты. Давайте начнем с присоединения к вызову…

Ниже вы можете видеть из первой строки, Agora SDK упрощает это, движок вызывает join Channel, передавая название канала, за которым следует вызов для настройки нашего локального видеопотока. (Шаг 7)

public void onjoinChannelClicked(View view) {
    mRtcEngine.joinChannel(null, "test-channel", "Extra Optional Data", 0);
    setupLocalVideoFeed();
    findViewById(R.id.joinBtn).setVisibility(View.GONE); // set the join button hidden
    findViewById(R.id.audioBtn).setVisibility(View.VISIBLE); // set the audio button hidden
    findViewById(R.id.leaveBtn).setVisibility(View.VISIBLE); // set the leave button hidden
    findViewById(R.id.videoBtn).setVisibility(View.VISIBLE); // set the video button hidden
}

Покинуть канал еще проще, движок вызывает команду покинуть канал. Выше вы заметите, что есть несколько строк для удаления вложенных просмотров видеопотока из каждого элемента пользовательского интерфейса.

public void onLeaveChannelClicked(View view) {
    leaveChannel();
    removeVideo(R.id.floating_video_container);
    removeVideo(R.id.bg_video_container);
    findViewById(R.id.joinBtn).setVisibility(View.VISIBLE); // set the join button visible
    findViewById(R.id.audioBtn).setVisibility(View.GONE); // set the audio button hidden
    findViewById(R.id.leaveBtn).setVisibility(View.GONE); // set the leave button hidden
    findViewById(R.id.videoBtn).setVisibility(View.GONE); // set the video button hidden
}

private void leaveChannel() {
    mRtcEngine.leaveChannel();
}

private void removeVideo(int containerID) {
    FrameLayout videoContainer = findViewById(containerID);
    videoContainer.removeAllViews();
}

Шаг 10: Добавление функциональности пользовательского интерфейса

Последние оставшиеся части связаны с подключением элементов пользовательского интерфейса для переключения микрофона и видеопотока на локальном устройстве. Давайте начнем с переключения звука.

Сначала мы получаем ссылку на нашу кнопку, а затем проверяем, была ли она включена/выключена с помощью IsSelected() . Как только мы обновили состояние элемента пользовательского интерфейса, мы передаем обновленное состояние кнопки движку.

public void onAudioMuteClicked(View view) {
    ImageView btn = (ImageView) view;
    if (btn.isSelected()) {
        btn.setSelected(false);
        btn.setImageResource(R.drawable.audio_toggle_btn);
    } else {
        btn.setSelected(true);
        btn.setImageResource(R.drawable.audio_toggle_active_btn);
    }

    mRtcEngine.muteLocalAudioStream(btn.isSelected());
}

Переходя к переключению видео, как и в случае с переключением звука, мы проверяем/обновляем состояние кнопки с помощью Выбрано() , а затем передаем это движку. Чтобы обеспечить лучшее визуальное представление отключаемого видео, мы скрываем/показываем Поверхность видео .

public void onVideoMuteClicked(View view) {
    ImageView btn = (ImageView) view;
    if (btn.isSelected()) {
        btn.setSelected(false);
        btn.setImageResource(R.drawable.video_toggle_btn);
    } else {
        btn.setSelected(true);
        btn.setImageResource(R.drawable.video_toggle_active_btn);
    }

    mRtcEngine.muteLocalVideoStream(btn.isSelected());

    FrameLayout container = findViewById(R.id.floating_video_container);
    container.setVisibility(btn.isSelected() ? View.GONE : View.VISIBLE);
    SurfaceView videoSurface = (SurfaceView) container.getChildAt(0);
    videoSurface.setZOrderMediaOverlay(!btn.isSelected());
    videoSurface.setVisibility(btn.isSelected() ? View.GONE : View.VISIBLE);
}

Я надеюсь, вам понравилось читать вместе и работать вместе над созданием приложения для видеочата 1 к 1 для Android с использованием Agora.io Видео SDK .

Оригинал: “https://dev.to/hermes_f/how-to-build-a-video-chat-app-on-android-45dn”