DJI SDK LiveStreamManager -3 Error: Failed to Start Stream
Hi all,
I'm working on a project using the DJI Mobile SDK V4 to stream live video from a drone to an RTMP server. Despite receiving video data consistently, I get a -3 error when trying to start the live stream via LiveStreamManager.startStream().
What I tried:
- I verified that video data is indeed being received from the drone.
- My RTMP server works because I tried streaming my mobile's camera feed.
- I enabled encoding with setVideoEncodingEnabled(true).
Below are the key parts of my code. The VideoFeedView is taken from the sample code
1. Drone Live Stream Manager
class DroneLiveStreamManager(private val primaryVideoFeedView: VideoFeedView) {
private val maxRetries = 10
private val retryDelay = 1000L // 1 second delay for retrying
// Initialize and set up the live stream manager
fun initLiveStream(retryCount: Int = 0) {
if (DJISDKManager.getInstance().getLiveStreamManager() == null) {
if (retryCount < maxRetries) {
Log.w(TAG, "LiveStreamManager is not available yet, retrying in ${retryDelay / 1000} seconds...")
Handler(Looper.getMainLooper()).postDelayed({
initLiveStream(retryCount + 1) // Retry after delay
}, retryDelay)
} else {
Log.e(TAG, "LiveStreamManager initialization failed after multiple retries.")
}
return
}
// Proceed with initialization once LiveStreamManager is available
primaryVideoFeedView.registerLiveVideo(VideoFeeder.getInstance().primaryVideoFeed, true)
DJISDKManager.getInstance().getLiveStreamManager().setVideoEncodingEnabled(true)
DJISDKManager.getInstance().getLiveStreamManager().setVideoSource(LiveStreamManager.LiveStreamVideoSource.Primary)
DJISDKManager.getInstance().getLiveStreamManager().addLiveErrorStatusListener { errorCode, errorMessage ->
Log.d(TAG, "Streaming error: Code $errorCode, Message: $errorMessage")
}
DJISDKManager.getInstance().getLiveStreamManager().registerListener(object : LiveStreamManager.OnLiveChangeListener {
override fun onStatusChanged(status: Int) {
Log.d(TAG, "Live stream status changed: $status")
}
})
Log.d(TAG, "Live stream manager initialized with RTMP URL.")
}
fun startLiveStream() {
if (DJISDKManager.getInstance().getLiveStreamManager()?.isStreaming == false) {
Thread {
// Set the live URL immediately before starting the stream
DJISDKManager.getInstance().getLiveStreamManager().setLiveUrl("rtmp://192.168.0.32:1935/live/test")
val result = DJISDKManager.getInstance().getLiveStreamManager().startStream()
DJISDKManager.getInstance().getLiveStreamManager().setStartTime()
Log.d(TAG, "startStream result: $result")
if (result == 0) {
Log.d(TAG, "Stream started successfully")
} else {
Log.e(TAG, "Failed to start stream, error code: $result")
}
}.start()
} else {
Log.d(TAG, "Stream already active or LiveStreamManager not available")
}
}
fun stopLiveStream() {
val liveStreamManager = DJISDKManager.getInstance().liveStreamManager
if (liveStreamManager?.isStreaming == true) {
liveStreamManager.stopStream()
Log.d(TAG, "Stopped live stream")
} else {
Log.d(TAG, "Stream is not active or LiveStreamManager not available")
}
}
}
2. Initializing Live Stream Manager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.d(TAG, "MainActivity created")
// Initialize the handler
mHandler = Handler(Looper.getMainLooper())
// Initialize videoFeedView after setting the content view
videoFeedView = findViewById(R.id.video_feed_view)
// Initialize the DroneLiveStreamManager
droneLiveStreamManager = DroneLiveStreamManager(videoFeedView)
// Check and request permissions if necessary
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkAndRequestPermissions()
}
// Call the dialog to prompt the user for Simulation or Normal Mode
showModeSelectionDialog()
}
3. Calling the StartLiveStream()
private fun showModeSelectionDialog() {
val builder = AlertDialog.Builder(this)
builder.setTitle("Select Mode")
builder.setMessage("Do you want to use Simulation Mode or Normal Mode?")
builder.setPositiveButton("Simulation Mode") { _, _ ->
Log.d(TAG, "User selected Simulation Mode")
// Start the live stream
droneLiveStreamManager.startLiveStream()
}
builder.setNegativeButton("Normal Mode") { _, _ ->
Log.d(TAG, "User selected Normal Mode")
showToast("Normal Mode selected. Attempting to connect to GPS if available.")
// Start the live stream
droneLiveStreamManager.startLiveStream()
}
builder.setCancelable(false)
builder.show()
}
4. Error I get:
Failed to start stream, error code: -3
Agent comment from yating.liao in Zendesk ticket #120889:
It appears that initLiveStream has not been utilized. The -3 often indicates that the corresponding screen is not displayed on the current page.
https://sdk-forum.dji.net/hc/en-us/articles/360046826494
°°°
Thank you for your response!
On the link you sent me, it says that I should use DJICodecManager to decode. This is already used though by the VIdeoFeedView which I copied and pasted on my project.
Here is the link of my project: https://github.com/George2397/drone_telemetry_android
Regarding the initLiveStream, I forgot to paste the code that calls this.
override fun onProductConnect(product: BaseProduct?) {
Log.d(TAG, "onProductConnect called with product: $product")
if (product != null) {
Log.d(TAG, "Connected product model: ${product.model}")
// Initialize live stream manager after product is connected
droneLiveStreamManager.initLiveStream()
} else {
Log.w(TAG, "No product detected on connection.")
}
showToast("Remote Controller Connected")
notifyStatusChange()
}
And here is the link to the file: https://github.com/George2397/drone_telemetry_android/blob/main/app/src/main/java/com/example/sample/MainActivity.kt
Agent comment from yating.liao in Zendesk ticket #120889:
I think you can retrieve the LiveStreamManager in the onComponentChange function. The onComponentChange will callback the component information when the camera and flight control components are detected. At this point, you should complete primaryVideoFeedView.registerLiveVideo. It's important to note that the live stream can only be started after the camera feed is displayed on primaryVideoFeedView.
Currently, I haven't found any obvious logical errors in the code you provided, but executing primaryVideoFeedView.registerLiveVideo in onProductConnect might cause the camera feed to not display correctly.
°°°