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

Как: Создать приложение удаленной помощи с дополненной реальностью в Android

Это могло случиться со многими из нас в какой-то момент: вы подключили этот фен или этот обогреватель… Помеченные как java, дополненная реальность, arcore, agoraio.

Это могло случиться со многими из нас в какой-то момент: вы включили фен или обогреватель, и внезапно весь ваш свет погас, а телевизор стал черным.

Теперь вам придется в отчаянии позвонить в службу поддержки вашего поставщика услуг. Вы объяснили, что произошло, и они сказали, что вам, возможно, просто нужно включить воздушный выключатель. Однако, когда вы открываете электрическую панель, вы задаетесь вопросом: какой из них является воздушным выключателем? После 20-минутного разговора с представителем службы поддержки клиентов, пытающимся найти этот переключатель, вы обнаруживаете, что у вас дома его вообще нет.

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

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

  1. Базовое и промежуточное понимание Java и Android SDK
  2. Базовое понимание концепций ARCore и дополненной реальности
  3. Agora.io Учетная запись разработчика
  4. Аппаратное обеспечение: 2 устройства Android, работающие под управлением Android API уровня 24 или выше и первоначально поставляемые с Google Play Store

* Вы можете проверить подробные требования к устройству здесь .

Пожалуйста, обратите внимание: Хотя для продолжения не требуется никаких знаний Java/Android, некоторые базовые концепции Java/Hardcore не будут объяснены на этом пути.

В этом руководстве мы собираемся создать приложение поддержки клиентов с поддержкой AR. Один пользователь создаст канал, введя имя канала, присоединившись к каналу в качестве стримера (люди, которым нужна поддержка). В то время как другой пользователь может присоединиться к тому же каналу, введя то же название канала, что и участник аудитории (служба поддержки клиентов). Когда оба пользователя будут подключены к каналам, стример будет транслировать их заднюю камеру аудитории. Аудитория может рисовать на своем собственном устройстве и получать сенсорный ввод в дополненной реальности в мире стримера!

Вот все шаги, которые мы рассмотрим в этой статье:

  1. Создать Новый Проект
  2. Создать пользовательский интерфейс
  3. Включить Хардкор
  4. Включить Видеовызов Стримеров
  5. Включить Видеозвонок аудитории
  6. Функция Удаленной Помощи
  7. Сборка И тестирование на устройстве

Вы можете найти мой Github демонстрационное приложение в качестве ссылки для этой статьи.

Для начала давайте откроем Android studio и создадим новый пустой проект.

  1. Откройте Android Studio и нажмите Начните новый проект Android Studio .
  2. На панели Выберите свой проект выберите Телефон и планшет > Пустое действие и нажмите Следующий .
  3. Нажмите Готово . Следуйте инструкциям на экране, если вам нужно установить какие-либо плагины.

Интеграция SDK

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

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

    //ARCore 
    implementation 'com.google.ar:core:1.0.0'
    implementation 'de.javagl:obj:0.2.1'
    implementation 'com.google.android.material:material:1.1.0'
    implementation 'com.android.support:appcompat-v7:27.0.2'
    implementation 'com.android.support:design:27.0.2'

    //Video 
    implementation 'io.agora.rtc:full-sdk:2.9.4'
}

Синхронизируйте проект после внесения изменений. Добавьте следующие разрешения для проекта в /app/src/main/AndroidManifest.xml файл:

    
    
    
    
    
    
    

Чтобы запустить ARCore, нам также необходимо добавить следующее в AndroidManifest.xml файл. Это указывает на то, что для этого приложения требуется ARCore.




Давайте создадим компонент пользовательского интерфейса для обоих пользователей. Для пользователя, который делится своим миром с AR, мы будем называть его “стример”. Для других пользователей, которые присоединяются к каналу за поддержкой, мы будем называть их “аудиторией”. Ниже приведен пример пользовательского интерфейса, который я буду использовать:

Пожалуйста, обратите внимание: Вы можете найти xml-файлы для пользовательского интерфейса здесь .

Основное различие между пользовательским интерфейсом стримера и пользовательским интерфейсом аудитории заключается в том, что пользовательский интерфейс стримера использует android.opengl. GLSurfaceView для визуализации вида камеры AR, в то время как пользовательский интерфейс аудитории использует RelativeLayout для визуализации видео, поступающего со стримера.

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

Мы также создадим экран, на котором пользователь сможет ввести название канала и присоединиться к каналу в качестве стримера или аудитории.

Пожалуйста, обратите внимание: Вы можете найти xml-файлы для JoinChannelUI здесь .

Логика пользовательского интерфейса канала очень проста. Если пользователь нажмет кнопку СОЗДАТЬ, он перейдет на страницу активности streamer , которая обрабатывает логику потоковой передачи. Если пользователь нажмет кнопку ПРИСОЕДИНИТЬСЯ, он перейдет на страницу активности аудитория , которая обрабатывает логику взаимодействия с аудиторией. Теперь нам нужно определить логику для обоих видов деятельности.

Настройка хардкора в проекте не так сложна, как думает большинство людей. В методе onResume() активности стримера нам нужно создать экземпляр сеанса . Экземпляр сеанса предназначен для управления состоянием системы AR и управления жизненным циклом. Мы можем использовать его для получения кадров, которые позволяют получить доступ к изображениям с камеры. Однако перед этим мы должны проверить, установлен ли ARCore.

