Пример Android-приложения для записи видеопотока
Данный пример может использоваться с Web Call Server для публикации и записи WebRTC-видеопотока.
На скриншоте ниже представлен пример после завершения публикации потока.
В URL в поле ввода
- 192.168.2.104 - адрес WCS-сервера
- testStream - имя потока
Над полем ввода отображается видео с камеры.
Под полем ввода расположены
- ссылка для скачивания записи потока
- медиа-плеер, в котором можно воспроизвести запись
Работа с кодом примера
Для разбора кода возьмем класс StreamRecordingActivity.java примера stream-recording, который доступен для скачивания в соответствующей сборке 1.0.1.38.
1. Инициализация API.
Flashphoner.init() код
Flashphoner.init(this);
При инициализации методу init() передается объект Сontext.
2. Создание сессии
Flashphoner.createSession() код
Методу передается объект SessionOptions со следующими параметрами
- URL WCS-сервера
- SurfaceViewRenderer localRenderer, который будет использоваться для отображения видео с камеры
SessionOptions sessionOptions = new SessionOptions(url); sessionOptions.setLocalRenderer(localRender); /** * Session for connection to WCS server is created with method createSession(). */ session = Flashphoner.createSession(sessionOptions);
3. Подключение к серверу.
Session.connect(). код
session.connect(new Connection());
4. Получение от сервера события, подтверждающего успешное соединение.
session.onConnected() код
@Override public void onConnected(final Connection connection) { runOnUiThread(new Runnable() { @Override public void run() { mStartButton.setText(R.string.action_stop); mStartButton.setTag(R.string.action_stop); mStartButton.setEnabled(true); mStatusView.setText(connection.getStatus()); ... } }); }
5. Создание видеопотока и подготовка к публикации.
Session.createStream(), ActivityCompat.requestPermissions() код
Методу Session.createStream() передается объект StreamOptions с параметрами:
- имя видеопотока;
- record в значении true для записи потока
StreamOptions streamOptions = new StreamOptions(streamName); streamOptions.setRecord(true); /** * Stream is created with method Session.createStream(). */ publishStream = session.createStream(streamOptions); /** * Callback function for stream status change is added to display the status. */ publishStream.on(new StreamStatusEvent() { @Override public void onStreamStatus(final Stream stream, final StreamStatus streamStatus) { runOnUiThread(new Runnable() { @Override public void run() { if (StreamStatus.PUBLISHING.equals(streamStatus)) { mStatusView.setText("RECORDING"); /** * Filename of the recording is determined. */ recordFilename = stream.getRecordName(); return; } else if (StreamStatus.FAILED.equals(streamStatus)) { Log.e(TAG, "Can not publish stream " + stream.getName() + " " + streamStatus); recordFilename = null; } mStatusView.setText(streamStatus.toString()); } }); } }); ActivityCompat.requestPermissions(StreamRecordingActivity.this, new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA}, PUBLISH_REQUEST_CODE);
6. Публикация потока после предоставления соответствующих прав
Stream.publish() код
case PUBLISH_REQUEST_CODE: { if (grantResults.length == 0 || grantResults[0] != PackageManager.PERMISSION_GRANTED || grantResults[1] != PackageManager.PERMISSION_GRANTED) { mStartButton.setEnabled(false); session.disconnect(); Log.i(TAG, "Permission has been denied by user"); } else { /** * Method Stream.publish() is called to publish stream. */ publishStream.publish(); Log.i(TAG, "Permission has been granted by user"); } }
7. Получение от сервера события, подтверждающего успешную публикацию потока
StreamStatusEvent PUBLISHING код
При получении данного события определяется имя файла записи потока с помощью метода Stream.getRecordName().
publishStream.on(new StreamStatusEvent() { @Override public void onStreamStatus(final Stream stream, final StreamStatus streamStatus) { runOnUiThread(new Runnable() { @Override public void run() { if (StreamStatus.PUBLISHING.equals(streamStatus)) { mStatusView.setText("RECORDING"); /** * Filename of the recording is determined. */ recordFilename = stream.getRecordName(); return; } else if (StreamStatus.FAILED.equals(streamStatus)) { Log.e(TAG, "Can not publish stream " + stream.getName() + " " + streamStatus); recordFilename = null; } mStatusView.setText(streamStatus.toString()); } }); } });
8. Закрытие соединения.
Session.disconnect() код
mStartButton.setEnabled(false); /** * Connection to WCS server is closed with method Session.disconnect(). */ session.disconnect();
9. Получение события, подтверждающего разъединение.
session.onDisconnection() код
При получении данного события формируется ссылка на скачивание файла записи потока и запускается локальный медиаплеер для воспроизведения файла
@Override public void onDisconnection(final Connection connection) { runOnUiThread(new Runnable() { @Override public void run() { mStartButton.setText(R.string.action_start); mStartButton.setTag(R.string.action_start); mStartButton.setEnabled(true); mStatusView.setText(connection.getStatus()); /** * After disconnection, download link for the recording of the published stream is displayed, and the recording can be played in the media player of the application. */ if (recordFilename != null) { /** * Download link is formed. * Stream recordings are saved to directory WCS_HOME/client/records on the server. */ String url = "http://" + uri.getHost() +":9091/client/records/" + recordFilename; mRecordedLink.setText(url); Linkify.addLinks(mRecordedLink, Linkify.WEB_URLS); MediaController mediaController = new MediaController(StreamRecordingActivity.this); mediaController.setAnchorView(mRecordedVideoView); mRecordedVideoView.setMediaController(mediaController); mRecordedVideoView.setVideoURI(Uri.parse(url)); /** * Playback of the recording in the media player is started. */ mRecordedVideoView.start(); } } });