Это могло случиться со многими из нас в какой-то момент: вы включили фен или обогреватель, и внезапно весь ваш свет погас, а телевизор стал черным.
Теперь вам придется в отчаянии позвонить в службу поддержки вашего поставщика услуг. Вы объяснили, что произошло, и они сказали, что вам, возможно, просто нужно включить воздушный выключатель. Однако, когда вы открываете электрическую панель, вы задаетесь вопросом: какой из них является воздушным выключателем? После 20-минутного разговора с представителем службы поддержки клиентов, пытающимся найти этот переключатель, вы обнаруживаете, что у вас дома его вообще нет.
Большая часть удаленной помощи сегодня осуществляется с помощью голосовых вызовов или текстовых сообщений. Это вряд ли удобно для пользователей, пытающихся описать свои проблемы или понять новые концепции и терминологию, необходимые для устранения неполадок.
К счастью, технологии достигли такого уровня, когда мы можем решить эту проблему с помощью видеочата и дополненной реальности. В этом руководстве я предоставлю пошаговое руководство, чтобы показать вам, как создать приложение для Android, которое использует чат и видеочат для создания интерактивного взаимодействия.
- Базовое и промежуточное понимание Java и Android SDK
- Базовое понимание концепций ARCore и дополненной реальности
- Agora.io Учетная запись разработчика
- Аппаратное обеспечение: 2 устройства Android, работающие под управлением Android API уровня 24 или выше и первоначально поставляемые с Google Play Store
* Вы можете проверить подробные требования к устройству здесь .
Пожалуйста, обратите внимание: Хотя для продолжения не требуется никаких знаний Java/Android, некоторые базовые концепции Java/Hardcore не будут объяснены на этом пути.
В этом руководстве мы собираемся создать приложение поддержки клиентов с поддержкой AR. Один пользователь создаст канал, введя имя канала, присоединившись к каналу в качестве стримера (люди, которым нужна поддержка). В то время как другой пользователь может присоединиться к тому же каналу, введя то же название канала, что и участник аудитории (служба поддержки клиентов). Когда оба пользователя будут подключены к каналам, стример будет транслировать их заднюю камеру аудитории. Аудитория может рисовать на своем собственном устройстве и получать сенсорный ввод в дополненной реальности в мире стримера!
Вот все шаги, которые мы рассмотрим в этой статье:
- Создать Новый Проект
- Создать пользовательский интерфейс
- Включить Хардкор
- Включить Видеовызов Стримеров
- Включить Видеозвонок аудитории
- Функция Удаленной Помощи
- Сборка И тестирование на устройстве
Вы можете найти мой Github демонстрационное приложение в качестве ссылки для этой статьи.
Для начала давайте откроем Android studio и создадим новый пустой проект.
- Откройте Android Studio и нажмите Начните новый проект Android Studio .
- На панели Выберите свой проект выберите Телефон и планшет > Пустое действие и нажмите Следующий .
- Нажмите Готово . Следуйте инструкциям на экране, если вам нужно установить какие-либо плагины.
Интеграция 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-сцены.
- Создайте экземпляр средства визуализации фона и передайте его идентификатор камере сеанса.
- Инициализируйте 3D-объект. Этот 3D-объект будет отрисован в streamers AR world позже.
- Инициализируйте визуализацию обнаружения плоскости.
- Инициализируйте облако точек.
@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.
- Очистить экран.
- Получите последний кадр из сеанса.
- Фиксируйте нажатия пользователя и проверяйте, были ли найдены какие-либо плоскости в сцене. Если это так, создайте якорь в этой точке.
- Нарисуйте фон.
- Нарисуйте облако точек.
- Повторите все якоря и нарисуйте 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 давайте сделаем следующее:
- Инициализировать GLSurfaceView OnTouchListener
- Инициализировать механизм Agora Rtc
- Настройка пользовательского источника видео
- Присоединиться к каналу
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 ? Мы опросили нажатия пользователя из
- В этом методе мы добавляем этот кран в очередь одного крана. Помните, когда мы создавали якоря в методе onDrawFrame
- ? Мы опросили нажатия пользователя из Одиночных нажатий в очереди, где тета Инициализирует движок Agora Rtc, и они добавляются в очередь. Чтобы инициализировать движок видео Agora, просто вызовите Rtc Engine.create(контекст, идентификатор приложения, обработчик событий Rtc)
- для создания RtcEngine для создания проекта Agora
- в консоли 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, ListfloatList) { 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”