@Override
protected void onResume() {
    super.onResume();

    if (mSession == null) {
        String message = null;
        try {
            switch (ArCoreApk.getInstance().requestInstall(this, !installRequested)) {
                case INSTALL_REQUESTED:
                    installRequested = true;
                    return;
                case INSTALLED:
                    break;
            }

            // ARCore requires camera permissions to operate. If we did not yet obtain runtime permission on Android M and above, now is a good time to ask the user for it.
            if (!CameraPermissionHelper.hasCameraPermission(this)) {
               CameraPermissionHelper.requestCameraPermission(this);
                return;
            }

            mSession = new Session(this);
        } catch (Exception e) {
            ...
        } 
        // Create default config and check if supported.
        Config config = new Config(mSession);
        if (!mSession.isSupported(config)) {
            showSnackbarMessage("This device does not support AR", true);
        }
        ...
}

Реализует GLSurfaceView. Средство визуализации

Мы будем использовать GLSurfaceView для визуализации камеры AR. Для этого в деятельности стримера должна быть реализована функция GLSurfaceView. Средство визуализации . Есть три функции, которые необходимо переопределить: onSurfaceCreated , На поверхности изменилось и Рамка для рисования .

Переопределение onSurfaceCreated

В методе onSurfaceCreated , который обычно вызывается в начале рендеринга, нам нужно будет выполнить некоторые инициализации для AR-сцены.

  1. Создайте экземпляр средства визуализации фона и передайте его идентификатор камере сеанса.
  2. Инициализируйте 3D-объект. Этот 3D-объект будет отрисован в streamers AR world позже.
  3. Инициализируйте визуализацию обнаружения плоскости.
  4. Инициализируйте облако точек.
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    GLES20.glClearColor(0.1f,0.1f,0.1f,1.0f);

    // Create the texture and pass it to ARCore session to be filled during update().
    mBackgroundRenderer.createOnGlThread(/*context=*/ this);
    if (mSession != null) {
  mSession.setCameraTextureName(mBackgroundRenderer.getTextureId());
    }
    // Prepare the other rendering objects.
    try {
        mVirtualObject.createOnGlThread(/*context=*/this, "andy.obj", "andy.png");
        mVirtualObject.setMaterialProperties(0.0f, 3.5f, 1.0f, 6.0f);
        mVirtualObjectShadow.createOnGlThread(/*context=*/this,
                "andy_shadow.obj", "andy_shadow.png");
        mVirtualObjectShadow.setBlendMode(ObjectRenderer.BlendMode.Shadow);
        mVirtualObjectShadow.setMaterialProperties(1.0f, 0.0f, 0.0f, 1.0f);
    } catch (IOException e) {
        ...
    }
    try {
        mPlaneRenderer.createOnGlThread(/*context=*/this, "trigrid.png");
    } catch (IOException e) {
        ...
    }
    mPointCloud.createOnGlThread(/*context=*/this);
}

Переопределение onSurfaceChanged

В методе onSurfaceChanged , который вызывается после создания поверхности и при изменении размера поверхности, мы установим наш видовой экран.

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
    ...
    GLES20.glViewport(0, 0, width, height);
}

Переопределение onDrawFrame

В методе onDrawFrame , который вызывается для рисования текущего кадра, нам нужно реализовать логику рендеринга для GLSurfaceView.

  1. Очистить экран.
  2. Получите последний кадр из сеанса.
  3. Фиксируйте нажатия пользователя и проверяйте, были ли найдены какие-либо плоскости в сцене. Если это так, создайте якорь в этой точке.
  4. Нарисуйте фон.
  5. Нарисуйте облако точек.
  6. Повторите все якоря и нарисуйте 3D-объект на каждом из якорей.
@Override
public void onDrawFrame(GL10 gl) {
    // Clear screen to notify driver it should not load any pixels from previous frame.
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    ...

    try {
        // Obtain the current frame from ARSession. When the configuration is set to
        // UpdateMode.BLOCKING (it is by default), this will throttle the rendering to the camera framerate.
        Frame frame = mSession.update();
        Camera camera = frame.getCamera();

        // Handle taps. Handling only one tap per frame, as taps are usually low frequency
        // compared to frame rate.
        MotionEvent tap = queuedSingleTaps.poll();
        if (tap != null && camera.getTrackingState() == TrackingState.TRACKING) {
            for (HitResult hit : frame.hitTest(tap)) {
                // Check if any plane was hit, and if it was hit inside the plane polygon
                Trackable trackable = hit.getTrackable();
                // Creates an anchor if a plane or an oriented point was hit.
                if ((trackable instanceof Plane && ((Plane) trackable).isPoseInPolygon(hit.getHitPose()))
                        || (trackable instanceof Point
                        && ((Point) trackable).getOrientationMode()
                        == Point.OrientationMode.ESTIMATED_SURFACE_NORMAL)) {
                    // Hits are sorted by depth. Consider only closest hit on a plane or oriented point.
                    // Cap the number of objects created. This avoids overloading both the
                    // rendering system and ARCore.
                    if (anchors.size() >= 250) {
                        anchors.get(0).detach();
                        anchors.remove(0);
                    }
                    // Adding an Anchor tells ARCore that it should track this position in
                    // space. This anchor is created on the Plane to place the 3D model
                    // in the correct position relative both to the world and to the plane.
                    anchors.add(hit.createAnchor());
                    break;
                }
            }
        }

        // Draw background.
        mBackgroundRenderer.draw(frame);

        ...
        if (isShowPointCloud()) {
            // Visualize tracked points.
            PointCloud pointCloud = frame.acquirePointCloud();
            mPointCloud.update(pointCloud);
            mPointCloud.draw(viewmtx, projmtx);

            // Application is responsible for releasing the point cloud resources after
            // using it.
            pointCloud.release();
        }

        ...

        if (isShowPlane()) {
            // Visualize planes.
            mPlaneRenderer.drawPlanes(
                    mSession.getAllTrackables(Plane.class), camera.getDisplayOrientedPose(), projmtx);
        }

        // Visualize anchors created by touch.
        float scaleFactor = 1.0f;

        for (Anchor anchor : anchors) {
            if (anchor.getTrackingState() != TrackingState.TRACKING) {
                continue;
            }
            // Get the current pose of an Anchor in world space. The Anchor pose is updated
            // during calls to session.update() as ARCore refines its estimate of the world.
            anchor.getPose().toMatrix(mAnchorMatrix, 0);


            // Update and draw the model and its shadow.
            mVirtualObject.updateModelMatrix(mAnchorMatrix, mScaleFactor);
            mVirtualObjectShadow.updateModelMatrix(mAnchorMatrix, scaleFactor);
            mVirtualObject.draw(viewmtx, projmtx, lightIntensity);
            mVirtualObjectShadow.draw(viewmtx, projmtx, lightIntensity);
        }
    } catch (Throwable t) {
        ...
    }
}

