Пример Android приложения с двумя Websocket сессиями
Данное приложение демонстрирует использование одновременно двух Websocket сессий для подключения к одному или двум разным WCS серверам. Публиковать при этом можно только один поток, т.к. Android не позволяет захватить одновременно две камеры, либо дважды одну и ту же камеру. Воспроизводить можно одновременно два потока.
На скриншоте представлен пример публикации на один сервер и проигрывания этого потока в двух сессиях
Работа с кодом примера
Для разбора кода возьмем класс TwoSessionsActivity.java примера 2sessions, который доступен для скачивания в соответствующей сборке 1.1.0.57
Реализация представляет собой два примера Two Way Streaming в одном приложении, поэтому далее рассмотрим подробно код одной из двух сессий
1. Инициализация API.
Flashphoner.init() code
Независимо от количества сессий, API инициализируется один раз на приложение
Flashphoner.init(this);
2. Создание сессии
Flashphoner.createSession() code
Методу передается объект SessionOptions со следующими параметрами
- URL WCS-сервера
- SurfaceViewRenderer localRenderer, который будет использоваться для отображения видео с камеры
- SurfaceViewRenderer remoteRenderer, который будет использоваться для отображения воспроизводимого потока
SessionOptions sessionOptions = new SessionOptions(mWcsUrl1View.getText().toString());
sessionOptions.setRemoteRenderer(remote1Render);
sessionOptions.setLocalRenderer(local1Render);
/**
* Session for connection to WCS server is created with method createSession().
*/
session1 = Flashphoner.createSession(sessionOptions);
3. Подключение к серверу.
Session.connect() code
session1.connect(new Connection());
4. Получение от сервера события, подтверждающего успешное соединение.
session.onConnected() code
По данному событию запрашиваются права на доступ к камере и микрофону
@Override
public void onConnected(final Connection connection) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mConnect1Button.setText(R.string.action_disconnect);
mConnect1Button.setTag(R.string.action_disconnect);
mConnect1Button.setEnabled(true);
mConnect1Status.setText(connection.getStatus());
mPlay1Button.setEnabled(true);
if (mPublish2Button.getTag() == null || Integer.valueOf(R.string.action_publish).equals(mPublish2Button.getTag())) {
mPublish1Button.setEnabled(true);
}
ActivityCompat.requestPermissions(TwoSessionsActivity.this,
new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA},
PUBLISH_REQUEST_CODE);
}
});
}
5. Публикация потока по нажатию кнопки Publish1Button
Session.createStream(), Stream.publish() code
mPublish1Button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
mPublish1Button.setEnabled(false);
mPublish2Button.setEnabled(false);
mConnect1Button.setEnabled(false);
mConnect2Button.setEnabled(false);
if (mPublish1Button.getTag() == null || Integer.valueOf(R.string.action_publish).equals(mPublish1Button.getTag())) {
/**
* The options for the stream to play are set.
* The stream name is passed when StreamOptions object is created.
* SurfaceViewRenderer to be used to display the video stream is set using method StreamOptions.setRenderer().
*/
StreamOptions streamOptions = new StreamOptions(mPublish1StreamView.getText().toString());
streamOptions.setRenderer(local1Render);
/**
* Stream is created with method Session.createStream().
*/
publish1Stream = session1.createStream(streamOptions);
...
publish1Stream.publish();
} else {
...
}
}
});
6. Воспроизведение потока при нажатии Play1Button
Session.createStream(), Stream.play() code
mPlay1Button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
mPlay1Button.setEnabled(false);
if (mPlay1Button.getTag() == null || Integer.valueOf(R.string.action_play).equals(mPlay1Button.getTag())) {
/**
* The options for the stream to play are set.
* The stream name is passed when StreamOptions object is created.
* SurfaceViewRenderer to be used to display the video stream is set using method StreamOptions.setRenderer().
*/
StreamOptions streamOptions = new StreamOptions(mPlay1StreamView.getText().toString());
streamOptions.setRenderer(remote1Render);
/**
* Stream is created with method Session.createStream().
*/
play1Stream = session1.createStream(streamOptions);
...
play1Stream.play();
...
} else {
...
}
}
});
7. Остановка воспроизведение потока
Stream.stop() code
mPlay1Button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
mPlay1Button.setEnabled(false);
if (mPlay1Button.getTag() == null || Integer.valueOf(R.string.action_play).equals(mPlay1Button.getTag())) {
...
} else {
/**
* Method Stream.stop() is called to stop playback of the stream.
*/
play1Stream.stop();
play1Stream = null;
}
...
}
});
8. Остановка публикации потока
Stream.stop() code
mPublish1Button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
mPublish1Button.setEnabled(false);
mPublish2Button.setEnabled(false);
mConnect1Button.setEnabled(false);
mConnect2Button.setEnabled(false);
if (mPublish1Button.getTag() == null || Integer.valueOf(R.string.action_publish).equals(mPublish1Button.getTag())) {
...
} else {
/**
* Method Stream.stop() is called to stop playback of the stream.
*/
publish1Stream.stop();
publish1Stream = null;
}
...
}
});
9. Закрытие соединения
Session.disconnect() code
mConnect1Button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
if (mConnect1Button.getTag() == null || Integer.valueOf(R.string.action_connect).equals(mConnect1Button.getTag())) {
...
} else {
mConnect1Button.setEnabled(false);
/**
* Connection to WCS server is closed with method Session.disconnect().
*/
session1.disconnect();
}
...
}
});
10. Получение события, подтверждающего разъединение.
session.onDisconnection() code
public void onDisconnection(final Connection connection) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mConnect1Button.setText(R.string.action_connect);
mConnect1Button.setTag(R.string.action_connect);
mConnect1Button.setEnabled(true);
mPlay1Button.setText(R.string.action_play);
mPlay1Button.setTag(R.string.action_play);
mPlay1Button.setEnabled(false);
mPublish1Button.setEnabled(false);
mPublish1Button.setText(R.string.action_publish);
mPublish1Button.setTag(R.string.action_publish);
mConnect1Status.setText(connection.getStatus());
mPlay1Status.setText("");
if (mConnect2Button.getTag() == null || Integer.valueOf(R.string.action_disconnect).equals(mConnect2Button.getTag())) {
mPublish2Button.setEnabled(true);
}
}
});
}
