Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Пример Android-приложения для записи видеопотока

Данный пример может использоваться с Web Call Server для публикации и записи WebRTC-видеопотока.

На скриншоте ниже представлен пример после завершения публикации потока.

В URL в поле ввода

  • 192.168.2.104 - адрес WCS-сервера
  • testStream - имя потока

Над полем ввода отображается видео с камеры.

Под полем ввода расположены

  • ссылка для скачивания записи потока
  • медиа-плеер, в котором можно воспроизвести запись

Работа с кодом примера

Для разбора кода возьмем класс StreamRecordingActivity.java примера stream-recording, который доступен для скачивания в соответствующей сборке 1.0.1.38.

1. Инициализация API.

Flashphoner.init() код

Code Block
languagejs
Flashphoner.init(this);


При инициализации методу init() передается объект Сontext.

2. Создание сессии

Flashphoner.createSession() код

Методу передается объект SessionOptions со следующими параметрами

  • URL WCS-сервера
  • SurfaceViewRenderer localRenderer, который будет использоваться для отображения видео с камеры


Code Block
languagejs
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(). код

Code Block
languagejs
session.connect(new Connection());


4. Получение от сервера события, подтверждающего успешное соединение.

session.onConnected() код

Code Block
languagejs
@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());

/**
* The options for the stream to publish are set.
* The stream name is passed when StreamOptions object is created.
* To enable stream recording, option 'record' is set to 'true' with method StreamOptions.setRecord().
*/
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);
}
});
}


5. Создание видеопотока и подготовка к публикации.

Session.createStream(), ActivityCompat.requestPermissions() код

Методу Session.createStream() передается объект StreamOptions с параметрами:

  • имя видеопотока;
  • record в значении true для записи потока
Code Block
languagejs
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() код

Code Block
languagejs
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().

Code Block
languagejs
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() код

Code Block
languagejs
mStartButton.setEnabled(false);

/**
* Connection to WCS server is closed with method Session.disconnect().
*/
session.disconnect();



9. Получение события, подтверждающего разъединение.

session.onDisconnection() код

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

Code Block
languagejs
@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();
}
}
});
}