Пожалуйста, обратите внимание: Некоторые концепции здесь не объясняются. Проверьте Код Github для большего понимания.

Настройка видеозвонка со стримера

В методе onCreate() в AgoraARStreamerActivity давайте сделаем следующее:

  1. Инициализировать GLSurfaceView OnTouchListener
  2. Инициализировать механизм Agora Rtc
  3. Настройка пользовательского источника видео
  4. Присоединиться к каналу

1. Инициализировать GLSurfaceView OnTouchListener

Установка OnTouchListener для GLSurfaceView позволяет нам фиксировать положение касания и устанавливать привязку AR в этом положении.

mGestureDetector = new GestureDetector(this,
        new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                onSingleTap(e);
                return true;
            }

            @Override
            public boolean onDown(MotionEvent e) {
                return true;
            }
        });

mSurfaceView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return mGestureDetector.onTouchEvent(event);
    }
});

Когда детектор жестов обнаружит одно касание, он запустит метод onSingleTap. В этом методе мы добавляем этот кран в очередь одного крана.

private void onSingleTap(MotionEvent e) {
    queuedSingleTaps.offer(e);
}

В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе onDrawFrame ? В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе onDrawFrame ? Мы опросили нажатия пользователя из

2. В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе || onDrawFrame ||? Мы опросили нажатия пользователя из || Одиночных нажатий в очереди, где тета Инициализирует движок Agora Rtc, и они добавляются в очередь.

В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе onDrawFrame ? Мы опросили нажатия пользователя из

mRtcEngine = RtcEngine.create(this, getString(R.string.private_broadcasting_app_id), mRtcEventHandler);

В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе onDrawFrame ? Мы опросили нажатия пользователя из

  1. В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе onDrawFrame
  2. ? Мы опросили нажатия пользователя из Одиночных нажатий в очереди, где тета Инициализирует движок Agora Rtc, и они добавляются в очередь. Чтобы инициализировать движок видео Agora, просто вызовите Rtc Engine.create(контекст, идентификатор приложения, обработчик событий Rtc)
  3. для создания RtcEngine для создания проекта Agora
  4. в консоли Agora. Чтобы получить

В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе onDrawFrame ? Мы опросили нажатия пользователя из

private IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
    @Override
    public void onJoinChannelSuccess(final String channel, int uid, int elapsed) {
        //when local user joined the channel
        ...
    }

    @Override
    public void onRemoteVideoStateChanged(final int uid, int state, int reason, int elapsed) {
        super.onRemoteVideoStateChanged(uid, state, reason, elapsed);
        //when remote user join the channel
        if (state == Constants.REMOTE_VIDEO_STATE_STARTING) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    addRemoteRender(uid);
                }
            });
        }
    }

    @Override
    public void onUserOffline(int uid, int reason) {
        //when remote user leave the channel
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                removeRemoteRender();
            }
        });
    }

    @Override
    public void onStreamMessage(int uid, int streamId, byte[] data) {
        //when received the remote user's stream message data
        ...
    }
};

В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе onDrawFrame ? Мы опросили нажатия пользователя из

