...
Данный пример может использоваться как стример для публикации WebRTC-видеопотока с Web Call Server и позволяет выбрать медиа-устройства и параметры для публикуемого видео
Пример переключения объекта для вывода изображения с камеры
Работа с кодом примера
Для разбора кода возьмем класс MediaDevicesActivity.java примера media-devices, который доступен для скачивания в соответствующей сборке 1.0.1.4669.
1. Инициализация API.
При инициализации методу init() передается объект Сontext.
...
Flashphoner.getMediaDevices(), MediaDeviceList.getAudioList(), MediaDeviceList.getVideoList() код code
| Code Block | ||||
|---|---|---|---|---|
| ||||
mMicSpinner = (LabelledSpinner) findViewById(R.id.microphone); mMicSpinner.setItemsArray(Flashphoner.getMediaDevices().getAudioList()); mMicLevel = (TextView) findViewById(R.id.microphone_level); mCameraSpinner = (LabelledSpinner) findViewById(R.id.camera); mCameraSpinner.setItemsArray(Flashphoner.getMediaDevices().getVideoList()); |
...
FPSurfaceViewRenderer.setMirror() код code
При показе видео изображение выводится на объекты FPSurfaceViewRenderer:
...
AudioConstraints, VideoConstraints код code
| Code Block | ||||
|---|---|---|---|---|
| ||||
@NonNull
private Constraints getConstraints() {
AudioConstraints audioConstraints = null;
if (mSendAudio.isChecked()) {
audioConstraints = new AudioConstraints();
if (mUseFEC.isChecked()) {
audioConstraints.setUseFEC(true);
}
if (mUseStereo.isChecked()) {
audioConstraints.setUseStereo(true);
}
if (!mDefaultPublishAudioBitrate.isChecked() && mDefaultPublishAudioBitrate.getText().length() > 0) {
audioConstraints.setBitrate(Integer.parseInt(mPublishAudioBitrate.getText().toString()));
}
}
VideoConstraints videoConstraints = null;
if (mSendVideo.isChecked()) {
videoConstraints = new VideoConstraints();
videoConstraints.setCameraId(((MediaDevice) mCameraSpinner.getSpinner().getSelectedItem()).getId());
if (mCameraFPS.getText().length() > 0) {
videoConstraints.setVideoFps(Integer.parseInt(mCameraFPS.getText().toString()));
}
if (mWidth.getText().length() > 0 && mHeight.getText().length() > 0) {
videoConstraints.setResolution(Integer.parseInt(mWidth.getText().toString()),
Integer.parseInt(mHeight.getText().toString()));
}
if (!mDefaultPublishVideoBitrate.isChecked() && mPublishVideoBitrate.getText().length() > 0) {
videoConstraints.setBitrate(Integer.parseInt(mPublishVideoBitrate.getText().toString()));
}
}
return new Constraints(audioConstraints, videoConstraints);
} |
...
Flashphoner.getLocalMediaAccess() код code
Методу передаются:
- настройки аудио и видео, заданные пользователем
- локальный объект SurfaceViewRenderer localRenderer для вывода изображения с выбранной камеры
...
Flashphoner.createSession() код code
Методу передается объект SessionOptions со следующими параметрами
...
7. Подключение к серверу.
| Code Block | ||||
|---|---|---|---|---|
| ||||
session.connect(new Connection()); |
8. Получение от сервера события, подтверждающего успешное соединение.
session.onConnected() код code
| Code Block | ||||
|---|---|---|---|---|
| ||||
@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);
mTestButton.setEnabled(false);
mStatusView.setText(connection.getStatus());;
...
}
});
} |
9. Создание потока и подготовка к публикации
session.createStream() код code
| Code Block | ||||
|---|---|---|---|---|
| ||||
publishStream = session.createStream(streamOptions);
if (mMuteAudio.isChecked()) {
publishStream.muteAudio();
}
if (mMuteVideo.isChecked()) {
publishStream.muteVideo();
}
...
ActivityCompat.requestPermissions(MediaDevicesActivity.this,
new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA},
PUBLISH_REQUEST_CODE); |
10. Публикация потока
| Code Block | ||||
|---|---|---|---|---|
| ||||
case PUBLISH_REQUEST_CODE: {
if (grantResults.length == 0 ||
grantResults[0] != PackageManager.PERMISSION_GRANTED ||
grantResults[1] != PackageManager.PERMISSION_GRANTED) {
mStartButton.setEnabled(false);
mTestButton.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");
}
break;
} |
...
StreamStatusEvent PUBLISHING код code
При получении данного события создается превью-видеопоток при помощи Session.createStream() и вызывается Stream.play() для его воспроизведения.
...
12. Переключение камеры во время трансляции
Stream.switchCamera() код code
| Code Block | ||||
|---|---|---|---|---|
| ||||
mSwitchCameraButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
if (publishStream != null) {
mSwitchCameraButton.setEnabled(false);
publishStream.switchCamera(new CameraSwitchHandler() {
@Override
public void onCameraSwitchDone(boolean var1) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mSwitchCameraButton.setEnabled(true);
}
});
}
@Override
public void onCameraSwitchError(String var1) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mSwitchCameraButton.setEnabled(true);
}
});
}
});
}
}
}); |
13. Переключение объекта для отображения видеопотока во время трансляции
Stream.switchRenderer() код code
| Code Block | ||||
|---|---|---|---|---|
| ||||
mSwitchRendererButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (spinner.getSelectedItemId() == 0){
if (isSwitchRemoteRenderer) {
playStream.switchRenderer(remoteRender);
isSwitchRemoteRenderer = false;
}
if (!isSwitchLocalRenderer) {
publishStream.switchRenderer(newSurfaceRenderer);
isSwitchLocalRenderer = true;
} else {
publishStream.switchRenderer(localRender);
isSwitchLocalRenderer = false;
}
} else {
if (isSwitchLocalRenderer) {
publishStream.switchRenderer(localRender);
isSwitchLocalRenderer = false;
}
if (!isSwitchRemoteRenderer) {
playStream.switchRenderer(newSurfaceRenderer);
isSwitchRemoteRenderer = true;
} else {
playStream.switchRenderer(remoteRender);
isSwitchRemoteRenderer = false;
}
}
}
}); |
14. Закрытие соединения.Session.disconnect() кодУправление звуком при помощи аппаратных кнопок
Flashphoner.setVolume() code
| Code Block | ||||
|---|---|---|---|---|
| ||||
mStartButton.setEnabled(false); /** * Connection to@Override WCS server is closedpublic withboolean method Session.onKeyDown(int keyCode, KeyEvent event) { int currentVolume = Flashphoner.getVolume(); switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_DOWN: if (currentVolume == 1) { Flashphoner.setVolume(0); } mPlayVolume.setProgress(currentVolume-1); break; case KeyEvent.KEYCODE_VOLUME_UP: if (currentVolume == 0) { Flashphoner.setVolume(1); } mPlayVolume.setProgress(currentVolume+1); break; } return super.onKeyDown(keyCode, event); } |
15. Закрытие соединения.
Session.disconnect() code
| Code Block | ||||
|---|---|---|---|---|
| ||||
mStartButton.setEnabled(false);
mTestButton.setEnabled(false);
/**
* Connection to WCS server is closed with method Session.disconnect().
*/
session.disconnect(); |
1516. Получение события, подтверждающего разъединение.
session.onDisconnection() код code
| Code Block | ||||
|---|---|---|---|---|
| ||||
@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);
mSwitchCameraButton.setEnabled(false);
mSwitchRendererButton.setEnabled(false);
mStatusView.setText(connection.getStatus());
mTestButton.setEnabled(true);
}
});
} |

