使用 DJI Android SDK LiveStreamManager 实时流式传输无人机相机有很大的延迟。使用 SampleCode 它没有,我错过了什么?
Using DJI Android SDK LiveStreamManager to stream drone camera live has a huge delay. Using the SampleCode it doesn't, what am I missing?
我已经使用 DJI SDK 创建了一个 android 应用程序。我已经按照说明进行操作,并且基本上从 DJI 示例代码 (https://github.com/dji-sdk/Mobile-SDK-Android/blob/master/Sample%20Code/app/src/main/java/com/dji/sdk/sample/demo/camera/LiveStreamView.java) 中复制了代码,因为它可以正常工作。
启动连接 activity 后,它注册了 SDK 并连接到 Mavic 2 Zoom 无人机,另一个 activity 来了,它处理到 RTMP 服务器的直播。当使用示例代码流式传输到同一个 RTMP 服务器时,它没有延迟,但是当使用我的应用程序时,它有 15 秒的延迟。我不知道为什么,我使用的是相同的组件。唯一的区别是我将相机焦点设置为最大,但我在示例代码中做了同样的事情,所以它应该不会造成任何问题。还使用与示例中相同的 VideoFeedView。
public class MainActivity extends Activity implements View.OnClickListener {
private static final String TAG = MainActivity.class.getName();
private String liveShowUrl = "rtmp://192.168.00.00/live";
private VideoFeedView primaryVideoFeedView;
private VideoFeedView fpvVideoFeedView;
private EditText showUrlInputEdit;
private Button startLiveShowBtn;
private Button enableVideoEncodingBtn;
private Button disableVideoEncodingBtn;
private Button stopLiveShowBtn;
private Button soundOnBtn;
private Button soundOffBtn;
private Button isLiveShowOnBtn;
private Button showInfoBtn;
private Button showLiveStartTimeBtn;
private Button showCurrentVideoSourceBtn;
private Button changeVideoSourceBtn;
private Camera camera;
private LiveStreamManager.OnLiveChangeListener listener;
private LiveStreamManager.LiveStreamVideoSource currentVideoSource = LiveStreamManager.LiveStreamVideoSource.Primary;
private CommonCallbacks.CompletionCallback focusSetCompletionCallback = new CommonCallbacks.CompletionCallback() {
@Override
public void onResult(DJIError djiError) {
Log.d(TAG, "Camera focus is set to manual");
Toast.makeText(getApplicationContext(), "camera focus set to manual", Toast.LENGTH_SHORT).show();
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initUI();
initListener();
camera = DronifyApplication.getCameraInstance();
camera.getFocusRingValueUpperBound(new CommonCallbacks.CompletionCallbackWith<Integer>() {
@Override
public void onSuccess(Integer integer) {
Toast.makeText(getApplicationContext(), "UPPER IS: " + integer.toString(),Toast.LENGTH_LONG).show();
Log.d(TAG, "UPPER IS: " + integer.toString());
}
@Override
public void onFailure(DJIError djiError) {
Toast.makeText(getApplicationContext(), "UPPER IS NOT SUPPORTED", Toast.LENGTH_LONG).show();
}
});
camera.setFocusMode(SettingsDefinitions.FocusMode.MANUAL, focusSetCompletionCallback);
if (camera.isAdjustableFocalPointSupported()) {
camera.setFocusRingValue(65, new CommonCallbacks.CompletionCallback() {
@Override
public void onResult(DJIError djiError) {
Log.i(TAG, "set focus ring value to max");
Toast.makeText(getApplicationContext(), "set focus ring value to max", Toast.LENGTH_SHORT).show();
}
});
}
Intent intent = new Intent(getApplication(), TCPService.class);
getApplication().startService(intent);
}
@Override
protected void onResume() {
super.onResume();
}
public static boolean isMultiStreamPlatform() {
if (DJISDKManager.getInstance() == null){
return false;
}
Model model = DJISDKManager.getInstance().getProduct().getModel();
return model != null && (model == Model.INSPIRE_2
|| model == Model.MATRICE_200
|| model == Model.MATRICE_210
|| model == Model.MATRICE_210_RTK
|| model == Model.MATRICE_600
|| model == Model.MATRICE_600_PRO
|| model == Model.A3
|| model == Model.N3);
}
private void initUI() {
primaryVideoFeedView = (VideoFeedView) findViewById(R.id.video_view_primary_video_feed);
primaryVideoFeedView.registerLiveVideo(VideoFeeder.getInstance().getPrimaryVideoFeed(), true);
fpvVideoFeedView = (VideoFeedView) findViewById(R.id.video_view_fpv_video_feed);
fpvVideoFeedView.registerLiveVideo(VideoFeeder.getInstance().getSecondaryVideoFeed(), false);
if (isMultiStreamPlatform()){
fpvVideoFeedView.setVisibility(View.VISIBLE);
}
showUrlInputEdit = (EditText) findViewById(R.id.edit_live_show_url_input);
showUrlInputEdit.setText(liveShowUrl);
startLiveShowBtn = (Button) findViewById(R.id.btn_start_live_show);
enableVideoEncodingBtn = (Button) findViewById(R.id.btn_enable_video_encode);
disableVideoEncodingBtn = (Button) findViewById(R.id.btn_disable_video_encode);
stopLiveShowBtn = (Button) findViewById(R.id.btn_stop_live_show);
soundOnBtn = (Button) findViewById(R.id.btn_sound_on);
soundOffBtn = (Button) findViewById(R.id.btn_sound_off);
isLiveShowOnBtn = (Button) findViewById(R.id.btn_is_live_show_on);
showInfoBtn = (Button) findViewById(R.id.btn_show_info);
showLiveStartTimeBtn = (Button) findViewById(R.id.btn_show_live_start_time);
showCurrentVideoSourceBtn = (Button) findViewById(R.id.btn_show_current_video_source);
changeVideoSourceBtn = (Button) findViewById(R.id.btn_change_video_source);
startLiveShowBtn.setOnClickListener(this);
enableVideoEncodingBtn.setOnClickListener(this);
disableVideoEncodingBtn.setOnClickListener(this);
stopLiveShowBtn.setOnClickListener(this);
soundOnBtn.setOnClickListener(this);
soundOffBtn.setOnClickListener(this);
isLiveShowOnBtn.setOnClickListener(this);
showInfoBtn.setOnClickListener(this);
showLiveStartTimeBtn.setOnClickListener(this);
showCurrentVideoSourceBtn.setOnClickListener(this);
changeVideoSourceBtn.setOnClickListener(this);
}
private void initListener() {
showUrlInputEdit.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
liveShowUrl = s.toString();
}
@Override
public void afterTextChanged(Editable s) {
}
});
listener = new LiveStreamManager.OnLiveChangeListener() {
@Override
public void onStatusChanged(int i) {
//Toast.makeText(getApplicationContext(), "status changed : " + i, Toast.LENGTH_SHORT).show();
}
};
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
BaseProduct product = DronifyApplication.getProductInstance();
if (product == null || !product.isConnected()) {
//Toast.makeText(getApplicationContext(), "disconnected", Toast.LENGTH_SHORT).show();
return;
}
if (isLiveStreamManagerOn()){
DJISDKManager.getInstance().getLiveStreamManager().registerListener(listener);
}
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (isLiveStreamManagerOn()){
DJISDKManager.getInstance().getLiveStreamManager().unregisterListener(listener);
}
}
private boolean isLiveStreamManagerOn() {
if (DJISDKManager.getInstance().getLiveStreamManager() == null) {
//Toast.makeText(getApplicationContext(), "no liveStream manager", Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_start_live_show:
startLiveShow();
break;
case R.id.btn_enable_video_encode:
enableReEncoder();
break;
case R.id.btn_disable_video_encode:
disableReEncoder();
break;
case R.id.btn_stop_live_show:
stopLiveShow();
break;
case R.id.btn_sound_on:
soundOn();
break;
case R.id.btn_sound_off:
soundOff();
break;
case R.id.btn_is_live_show_on:
isLiveShowOn();
break;
case R.id.btn_show_info:
showInfo();
break;
case R.id.btn_show_live_start_time:
showLiveStartTime();
break;
case R.id.btn_show_current_video_source:
showCurrentVideoSource();
break;
case R.id.btn_change_video_source:
changeVideoSource();
break;
default:
break;
}
}
private void enableReEncoder() {
if (!isLiveStreamManagerOn()) {
return;
}
DJISDKManager.getInstance().getLiveStreamManager().setVideoEncodingEnabled(true);
Toast.makeText(getApplicationContext(), "Force Re-Encoder Enabled!", Toast.LENGTH_SHORT).show();
}
private void disableReEncoder() {
if (!isLiveStreamManagerOn()) {
return;
}
DJISDKManager.getInstance().getLiveStreamManager().setVideoEncodingEnabled(false);
Toast.makeText(getApplicationContext(), "Disable Force Re-Encoder!", Toast.LENGTH_SHORT).show();
}
private void soundOn() {
if (!isLiveStreamManagerOn()) {
return;
}
DJISDKManager.getInstance().getLiveStreamManager().setAudioMuted(false);
Toast.makeText(getApplicationContext(), "Sound ON", Toast.LENGTH_SHORT).show();
}
private void soundOff() {
if (!isLiveStreamManagerOn()) {
return;
}
DJISDKManager.getInstance().getLiveStreamManager().setAudioMuted(true);
Toast.makeText(getApplicationContext(), "Sound OFF", Toast.LENGTH_SHORT).show();
}
private void isLiveShowOn() {
if (!isLiveStreamManagerOn()) {
return;
}
Toast.makeText(getApplicationContext(), "Is Live Show On:" + DJISDKManager.getInstance().getLiveStreamManager().isStreaming(), Toast.LENGTH_SHORT).show();
}
private void showLiveStartTime() {
if (!isLiveStreamManagerOn()) {
return;
}
if (!DJISDKManager.getInstance().getLiveStreamManager().isStreaming()){
Toast.makeText(getApplicationContext(), "Please Start Live First", Toast.LENGTH_SHORT).show();
return;
}
long startTime = DJISDKManager.getInstance().getLiveStreamManager().getStartTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
String sd = sdf.format(new Date(Long.parseLong(String.valueOf(startTime))));
Toast.makeText(getApplicationContext(), "Live Start Time: " + sd, Toast.LENGTH_SHORT).show();
}
private void changeVideoSource() {
if (!isLiveStreamManagerOn()) {
return;
}
if (!isSupportSecondaryVideo()) {
return;
}
if (DJISDKManager.getInstance().getLiveStreamManager().isStreaming()) {
Toast.makeText(getApplicationContext(), "Before change live source, you should stop live stream!", Toast.LENGTH_SHORT).show();
return;
}
currentVideoSource = (currentVideoSource == LiveStreamManager.LiveStreamVideoSource.Primary) ?
LiveStreamManager.LiveStreamVideoSource.Secoundary :
LiveStreamManager.LiveStreamVideoSource.Primary;
DJISDKManager.getInstance().getLiveStreamManager().setVideoSource(currentVideoSource);
Toast.makeText(getApplicationContext(), "Change Success ! Video Source : " + currentVideoSource.name(), Toast.LENGTH_SHORT).show();
}
private void showCurrentVideoSource(){
Toast.makeText(getApplicationContext(), "Video Source : " + currentVideoSource.name(), Toast.LENGTH_SHORT).show();
}
private boolean isSupportSecondaryVideo(){
if (isMultiStreamPlatform()) {
Toast.makeText(getApplicationContext(), "No secondary video!", Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
private void showInfo() {
StringBuilder sb = new StringBuilder();
sb.append("Video BitRate:").append(DJISDKManager.getInstance().getLiveStreamManager().getLiveVideoBitRate()).append(" kpbs\n");
sb.append("Audio BitRate:").append(DJISDKManager.getInstance().getLiveStreamManager().getLiveAudioBitRate()).append(" kpbs\n");
sb.append("Video FPS:").append(DJISDKManager.getInstance().getLiveStreamManager().getLiveVideoFps()).append("\n");
sb.append("Video Cache size:").append(DJISDKManager.getInstance().getLiveStreamManager().getLiveVideoCacheSize()).append(" frame");
Toast.makeText(getApplicationContext(), sb.toString(), Toast.LENGTH_LONG).show();
}
void startLiveShow() {
Toast.makeText(getApplicationContext(), "start live show: " + isLiveStreamManagerOn(), Toast.LENGTH_SHORT).show();
if (!isLiveStreamManagerOn()) {
Toast.makeText(getApplicationContext(), "1. return", Toast.LENGTH_SHORT).show();
return;
}
if (DJISDKManager.getInstance().getLiveStreamManager().isStreaming()) {
Toast.makeText(getApplicationContext(), "live show already started", Toast.LENGTH_SHORT).show();
return;
}
new Thread() {
@Override
public void run() {
DJISDKManager.getInstance().getLiveStreamManager().setLiveUrl(liveShowUrl);
DJISDKManager.getInstance().getLiveStreamManager().setVideoEncodingEnabled(true);
DJISDKManager.getInstance().getLiveStreamManager().setAudioMuted(false);
final int result = DJISDKManager.getInstance().getLiveStreamManager().startStream();
DJISDKManager.getInstance().getLiveStreamManager().setStartTime();
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(getApplication(), "RESULT: " + result, Toast.LENGTH_SHORT).show();
}
});
}
}.start();
}
private void stopLiveShow() {
if (!isLiveStreamManagerOn()) {
return;
}
DJISDKManager.getInstance().getLiveStreamManager().stopStream();
Toast.makeText(getApplicationContext(), "stop live show", Toast.LENGTH_SHORT).show();
}
}
知道为什么吗?我已经在 Google Pixel 2 和 Huawei Mate 10 上测试过了。示例在两个设备上都没有问题,我的应用程序有延迟。谢谢!
回答我自己的问题,我注意到的唯一区别是 SampleCode 要求 4 个权限,而我尝试或复制权限的所有项目始终只有 3 个权限。
所以清单:
< uses-permission android:name="android.permission.RECORD_AUDIO" />
您的运行时权限:
Manifest.permission.RECORD_AUDIO
延迟消失了,一切正常。仍然不知道为什么:)
我已经使用 DJI SDK 创建了一个 android 应用程序。我已经按照说明进行操作,并且基本上从 DJI 示例代码 (https://github.com/dji-sdk/Mobile-SDK-Android/blob/master/Sample%20Code/app/src/main/java/com/dji/sdk/sample/demo/camera/LiveStreamView.java) 中复制了代码,因为它可以正常工作。
启动连接 activity 后,它注册了 SDK 并连接到 Mavic 2 Zoom 无人机,另一个 activity 来了,它处理到 RTMP 服务器的直播。当使用示例代码流式传输到同一个 RTMP 服务器时,它没有延迟,但是当使用我的应用程序时,它有 15 秒的延迟。我不知道为什么,我使用的是相同的组件。唯一的区别是我将相机焦点设置为最大,但我在示例代码中做了同样的事情,所以它应该不会造成任何问题。还使用与示例中相同的 VideoFeedView。
public class MainActivity extends Activity implements View.OnClickListener {
private static final String TAG = MainActivity.class.getName();
private String liveShowUrl = "rtmp://192.168.00.00/live";
private VideoFeedView primaryVideoFeedView;
private VideoFeedView fpvVideoFeedView;
private EditText showUrlInputEdit;
private Button startLiveShowBtn;
private Button enableVideoEncodingBtn;
private Button disableVideoEncodingBtn;
private Button stopLiveShowBtn;
private Button soundOnBtn;
private Button soundOffBtn;
private Button isLiveShowOnBtn;
private Button showInfoBtn;
private Button showLiveStartTimeBtn;
private Button showCurrentVideoSourceBtn;
private Button changeVideoSourceBtn;
private Camera camera;
private LiveStreamManager.OnLiveChangeListener listener;
private LiveStreamManager.LiveStreamVideoSource currentVideoSource = LiveStreamManager.LiveStreamVideoSource.Primary;
private CommonCallbacks.CompletionCallback focusSetCompletionCallback = new CommonCallbacks.CompletionCallback() {
@Override
public void onResult(DJIError djiError) {
Log.d(TAG, "Camera focus is set to manual");
Toast.makeText(getApplicationContext(), "camera focus set to manual", Toast.LENGTH_SHORT).show();
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initUI();
initListener();
camera = DronifyApplication.getCameraInstance();
camera.getFocusRingValueUpperBound(new CommonCallbacks.CompletionCallbackWith<Integer>() {
@Override
public void onSuccess(Integer integer) {
Toast.makeText(getApplicationContext(), "UPPER IS: " + integer.toString(),Toast.LENGTH_LONG).show();
Log.d(TAG, "UPPER IS: " + integer.toString());
}
@Override
public void onFailure(DJIError djiError) {
Toast.makeText(getApplicationContext(), "UPPER IS NOT SUPPORTED", Toast.LENGTH_LONG).show();
}
});
camera.setFocusMode(SettingsDefinitions.FocusMode.MANUAL, focusSetCompletionCallback);
if (camera.isAdjustableFocalPointSupported()) {
camera.setFocusRingValue(65, new CommonCallbacks.CompletionCallback() {
@Override
public void onResult(DJIError djiError) {
Log.i(TAG, "set focus ring value to max");
Toast.makeText(getApplicationContext(), "set focus ring value to max", Toast.LENGTH_SHORT).show();
}
});
}
Intent intent = new Intent(getApplication(), TCPService.class);
getApplication().startService(intent);
}
@Override
protected void onResume() {
super.onResume();
}
public static boolean isMultiStreamPlatform() {
if (DJISDKManager.getInstance() == null){
return false;
}
Model model = DJISDKManager.getInstance().getProduct().getModel();
return model != null && (model == Model.INSPIRE_2
|| model == Model.MATRICE_200
|| model == Model.MATRICE_210
|| model == Model.MATRICE_210_RTK
|| model == Model.MATRICE_600
|| model == Model.MATRICE_600_PRO
|| model == Model.A3
|| model == Model.N3);
}
private void initUI() {
primaryVideoFeedView = (VideoFeedView) findViewById(R.id.video_view_primary_video_feed);
primaryVideoFeedView.registerLiveVideo(VideoFeeder.getInstance().getPrimaryVideoFeed(), true);
fpvVideoFeedView = (VideoFeedView) findViewById(R.id.video_view_fpv_video_feed);
fpvVideoFeedView.registerLiveVideo(VideoFeeder.getInstance().getSecondaryVideoFeed(), false);
if (isMultiStreamPlatform()){
fpvVideoFeedView.setVisibility(View.VISIBLE);
}
showUrlInputEdit = (EditText) findViewById(R.id.edit_live_show_url_input);
showUrlInputEdit.setText(liveShowUrl);
startLiveShowBtn = (Button) findViewById(R.id.btn_start_live_show);
enableVideoEncodingBtn = (Button) findViewById(R.id.btn_enable_video_encode);
disableVideoEncodingBtn = (Button) findViewById(R.id.btn_disable_video_encode);
stopLiveShowBtn = (Button) findViewById(R.id.btn_stop_live_show);
soundOnBtn = (Button) findViewById(R.id.btn_sound_on);
soundOffBtn = (Button) findViewById(R.id.btn_sound_off);
isLiveShowOnBtn = (Button) findViewById(R.id.btn_is_live_show_on);
showInfoBtn = (Button) findViewById(R.id.btn_show_info);
showLiveStartTimeBtn = (Button) findViewById(R.id.btn_show_live_start_time);
showCurrentVideoSourceBtn = (Button) findViewById(R.id.btn_show_current_video_source);
changeVideoSourceBtn = (Button) findViewById(R.id.btn_change_video_source);
startLiveShowBtn.setOnClickListener(this);
enableVideoEncodingBtn.setOnClickListener(this);
disableVideoEncodingBtn.setOnClickListener(this);
stopLiveShowBtn.setOnClickListener(this);
soundOnBtn.setOnClickListener(this);
soundOffBtn.setOnClickListener(this);
isLiveShowOnBtn.setOnClickListener(this);
showInfoBtn.setOnClickListener(this);
showLiveStartTimeBtn.setOnClickListener(this);
showCurrentVideoSourceBtn.setOnClickListener(this);
changeVideoSourceBtn.setOnClickListener(this);
}
private void initListener() {
showUrlInputEdit.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
liveShowUrl = s.toString();
}
@Override
public void afterTextChanged(Editable s) {
}
});
listener = new LiveStreamManager.OnLiveChangeListener() {
@Override
public void onStatusChanged(int i) {
//Toast.makeText(getApplicationContext(), "status changed : " + i, Toast.LENGTH_SHORT).show();
}
};
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
BaseProduct product = DronifyApplication.getProductInstance();
if (product == null || !product.isConnected()) {
//Toast.makeText(getApplicationContext(), "disconnected", Toast.LENGTH_SHORT).show();
return;
}
if (isLiveStreamManagerOn()){
DJISDKManager.getInstance().getLiveStreamManager().registerListener(listener);
}
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (isLiveStreamManagerOn()){
DJISDKManager.getInstance().getLiveStreamManager().unregisterListener(listener);
}
}
private boolean isLiveStreamManagerOn() {
if (DJISDKManager.getInstance().getLiveStreamManager() == null) {
//Toast.makeText(getApplicationContext(), "no liveStream manager", Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_start_live_show:
startLiveShow();
break;
case R.id.btn_enable_video_encode:
enableReEncoder();
break;
case R.id.btn_disable_video_encode:
disableReEncoder();
break;
case R.id.btn_stop_live_show:
stopLiveShow();
break;
case R.id.btn_sound_on:
soundOn();
break;
case R.id.btn_sound_off:
soundOff();
break;
case R.id.btn_is_live_show_on:
isLiveShowOn();
break;
case R.id.btn_show_info:
showInfo();
break;
case R.id.btn_show_live_start_time:
showLiveStartTime();
break;
case R.id.btn_show_current_video_source:
showCurrentVideoSource();
break;
case R.id.btn_change_video_source:
changeVideoSource();
break;
default:
break;
}
}
private void enableReEncoder() {
if (!isLiveStreamManagerOn()) {
return;
}
DJISDKManager.getInstance().getLiveStreamManager().setVideoEncodingEnabled(true);
Toast.makeText(getApplicationContext(), "Force Re-Encoder Enabled!", Toast.LENGTH_SHORT).show();
}
private void disableReEncoder() {
if (!isLiveStreamManagerOn()) {
return;
}
DJISDKManager.getInstance().getLiveStreamManager().setVideoEncodingEnabled(false);
Toast.makeText(getApplicationContext(), "Disable Force Re-Encoder!", Toast.LENGTH_SHORT).show();
}
private void soundOn() {
if (!isLiveStreamManagerOn()) {
return;
}
DJISDKManager.getInstance().getLiveStreamManager().setAudioMuted(false);
Toast.makeText(getApplicationContext(), "Sound ON", Toast.LENGTH_SHORT).show();
}
private void soundOff() {
if (!isLiveStreamManagerOn()) {
return;
}
DJISDKManager.getInstance().getLiveStreamManager().setAudioMuted(true);
Toast.makeText(getApplicationContext(), "Sound OFF", Toast.LENGTH_SHORT).show();
}
private void isLiveShowOn() {
if (!isLiveStreamManagerOn()) {
return;
}
Toast.makeText(getApplicationContext(), "Is Live Show On:" + DJISDKManager.getInstance().getLiveStreamManager().isStreaming(), Toast.LENGTH_SHORT).show();
}
private void showLiveStartTime() {
if (!isLiveStreamManagerOn()) {
return;
}
if (!DJISDKManager.getInstance().getLiveStreamManager().isStreaming()){
Toast.makeText(getApplicationContext(), "Please Start Live First", Toast.LENGTH_SHORT).show();
return;
}
long startTime = DJISDKManager.getInstance().getLiveStreamManager().getStartTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
String sd = sdf.format(new Date(Long.parseLong(String.valueOf(startTime))));
Toast.makeText(getApplicationContext(), "Live Start Time: " + sd, Toast.LENGTH_SHORT).show();
}
private void changeVideoSource() {
if (!isLiveStreamManagerOn()) {
return;
}
if (!isSupportSecondaryVideo()) {
return;
}
if (DJISDKManager.getInstance().getLiveStreamManager().isStreaming()) {
Toast.makeText(getApplicationContext(), "Before change live source, you should stop live stream!", Toast.LENGTH_SHORT).show();
return;
}
currentVideoSource = (currentVideoSource == LiveStreamManager.LiveStreamVideoSource.Primary) ?
LiveStreamManager.LiveStreamVideoSource.Secoundary :
LiveStreamManager.LiveStreamVideoSource.Primary;
DJISDKManager.getInstance().getLiveStreamManager().setVideoSource(currentVideoSource);
Toast.makeText(getApplicationContext(), "Change Success ! Video Source : " + currentVideoSource.name(), Toast.LENGTH_SHORT).show();
}
private void showCurrentVideoSource(){
Toast.makeText(getApplicationContext(), "Video Source : " + currentVideoSource.name(), Toast.LENGTH_SHORT).show();
}
private boolean isSupportSecondaryVideo(){
if (isMultiStreamPlatform()) {
Toast.makeText(getApplicationContext(), "No secondary video!", Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
private void showInfo() {
StringBuilder sb = new StringBuilder();
sb.append("Video BitRate:").append(DJISDKManager.getInstance().getLiveStreamManager().getLiveVideoBitRate()).append(" kpbs\n");
sb.append("Audio BitRate:").append(DJISDKManager.getInstance().getLiveStreamManager().getLiveAudioBitRate()).append(" kpbs\n");
sb.append("Video FPS:").append(DJISDKManager.getInstance().getLiveStreamManager().getLiveVideoFps()).append("\n");
sb.append("Video Cache size:").append(DJISDKManager.getInstance().getLiveStreamManager().getLiveVideoCacheSize()).append(" frame");
Toast.makeText(getApplicationContext(), sb.toString(), Toast.LENGTH_LONG).show();
}
void startLiveShow() {
Toast.makeText(getApplicationContext(), "start live show: " + isLiveStreamManagerOn(), Toast.LENGTH_SHORT).show();
if (!isLiveStreamManagerOn()) {
Toast.makeText(getApplicationContext(), "1. return", Toast.LENGTH_SHORT).show();
return;
}
if (DJISDKManager.getInstance().getLiveStreamManager().isStreaming()) {
Toast.makeText(getApplicationContext(), "live show already started", Toast.LENGTH_SHORT).show();
return;
}
new Thread() {
@Override
public void run() {
DJISDKManager.getInstance().getLiveStreamManager().setLiveUrl(liveShowUrl);
DJISDKManager.getInstance().getLiveStreamManager().setVideoEncodingEnabled(true);
DJISDKManager.getInstance().getLiveStreamManager().setAudioMuted(false);
final int result = DJISDKManager.getInstance().getLiveStreamManager().startStream();
DJISDKManager.getInstance().getLiveStreamManager().setStartTime();
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(getApplication(), "RESULT: " + result, Toast.LENGTH_SHORT).show();
}
});
}
}.start();
}
private void stopLiveShow() {
if (!isLiveStreamManagerOn()) {
return;
}
DJISDKManager.getInstance().getLiveStreamManager().stopStream();
Toast.makeText(getApplicationContext(), "stop live show", Toast.LENGTH_SHORT).show();
}
}
知道为什么吗?我已经在 Google Pixel 2 和 Huawei Mate 10 上测试过了。示例在两个设备上都没有问题,我的应用程序有延迟。谢谢!
回答我自己的问题,我注意到的唯一区别是 SampleCode 要求 4 个权限,而我尝试或复制权限的所有项目始终只有 3 个权限。
所以清单:
< uses-permission android:name="android.permission.RECORD_AUDIO" />
您的运行时权限:
Manifest.permission.RECORD_AUDIO
延迟消失了,一切正常。仍然不知道为什么:)