В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе || onDrawFrame ||? Мы опросили нажатия пользователя из || Одиночных нажатий в очереди, где тета Инициализирует движок Agora Rtc, и они добавляются в очередь. Чтобы инициализировать движок видео Agora, просто вызовите || Rtc Engine.create(контекст, идентификатор приложения, обработчик событий Rtc) || для создания RtcEngine для создания проекта Agora || в консоли Agora. Для того, чтобы перейти на вкладку || Управление проектами || слева, нажмите “Создать” и следуйте инструкциям на экране, чтобы установить Prпожалуйста, обратите внимание: Часть логики отображения просмотров видео на экране скрыта. Для получения дополнительных обработчиков событий RtcEngine, которые вы можете использовать, ознакомьтесь с документом || Agora Rtc API. Проверьте комментарии в верхней части каждого метода обработки событий, чтобы лучше их понять. Давайте реализуем это с помощью некоторых базовых обработчиков событий, необходимых для этого приложения. || mRtcEventHandler || – это обработчик для управления различными событиями, происходящими с механизмом Rtc. На странице Управления проектами найдите идентификатор приложения вашего проекта. введите имя, выберите механизм аутентификации и нажмите “Отправить”. панель управления. он || Идентификатор приложения || в параметре, выполните следующие действия: tance. В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе || onDrawFrame ||? Мы опросили нажатия пользователя из || Одиночных нажатий в очереди, где тета Инициализирует движок Agora Rtc, и они добавляются в очередь. Чтобы инициализировать движок видео Agora, просто вызовите || Rtc Engine.create(контекст, идентификатор приложения, обработчик событий Rtc) || для создания RtcEngine для создания проекта Agora || в консоли Agora. Для того, чтобы перейти на вкладку || Управление проектами || слева, нажмите “Создать” и следуйте инструкциям на экране, чтобы установить Pryвы можете проверить, пожалуйста, обратите внимание: Часть логики отображения просмотров видео на экране скрыта. Для получения дополнительных обработчиков событий RtcEngine, которые вы можете использовать, ознакомьтесь с документом || Agora Rtc API. Проверьте комментарии в верхней части каждого метода обработки событий, чтобы лучше их понять. Давайте реализуем это с помощью некоторых базовых обработчиков событий, необходимых для этого приложения. || mRtcEventHandler || – это обработчик для управления различными событиями, происходящими с механизмом Rtc. На странице Управления проектами найдите идентификатор приложения вашего проекта. введите имя, выберите механизм аутентификации и нажмите “Отправить”. панель управления. он || Идентификатор приложения || в параметре, выполните следующие действия: tance. В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе || onDrawFrame ||? Мы опросили нажатия пользователя из || Одиночных нажатий в очереди, где тета Инициализирует движок Agora Rtc, и они добавляются в очередь. Чтобы инициализировать движок видео Agora, просто вызовите || Rtc Engine.create(контекст, идентификатор приложения, обработчик событий Rtc) || для создания RtcEngine для создания проекта Agora || в консоли Agora. Для того, чтобы перейти на вкладку || Управление проектами || слева, нажмите “Создать” и следуйте инструкциям на экране, чтобы установить демонстрационное приложение prGithub. Вы можете проверить, пожалуйста, обратите внимание: Часть логики для отображения просмотров видео на экране скрыта. Для получения дополнительных обработчиков событий RtcEngine, которые вы можете использовать, ознакомьтесь с документом || Agora Rtc API. Проверьте комментарии в верхней части каждого метода обработки событий, чтобы лучше их понять. Давайте реализуем это с помощью некоторых базовых обработчиков событий, необходимых для этого приложения. || mRtcEventHandler || – это обработчик для управления различными событиями, происходящими с механизмом Rtc. На странице Управления проектами найдите идентификатор приложения вашего проекта. введите имя, выберите механизм аутентификации и нажмите “Отправить”. панель управления. он || Идентификатор приложения || в параметре, выполните следующие действия: tance. В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе || onDrawFrame ||? Мы опросили нажатия пользователя из || Одиночных нажатий в очереди, где тета Инициализирует движок Agora Rtc, и они добавляются в очередь. Чтобы инициализировать движок видео Agora, просто вызовите || Rtc Engine.create(контекст, идентификатор приложения, обработчик событий Rtc) || для создания RtcEngine для создания проекта Agora || в консоли Agora. Для того, чтобы перейти на вкладку || Управление проектами || слева, нажмите “Создать” и следуйте инструкциям на экране, чтобы установить prдля лучшего понимания того, как динамически отображать и удалять просмотры видео на экране. Демонстрационное приложение Github Вы можете проверить, Пожалуйста, обратите внимание: Часть логики отображения просмотров видео на экране скрыта. Для получения дополнительных обработчиков событий RtcEngine, которые вы можете использовать, ознакомьтесь с документом || Agora Rtc API. Проверьте комментарии в верхней части каждого метода обработки событий, чтобы лучше их понять. Давайте реализуем это с помощью некоторых базовых обработчиков событий, необходимых для этого приложения. || mRtcEventHandler || – это обработчик для управления различными событиями, происходящими с механизмом Rtc. На странице Управления проектами найдите идентификатор приложения вашего проекта. введите имя, выберите механизм аутентификации и нажмите “Отправить”. панель управления. он || Идентификатор приложения || в параметре, выполните следующие действия: tance.

3. В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе || onDrawFrame ||? Мы опросили нажатия пользователя из || Одиночных нажатий в очереди, где тета Инициализирует движок Agora Rtc, и они добавляются в очередь. Чтобы инициализировать движок видео Agora, просто вызовите || Rtc Engine.create(контекст, идентификатор приложения, обработчик событий Rtc) || для создания RtcEngine для создания проекта Agora || в консоли Agora. Для того, чтобы перейти на вкладку || Управление проектами || слева, нажмите “Создать” и следуйте инструкциям на экране, чтобы настроить пользовательский источник видео для лучшего понимания того, как динамически отображать и удалять просмотры видео на экране. Демонстрационное приложение Github Вы можете проверить, Пожалуйста, обратите внимание: Часть логики отображения просмотров видео на экране скрыта. Для получения дополнительных обработчиков событий RtcEngine, которые вы можете использовать, ознакомьтесь с документом || Agora Rtc API. Проверьте комментарии в верхней части каждого метода обработки событий, чтобы лучше их понять. Давайте реализуем это с помощью некоторых базовых обработчиков событий, необходимых для этого приложения. || mRtcEventHandler || – это обработчик для управления различными событиями, происходящими с механизмом Rtc. На странице Управления проектами найдите идентификатор приложения вашего проекта. введите имя, выберите механизм аутентификации и нажмите “Отправить”. панель управления. он || Идентификатор приложения || в параметре, выполните следующие действия: tance.

В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе || onDrawFrame ||? Мы опросили нажатия пользователя из || Одиночных нажатий в очереди, где тета Инициализирует движок Agora Rtc, и они добавляются в очередь. Чтобы инициализировать движок видео Agora, просто вызовите || Rtc Engine.create(контекст, идентификатор приложения, обработчик событий Rtc) || для создания RtcEngine для создания проекта Agora || в консоли Agora. Для того, чтобы перейти на вкладку || Управление проектами || слева, нажмите “Создать” и следуйте инструкциям на экране, чтобы настроить наше приложение, мы хотим, чтобы стример отправлял свой AR-мир аудитории. Настройте пользовательский источник видео для лучшего понимания того, как динамически отображать и удалять просмотры видео на экране. Демонстрационное приложение Github Вы можете проверить, Пожалуйста, обратите внимание: Часть логики отображения просмотров видео на экране скрыта. Для получения дополнительных обработчиков событий RtcEngine, которые вы можете использовать, ознакомьтесь с документом || Agora Rtc API. Проверьте комментарии в верхней части каждого метода обработки событий, чтобы лучше их понять. Давайте реализуем это с помощью некоторых базовых обработчиков событий, необходимых для этого приложения. || mRtcEventHandler || – это обработчик для управления различными событиями, происходящими с механизмом Rtc. На странице Управления проектами найдите идентификатор приложения вашего проекта. введите имя, выберите механизм аутентификации и нажмите “Отправить”. панель управления. он || Идентификатор приложения || в параметре, выполните следующие действия: tance. В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе || onDrawFrame ||? Мы опросили нажатия пользователя из || Одиночных нажатий в очереди, где тета Инициализирует движок Agora Rtc, и они добавляются в очередь. Чтобы инициализировать движок видео Agora, просто вызовите || Rtc Engine.create(контекст, идентификатор приложения, обработчик событий Rtc) || для создания RtcEngine для создания проекта Agora || в консоли Agora. Для того, чтобы перейти на вкладку || Управление проектами || слева, нажмите “Создать” и следуйте инструкциям на экране, чтобы установить prSo, чтобы видео, которое они отправляют, было из пользовательского источника видео вместо общего видеопотока камеры. В нашем приложении мы хотим позволить стримеру отправлять свой AR-мир аудитории. Настройте пользовательский источник видео для лучшего понимания того, как динамически отображать и удалять просмотры видео на экране. Демонстрационное приложение Github Вы можете проверить, Пожалуйста, обратите внимание: Часть логики отображения просмотров видео на экране скрыта. Для получения дополнительных обработчиков событий RtcEngine, которые вы можете использовать, ознакомьтесь с документом || Agora Rtc API. Проверьте комментарии в верхней части каждого метода обработки событий, чтобы лучше их понять. Давайте реализуем это с помощью некоторых базовых обработчиков событий, необходимых для этого приложения. || mRtcEventHandler || – это обработчик для управления различными событиями, происходящими с механизмом Rtc. На странице Управления проектами найдите идентификатор приложения вашего проекта. введите имя, выберите механизм аутентификации и нажмите “Отправить”. панель управления. он || Идентификатор приложения || в параметре, выполните следующие действия: tance. В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе || onDrawFrame ||? Мы опросили нажатия пользователя из || Одиночных нажатий в очереди, где тета Инициализирует движок Agora Rtc, и они добавляются в очередь. Чтобы инициализировать движок видео Agora, просто вызовите || Rtc Engine.create(контекст, идентификатор приложения, обработчик событий Rtc) || для создания RtcEngine для создания проекта Agora || в консоли Agora. Для того, чтобы перейти на вкладку || Управление проектами || слева, нажмите “Создать” и следуйте инструкциям на экране, чтобы установить prLuckily, Agora Video SDK предоставляет метод API для отправки пользовательских видеоисточников. Таким образом, видео, которое они отправляют, поступает из пользовательского источника видео, а не из общего видеопотока камеры. В нашем приложении мы хотим позволить стримеру отправлять свой AR-мир аудитории. Настройте пользовательский источник видео для лучшего понимания того, как динамически отображать и удалять просмотры видео на экране. Демонстрационное приложение Github Вы можете проверить, Пожалуйста, обратите внимание: Часть логики отображения просмотров видео на экране скрыта. Для получения дополнительных обработчиков событий RtcEngine, которые вы можете использовать, ознакомьтесь с документом || Agora Rtc API. Проверьте комментарии в верхней части каждого метода обработки событий, чтобы лучше их понять. Давайте реализуем это с помощью некоторых базовых обработчиков событий, необходимых для этого приложения. || mRtcEventHandler || – это обработчик для управления различными событиями, происходящими с механизмом Rtc. На странице Управления проектами найдите идентификатор приложения вашего проекта. введите имя, выберите механизм аутентификации и нажмите “Отправить”. панель управления. он || Идентификатор приложения || в параметре, выполните следующие действия: tance.

В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе || onDrawFrame ||? Мы опросили нажатия пользователя из || Одиночных нажатий в очереди, где тета Инициализирует движок Agora Rtc, и они добавляются в очередь. Чтобы инициализировать движок видео Agora, просто вызовите || Rtc Engine.create(контекст, идентификатор приложения, обработчик событий Rtc) || для создания RtcEngine для создания проекта Agora || в консоли Agora. Для того, чтобы перейти на вкладку || Управление проектами || слева, нажмите “Создать” и следуйте инструкциям на экране, чтобы установить prcreate класс под названием AgoraVideoSource, который реализует интерфейс Ivideosource. К счастью, Agora Video SDK предоставляет API-метод для отправки пользовательских видеоисточников. Таким образом, видео, которое они отправляют, поступает из пользовательского источника видео, а не из общего видеопотока камеры. В нашем приложении мы хотим позволить стримеру отправлять свой AR-мир аудитории. Настройте пользовательский источник видео для лучшего понимания того, как динамически отображать и удалять просмотры видео на экране. Демонстрационное приложение Github Вы можете проверить, Пожалуйста, обратите внимание: Часть логики отображения просмотров видео на экране скрыта. Для получения дополнительных обработчиков событий RtcEngine, которые вы можете использовать, ознакомьтесь с документом || Agora Rtc API. Проверьте комментарии в верхней части каждого метода обработки событий, чтобы лучше их понять. Давайте реализуем это с помощью некоторых базовых обработчиков событий, необходимых для этого приложения. || mRtcEventHandler || – это обработчик для управления различными событиями, происходящими с механизмом Rtc. На странице Управления проектами найдите идентификатор приложения вашего проекта. введите имя, выберите механизм аутентификации и нажмите “Отправить”. панель управления. он || Идентификатор приложения || в параметре, выполните следующие действия: tance. В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе || onDrawFrame ||? Мы опросили нажатия пользователя из || Одиночных нажатий в очереди, где тета Инициализирует движок Agora Rtc, и они добавляются в очередь. Чтобы инициализировать движок видео Agora, просто вызовите || Rtc Engine.create(контекст, идентификатор приложения, обработчик событий Rtc) || для создания RtcEngine для создания проекта Agora || в консоли Agora. Для того, чтобы перейти на вкладку || Управление проектами || слева, нажмите “Создать” и следуйте инструкциям на экране, чтобы установить Prинтерфейс IVideoSource определяет набор протоколов для реализации пользовательского источника видео и передачи его в базовый медиа-движок для замены источника видео по умолчанию. Создайте класс под названием AgoraVideoSource, который реализует интерфейс ivideosource. К счастью, Agora Video SDK предоставляет API-метод для отправки пользовательских видеоисточников. Таким образом, видео, которое они отправляют, поступает из пользовательского источника видео, а не из общего видеопотока камеры. В нашем приложении мы хотим позволить стримеру отправлять свой AR-мир аудитории. Настройте пользовательский источник видео для лучшего понимания того, как динамически отображать и удалять просмотры видео на экране. Демонстрационное приложение Github Вы можете проверить, Пожалуйста, обратите внимание: Часть логики отображения просмотров видео на экране скрыта. Для получения дополнительных обработчиков событий RtcEngine, которые вы можете использовать, ознакомьтесь с документом || Agora Rtc API. Проверьте комментарии в верхней части каждого метода обработки событий, чтобы лучше их понять. Давайте реализуем это с помощью некоторых базовых обработчиков событий, необходимых для этого приложения. || mRtcEventHandler || – это обработчик для управления различными событиями, происходящими с механизмом Rtc. На странице Управления проектами найдите идентификатор приложения вашего проекта. введите имя, выберите механизм аутентификации и нажмите “Отправить”. панель управления. он || Идентификатор приложения || в параметре, выполните следующие действия: tance.

public class AgoraVideoSource implements IVideoSource {
    private IVideoFrameConsumer mConsumer;

    @Override
    public boolean onInitialize(IVideoFrameConsumer iVideoFrameConsumer) {
        mConsumer = iVideoFrameConsumer;
        return true;
    }

    @Override
    public boolean onStart() {
        return true;
    }

    @Override
    public void onStop() {
    }

    @Override
    public void onDispose() {
    }

    @Override
    public int getBufferType() {
        return MediaIO.BufferType.BYTE_ARRAY.intValue();
    }

    public IVideoFrameConsumer getConsumer() {
        return mConsumer;
    }
}

В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе onDrawFrame ? Мы опросили нажатия пользователя из Одиночных нажатий в очереди, где тета Инициализирует движок Agora Rtc, и они добавляются в очередь. Чтобы инициализировать движок видео Agora, просто вызовите Rtc Engine.create(контекст, идентификатор приложения, обработчик событий Rtc)

mSource = new AgoraVideoSource();

В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе onDrawFrame ? Мы опросили нажатия пользователя из Одиночных нажатий в очереди, где тета Инициализирует движок Agora Rtc, и они добавляются в очередь. Чтобы инициализировать движок видео Agora, просто вызовите Rtc Engine.create(контекст, идентификатор приложения, обработчик событий Rtc)

public class AgoraVideoRender implements IVideoSink {
    private Peer mPeer;
    private boolean mIsLocal;

    public AgoraVideoRender(int uid, boolean local) {
        mPeer = new Peer();
        mPeer.uid = uid;
        mIsLocal = local;
    }

    public Peer getPeer() {
        return mPeer;
    }

    @Override
    public boolean onInitialize() {
        return true;
    }

    @Override
    public boolean onStart() {
        return true;
    }

    @Override
    public void onStop() {

    }

    @Override
    public void onDispose() {

    }

    @Override
    public long getEGLContextHandle() {
        return 0;
    }

    @Override
    public int getBufferType() {
        return MediaIO.BufferType.BYTE_BUFFER.intValue();
    }

    @Override
    public int getPixelFormat() {
        return MediaIO.PixelFormat.RGBA.intValue();
    }

    @Override
    public void consumeByteBufferFrame(ByteBuffer buffer, int format, int width, int height, int rotation, long ts) {
        if (!mIsLocal) {
            mPeer.data = buffer;
            mPeer.width = width;
            mPeer.height = height;
            mPeer.rotation = rotation;
            mPeer.ts = ts;
        }
    }

    @Override
    public void consumeByteArrayFrame(byte[] data, int format, int width, int height, int rotation, long ts) {

    }

    @Override
    public void consumeTextureFrame(int texId, int format, int width, int height, int rotation, long ts, float[] matrix) {

    }

}

Подобно экземпляру источника видео Agora, мы создаем экземпляр рендеринга видео Agora, вызывая его конструктор. Здесь мы передаем uid как 0 для представления локального рендеринга видео.

mRender = new AgoraVideoRender(0, true);

После создания двух экземпляров мы вызываем

mRtcEngine.setVideoSource(mSource);
mRtcEngine.setLocalVideoRenderer(mRender);

для настройки пользовательского источника видео AR и локального средства визуализации видео.

Однако установленный нами источник видео не содержит данных. Нам нужно передать изображение с камеры AR нашему источнику видео. Для этого мы собираемся добавить логику в конце метода onDrawFrame, который мы переопределяли ранее.

@Override
public void onDrawFrame(GL10 gl) {
    ...
    final Bitmap outBitmap = Bitmap.createBitmap(mSurfaceView.getWidth(), mSurfaceView.getHeight(), Bitmap.Config.ARGB_8888);
    PixelCopy.request(mSurfaceView, outBitmap, new PixelCopy.OnPixelCopyFinishedListener() {
        @Override
        public void onPixelCopyFinished(int copyResult) {
            if (copyResult == PixelCopy.SUCCESS) {
                sendARView(outBitmap);
            } else {
                Toast.makeText(AgoraARCoreActivity.this, "Pixel Copy Failed", Toast.LENGTH_SHORT);
            }
        }
    }, mSenderHandler);
}
private void sendARView(Bitmap bitmap) {
    if (bitmap == null) return;

    if (mSource.getConsumer() == null) return;

    //Bitmap bitmap = source.copy(Bitmap.Config.ARGB_8888,true);
    int width = bitmap.getWidth();
    int height = bitmap.getHeight();

    int size = bitmap.getRowBytes() * bitmap.getHeight();
    ByteBuffer byteBuffer = ByteBuffer.allocate(size);
    bitmap.copyPixelsToBuffer(byteBuffer);
    byte[] data = byteBuffer.array();

    mSource.getConsumer().consumeByteArrayFrame(data, MediaIO.PixelFormat.RGBA.intValue(), width, height, 0, System.currentTimeMillis());
}

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

4. Присоединиться к каналу

Теперь мы готовы присоединиться к каналу, вызвав joinChannel() на экземпляре Rtc Engine, передав имя канала из предыдущего действия.

mRtcEngine.joinChannel(null, channelName, "", 0);

Пожалуйста, обратите внимание: Маркер в параметре может быть установлен в значение null.

Вызвав эту функцию и успешно присоединившись к каналу, обработчик событий механизма Rtc запустит метод onJoinChannelSuccess(), который мы реализовали на предыдущем шаге. Он вернет уникальный идентификатор видео Agora, сгенерированный сервером Agora.

До этого момента стример может присоединиться к каналу и транслировать зрителям свой мир ПРИБЫТИЯ.

Включение видеовызова аудитории очень похоже на то, что мы написали для стримера. Единственное отличие заключается в настройке видео с локальной камеры после инициализации движка Rtc.

mRtcEngine.enableVideo();
mLocalView = RtcEngine.CreateRendererView(getBaseContext());
mLocalContainer.addView(mLocalView);
mLocalView.setZOrderMediaOverlay(true);

VideoCanvas localVideoCanvas = new VideoCanvas(mLocalView, VideoCanvas.RENDER_MODE_HIDDEN, 0);
mRtcEngine.setupLocalVideo(localVideoCanvas);

Единственное отличие заключается в настройке видео с локальной камеры после инициализации движка Rtc. Это приведет к отображению локальной камеры аудитории в правом верхнем углу экрана.

Единственное отличие заключается в настройке видео с локальной камеры после инициализации движка Rtc. Это приведет к отображению локальной камеры аудитории в правом верхнем углу экрана. пожалуйста, обратите внимание: Единственное отличие заключается в настройке видео с локальной камеры после инициализации движка Rtc. Это приведет к отображению локальной камеры аудитории в правом верхнем углу экрана. Пожалуйста, обратите Внимание: Найдите Единственное отличие заключается в настройке видео с локальной камеры после инициализации движка Rtc. Это приведет к отображению локальной камеры аудитории в правом верхнем углу экрана. Пожалуйста, обратите внимание: Найдите код на Github Единственное отличие заключается в настройке видео с локальной камеры после инициализации движка Rtc. Это приведет к отображению локальной камеры аудитории в правом верхнем углу экрана. Пожалуйста, обратите внимание: Найдите код Github для большего понимания.

Единственное отличие заключается в настройке видео с локальной камеры после инициализации движка Rtc. Это приведет к отображению локальной камеры аудитории в правом верхнем углу экрана. Пожалуйста, обратите внимание: Найдите код Github для большего понимания. Теперь мы можем начать видеозвонок между стримером и аудиторией. Однако это все еще не полноценное приложение для удаленной помощи, поскольку аудитория не может взаимодействовать с миром AR streamer. Затем мы начнем внедрять функцию разметки аудитории через ARCore.

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

Чтобы достичь этого, мы собираемся собрать позиции касания участников аудитории и отправить их стримеру. Пока стример получает эти точки касания, мы можем имитировать касания на экране стримера для создания объектов AR.

Давайте сначала соберем позиции касания аудитории. В методе onCreate активности аудитории Agora AR настройте прослушиватель прикосновений в контейнере удаленного просмотра. Соберите все положения точек касания по отношению к центру экрана. Отправьте их стримеру в виде сообщения потока данных, используя метод Agora API, отправить потоковое сообщение . Это приведет к запуску стримеров сообщение в потоке обратный вызов. Поскольку пользователь может отправлять только 6 Кб данных в секунду, мы отправляем точки касания всякий раз, когда собираем 10 из них.

mRemoteContainer.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                //get the touch position related to the center of the screen
                touchCount++;
                float x = event.getRawX() - ((float)mWidth / 2);
                float y = event.getRawY() - ((float)mHeight / 2);
                floatList.add(x);
                floatList.add(y);
                if (touchCount == 10) {
                    //send the touch positions when collected 10 touch points
                    sendMessage(touchCount, floatList);
                    touchCount = 0;
                    floatList.clear();
                }
                break;
            case MotionEvent.ACTION_UP:
                //send touch positions after the touch motion
                sendMessage(touchCount, floatList);
                touchCount = 0;
                floatList.clear();
                break;
        }
        return true;
    }
});

Вот логика отправки сообщения :

/**
 * send the touch points as a byte array to Agora sdk
 * @param touchCount
 * @param floatList
 */
private void sendMessage(int touchCount, List floatList) {
    byte[] motionByteArray = new byte[touchCount * 4 * 2];
    for (int i = 0; i < floatList.size(); i++) {
        byte[] curr = ByteBuffer.allocate(4).putFloat(floatList.get(i)).array();
        for (int j = 0; j < 4; j++) {
            motionByteArray[i * 4 + j] = curr[j];
        }
    }
    mRtcEngine.sendStreamMessage(dataChannel, motionByteArray);
}

Теперь в AgoraARStreamerActivity нам нужно переопределить в потоковом сообщении обратный вызов для получения точек касания, отправленных аудиторией, и имитации прикосновений на экране стримера.

@Override
public void onStreamMessage(int uid, int streamId, byte[] data) {
    //when received the remote user's stream message data
    super.onStreamMessage(uid, streamId, data);
    int touchCount = data.length / 8;       //number of touch points from data array
    for (int k = 0; k < touchCount; k++) {
        //get the touch point's x,y position related to the center of the screen and calculated the raw position
        byte[] xByte = new byte[4];
        byte[] yByte = new byte[4];
        for (int i = 0; i < 4; i++) {
            xByte[i] = data[i + 8 * k];
            yByte[i] = data[i + 8 * k + 4];
        }
        float convertedX = ByteBuffer.wrap(xByte).getFloat();
        float convertedY = ByteBuffer.wrap(yByte).getFloat();
        float center_X = convertedX + ((float) mWidth / 2);
        float center_Y = convertedY + ((float) mHeight / 2);

        //simulate the clicks based on the touch position got from the data array
        instrumentation.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, center_X, center_Y, 0));
        instrumentation.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, center_X, center_Y, 0));
    }
}

Это все, что вам нужно для создания приложения удаленной помощи. Теперь давайте запустим наше приложение!

Перейдите в Android Studio, убедитесь, что ваше Android-устройство подключено, и нажмите Запустите , чтобы создать приложение на вашем устройстве. Не забудьте создать приложение на двух устройствах, чтобы начать видеозвонок. Оба устройства должны работать под управлением Android API уровня 24 или выше и изначально поставляться в магазине Google Play.

Вы можете проверить подробные требования к устройству здесь .

Поздравляю! Вы просто создаете приложение для удаленной помощи с функциями дополненной реальности!

Спасибо, что последовали за мной. Пожалуйста, оставьте комментарий ниже! Вот адрес электронной почты для любых вопросов, которые у вас могут возникнуть: devrel@agora.io .

Оригинал: “https://dev.to/ysc1995/how-to-build-an-augmented-reality-remote-assistance-app-in-android-5980”