Code Monkey home page Code Monkey logo

Comments (27)

dji-dev avatar dji-dev commented on July 17, 2024 1

Agent comment from yating.liao in Zendesk ticket #110093:

1. Do I need to disable MediaManager if I want to take photos again? -- Yes. After exiting the playback mode, you can take photos.
2. Do I need to call pullMediaFileListFromCamera again, if I disabled MediaManager? -- No.The file list will update automatically, even if you disable MediaManager.
3. Does MediaDataCenter.getInstance().mediaManager.mediaFileListData updates by itself or I need to call pullMedia again. -- Yes, it will update automatically. The file list status UP_TO_DATE indicates that the update is complete.

°°°

from mobile-sdk-android-v5.

dji-lyt avatar dji-lyt commented on July 17, 2024 1

@antonymarion We can discuss under the issue you created, which will continue to track the problem with @IakovlevAA .

from mobile-sdk-android-v5.

antonymarion avatar antonymarion commented on July 17, 2024

Why are you putting sleeping timer and not using (nesting your code) into success callback instead ?

For instance enable is followed by sleep, why don't you put the code after the sleep into the success callback of enable instead ?

from mobile-sdk-android-v5.

IakovlevAA avatar IakovlevAA commented on July 17, 2024

I think I'll try your method, but theoretically I don't need to nest it because for example:

MediaDataCenter.getInstance().mediaManager.enable(object :
            CommonCallbacks.CompletionCallback {
            override fun onSuccess() {
                var currentTime = System.currentTimeMillis()
                MediaDataCenter.getInstance().mediaManager.pullMediaFileListFromCamera(
                    PullMediaFileListParam.Builder().mediaFileIndex(-1).count(-1).filter(MediaFileFilter.PHOTO).build(),
                    object :
                        CommonCallbacks.CompletionCallback {
                        override fun onSuccess() {
                            ToastUtils.showToast("Spend time:${(System.currentTimeMillis() - currentTime) / 1000}s")
                            println("fetch success")
                            mediafiles = MediaDataCenter.getInstance().mediaManager.mediaFileListData.data
                        }
        
                        override fun onFailure(error: IDJIError) {
                            ToastUtils.showToast("fetch failed$error")
                        }
                    })
            }

            override fun onFailure(error: IDJIError) {
                ToastUtils.showToast("error is ${error.description()}")
            }
        })

This code, if I understood you, doesn't look correct to me...

from mobile-sdk-android-v5.

antonymarion avatar antonymarion commented on July 17, 2024

This code is correct, this is kind of callback hell (will lead to nested callback inside nested callback and so on), but it is the correct way to handle asynchronous execution.

Promise Like with await/async is much better to read: https://kotlinlang.org/docs/composing-suspending-functions.html#concurrent-using-async

https://kotlinlang.org/docs/async-programming.html

from mobile-sdk-android-v5.

IakovlevAA avatar IakovlevAA commented on July 17, 2024

Thanks for tips! Interesting what others think about it. I'm just 100% confident, that there is another way, but not nesting callbacks

from mobile-sdk-android-v5.

antonymarion avatar antonymarion commented on July 17, 2024

Yes async await as explained in the docs above.

Callback is error prone and not maintanable.

Promise with then is better for maintenance.

Async await is the best option

from mobile-sdk-android-v5.

antonymarion avatar antonymarion commented on July 17, 2024

By the way, I tested right now (removing all the timers) I have no issue of slow down like you have, I believe that your timer does not help..

from mobile-sdk-android-v5.

IakovlevAA avatar IakovlevAA commented on July 17, 2024

Do you mean slow down of fetching mediafiles or pulling image? Without timers I couldn't get code to work at all

from mobile-sdk-android-v5.

IakovlevAA avatar IakovlevAA commented on July 17, 2024

As Antony mentioned, I tried nesting callbacks. Also I found, that if you call CameraKey.KeyStartShootPhoto.create().action() and after that trying to do something with MediaDataCenter or MediaManager it will process comands a very long time(enabling will always fail btw). So, that was the reason why fetching and downloading was too slow

from mobile-sdk-android-v5.

antonymarion avatar antonymarion commented on July 17, 2024

Call enabling with MediaManager instead.

It will work then

from mobile-sdk-android-v5.

IakovlevAA avatar IakovlevAA commented on July 17, 2024

No, still failing with this code

fun takePhoto(callback: CommonCallbacks.CompletionCallback) {
        RxUtil.setValue(
            KeyTools.createKey<CameraMode>(
                CameraKey.KeyCameraMode
            ), CameraMode.PHOTO_NORMAL)
            .andThen(RxUtil.performActionWithOutResult(KeyTools.createKey(CameraKey.KeyStartShootPhoto)))
            .subscribe({ CallbackUtils.onSuccess(callback) }
            ) { throwable: Throwable ->
                CallbackUtils.onFailure(
                    callback,
                    (throwable as RxError).djiError
                )
            }
    }
    
    fun shootPhoto()
    {
  

        takePhoto(object : CommonCallbacks.CompletionCallback {
            override fun onSuccess() {
                ToastUtils.showToast("take photo success")
                var currentTime = System.currentTimeMillis()
                MediaManager.getInstance().enable(object :
                    CommonCallbacks.CompletionCallback {
                    override fun onSuccess() {
                        ToastUtils.showToast("enable playback success")
                        val mediaSource = MediaFileListDataSource.Builder().setLocation(CameraStorageLocation.SDCARD).build()
                        MediaDataCenter.getInstance().mediaManager.setMediaFileDataSource(mediaSource)
                        MediaDataCenter.getInstance().mediaManager.pullMediaFileListFromCamera(
                            PullMediaFileListParam.Builder().mediaFileIndex(-1).count(-1).filter(MediaFileFilter.PHOTO).build(),
                            object :
                                CommonCallbacks.CompletionCallback {
                                override fun onSuccess() {
                                    ToastUtils.showToast("Spend time:${(System.currentTimeMillis() - currentTime) / 1000}s")
                                    println("fetch success")
                                    mediafiles = MediaDataCenter.getInstance().mediaManager.mediaFileListData.data
                                    downloadFile()
                                }
        
                                override fun onFailure(error: IDJIError) {
                                    ToastUtils.showToast("fetch failed$error")
                                }
                            })
                    }
        
                    override fun onFailure(error: IDJIError) {
                        ToastUtils.showToast("error is ${error.description()}")
                    }
                })
                    }
        
                    override fun onFailure(error: IDJIError) {
                        ToastUtils.showToast("take photo failed")
                    }
                })
    }

Noticed that there is an error with this code

java.lang.NoClassDefFoundError: Failed resolution of: Ldji/v5/common/callback/CommonCallbacks$CompletionCallback;

But if I insert this code in begining of function shootPhoto

if(CameraKey.KeyIsShootingPhoto.create().get() == true)
{
          CameraKey.KeyStopShootPhoto.create().action()     
}

MediaManager won't be enabled

from mobile-sdk-android-v5.

antonymarion avatar antonymarion commented on July 17, 2024

Weird.

Working on my side, I use 300 RTK for testing

If ever you do not find with the official DJI support then go to my profile page and take the $50 sponsor I will give you support.

from mobile-sdk-android-v5.

IakovlevAA avatar IakovlevAA commented on July 17, 2024

Tried another approach:

fun pullMedia()
    {
        var currentTime = System.currentTimeMillis()
        MediaManager.getInstance().enable(object :
            CommonCallbacks.CompletionCallback {
            override fun onSuccess() {
                ToastUtils.showToast("enable playback success")
                val mediaSource = MediaFileListDataSource.Builder().setLocation(CameraStorageLocation.SDCARD).build()
                MediaDataCenter.getInstance().mediaManager.setMediaFileDataSource(mediaSource)
                MediaDataCenter.getInstance().mediaManager.pullMediaFileListFromCamera(
                    PullMediaFileListParam.Builder().mediaFileIndex(-1).count(-1).filter(MediaFileFilter.PHOTO).build(),
                    object :
                        CommonCallbacks.CompletionCallback {
                        override fun onSuccess() {
                            ToastUtils.showToast("Spend time:${(System.currentTimeMillis() - currentTime) / 1000}s")
                            println("fetch success")
                            mediafiles = MediaDataCenter.getInstance().mediaManager.mediaFileListData.data
                        }

                        override fun onFailure(error: IDJIError) {
                            ToastUtils.showToast("fetch failed$error")
                        }
                    })
            }

            override fun onFailure(error: IDJIError) {
                ToastUtils.showToast("error is ${error.description()}")
            }
        })

    }


fun shootPhoto(): ByteArray {
        rotateCamera()

        KeyManager.getInstance().performAction(KeyTools.createKey(CameraKey.KeyResetCameraSetting), object: CommonCallbacks.CompletionCallbackWithParam<EmptyMsg>{
            override fun onSuccess(t: EmptyMsg?) {
                ToastUtils.showToast("reset photo success")
                KeyManager.getInstance().performAction(KeyTools.createKey(CameraKey.KeyStartShootPhoto), object: CommonCallbacks.CompletionCallbackWithParam<EmptyMsg>{
                    override fun onSuccess(t: EmptyMsg?) {
                        ToastUtils.showToast("take photo success")
                        pullMedia()
                    }

                    override fun onFailure(error: IDJIError) {
                        ToastUtils.showToast("take photo failed $error")
                    }
                })
    }

            override fun onFailure(error: IDJIError) {
                ToastUtils.showToast("reset photo failed $error")
            }
        })

First shoot is ok, but after that CameraKey.KeyStartShootPhoto returns CANNOT_START_TASK_VLOTAGE_ALARM error. I've read that I must set camera mode, but it doesn't help

from mobile-sdk-android-v5.

dji-dev avatar dji-dev commented on July 17, 2024

Agent comment from yating.liao in Zendesk ticket #110093:

I have reviewed your code. After switching the camera mode, you directly take a photo and then use mediaManager to retrieve the information. The sequence is correct, but we need to consider the time required for the camera to switch modes and generate the photo.

I would recommend adjusting your code according to this logic:

  1. Listen for changes in KeyCameraMode to determine when the camera has completed the mode switch. The success of setValue only indicates that the camera has successfully received the command.
  2. Add a MediaFileListStateListener to monitor the status of media files. After taking a photo, the camera will generate the corresponding file, and the file list status can indicate whether the camera has completed writing the file. UP_TO_DATE indicates that the file list is up to date, and you can directly retrieve the latest file type using getMediaFileListData. Typically, the latest photo is placed first. It is worth to noting that you need to call pullMediaFileListFromCamera at least once to initialize the listener and file list.
  3. Before downloading the file, use MediaManager.getInstance().enable to put the camera into playback mode. You can use CameraKey.KeyIsPlayingBack to determine if it is in playback mode.

    °°°

from mobile-sdk-android-v5.

IakovlevAA avatar IakovlevAA commented on July 17, 2024

Thanks, I'll try this. I have some questions:

  1. Do I need to disable MediaManager if I want to take photos again?
  2. Do I need to call pullMediaFileListFromCamera again, if I disabled MediaManager?
  3. Does MediaDataCenter.getInstance().mediaManager.mediaFileListData updates by itself or I need to call pullMedia again

from mobile-sdk-android-v5.

antonymarion avatar antonymarion commented on July 17, 2024

Agent comment from yating.liao in Zendesk ticket #110093:I have reviewed your code. After switching the camera mode, you directly take a photo and then use mediaManager to retrieve the information. The sequence is correct, but we need to consider the time required for the camera to switch modes and generate the photo.

I would recommend adjusting your code according to this logic:

  1. Listen for changes in KeyCameraMode to determine when the camera has completed the mode switch. The success of setValue only indicates that the camera has successfully received the command.
  2. Add a MediaFileListStateListener to monitor the status of media files. After taking a photo, the camera will generate the corresponding file, and the file list status can indicate whether the camera has completed writing the file. UP_TO_DATE indicates that the file list is up to date, and you can directly retrieve the latest file type using getMediaFileListData. Typically, the latest photo is placed first. It is worth to noting that you need to call pullMediaFileListFromCamera at least once to initialize the listener and file list.
  3. Before downloading the file, use MediaManager.getInstance().enable to put the camera into playback mode. You can use CameraKey.KeyIsPlayingBack to determine if it is in playback mode.
    °°°

Just to make sure, you said "Listen for changes in KeyCameraMode", but, is it necessary to listen if we can simply use RxUtil.setValue to cameraMode PHOTO_NORMAL and chain the promise using andThen instead ?

Normally, if the Promise is returned after the CameraMode has resolved, it should already be in the right state to take the Photo. So, no need to create a dedicated listener for this, right?

from mobile-sdk-android-v5.

IakovlevAA avatar IakovlevAA commented on July 17, 2024

Thanks, it helped a lot! Yet, one another question: Is it necessary to enter playaback mode to download photos? As I can see, I can enable MediaManager, start pulling photos and as it updates without MediaManager, I can just look for photo by its index. So, in short - does pullOriginalMediaFileFromCamera need playback mode enabled?

from mobile-sdk-android-v5.

antonymarion avatar antonymarion commented on July 17, 2024

And please do not forget my question about chained promises using RxUtil setValue.

It is quite critical to know if we can rely on promises in DJI's SDK or if we have to set listeners and trigger some logic on events received instead, as you proposed...

from mobile-sdk-android-v5.

dji-dev avatar dji-dev commented on July 17, 2024

Agent comment from yating.liao in Zendesk ticket #110093:

Do you mean if the callback result of the SDK interface can be used as the result for the next step in RxUtil? I would recommend using the listeners provided by the SDK as the callback result of the SDK interface does not represent the execution result of the drone. This is also the approach that Mobile SDK has always taken.

°°°

from mobile-sdk-android-v5.

antonymarion avatar antonymarion commented on July 17, 2024

Well, it answers to my question, but the fact that "this is also the approach that Mobile SDK has always taken." is not a justification if you place yourself at the users' perspective.

You said "the callback result of the SDK interface does not represent the execution result of the drone".
So it confirms what I noticed and did not expect from an SDK. But I prefered to be sure and to have your confirmation.

Do you believe the DJI's SDK will handle callback/promises as expected in a near future?

Promise or Callback are designed to be chained, and if it is not possible with DJI's SDK then it is a design flaw inside the SDK.

from mobile-sdk-android-v5.

IakovlevAA avatar IakovlevAA commented on July 17, 2024

Tried method with listening mediaFileListState. I come to a problem with pullMedia. When drone starts and I take photo mediaFileListState becomes UPDATING permanently, and this changes only if I call pullMedia once again or takePhoto. Also my question was left without answer....
does pullOriginalMediaFileFromCamera or pullPreviewFromCamera need playback mode enabled?

from mobile-sdk-android-v5.

dji-dev avatar dji-dev commented on July 17, 2024

Agent comment from yating.liao in Zendesk ticket #110093:

Is the latest version of MSDK being used by you? This issue was present in earlier versions, but it has been fixed in the new version.

°°°

from mobile-sdk-android-v5.

IakovlevAA avatar IakovlevAA commented on July 17, 2024

yes, just tried in Sample app. In Widget tool -> Media Playback -> take photo. State is UPDATING, until I push fetch media. Also found, if I take photo and immediately push enable(Media Manager), state is stucked in Updating, until new photo is taken

from mobile-sdk-android-v5.

IakovlevAA avatar IakovlevAA commented on July 17, 2024

My goal is to download photo as soon as it was taken. Right now I'm struggling with strange behaviour

  1. Take photo with RxUtil (sometimes failing with REQUEST_HANDLER_NOT_FOUND, reason - unknown)
  2. Start pulling the exact photo I've taken with CameraKey.KeyNewlyGeneratedMediaFile.create().get()?.index
val index = CameraKey.KeyNewlyGeneratedMediaFile.create().get()?.index ?: -1
val count = if(index == -1) -1 else 1
val mediaSource = MediaFileListDataSource.Builder().setLocation(CameraStorageLocation.SDCARD).build()
        MediaDataCenter.getInstance().mediaManager.setMediaFileDataSource(mediaSource)
        MediaDataCenter.getInstance().mediaManager.pullMediaFileListFromCamera(
            PullMediaFileListParam.Builder().mediaFileIndex(index).count(count).filter(MediaFileFilter.PHOTO).build(), object : CommonCallbacks.CompletionCallback {
                override fun onSuccess() {
                    cameraStateActivity.postValue("Pull media success")
                }

                override fun onFailure(error: IDJIError) {
                    cameraStateActivity.postValue("fetch failed ${error.description()}")
                    errorHappened = true
                }
            })

This called once fileListState is IDLE
3. Once mediaFileList is updated I'm enabling MediaManager

if (mediaFileListState == MediaFileListState.UP_TO_DATE)
            {
                MediaDataCenter.getInstance().mediaManager.stopPullMediaFileListFromCamera()
                val data = MediaDataCenter.getInstance().mediaManager.mediaFileListData;
                mediaFileListData.postValue(data)
                 MediaManager.getInstance().enable(object :
                  CommonCallbacks.CompletionCallback {
                  override fun onSuccess()
                  {
                      downloadFile()
                  }
      
                  override fun onFailure(error: IDJIError) {
                      println("$error")
                  }
              })
            }

P.S On this stage after taking photo may never ends, and so mediaFileListState is UPDATING permanently
4. Call mediaFile.pullPreviewFromCamera on mediaFile I pulled
Sometimes, pulling just don't work and it pull old photos or never pull at all.
You can reproduce the same in Sample App, by tapping buttons very fast(take photo->fetch media->enable). FileState will stuck in infite update

from mobile-sdk-android-v5.

dji-dev avatar dji-dev commented on July 17, 2024

Agent comment from yating.liao in Zendesk ticket #110093:

The MediaManager.getInstance().enable method puts the camera into playback mode. In playback mode, it is not possible to take photos. The take photo interface will instead callback a photo capture failure, rather than continuously attempting to capture a photo.

It seems illogical to use the take photo interface without confirming the result of enabling MediaManager first.

°°°

from mobile-sdk-android-v5.

IakovlevAA avatar IakovlevAA commented on July 17, 2024

I do understand, that it is impossible to take photos while MediaManager is enabled. What I'm trying to show, that too fast switch between take photo and enable MediaManager causes troubles (even if I check that camera stopped shooting photo).
Right now I achieved my goal to download photo with this steps
Take photo -> sleep(5000) -> enable MediaManager -> wait for camera to enter playback mode -> pullMedia with index I got in CameraKey.KeyNewlyGeneratedMediaFile -> disable MediaManager(because in playback mode filestate stuck in infinite UPDATE) -> Wait for filestate to enter UP_TO_DATE -> enable MediaManager -> stopPullMediaFileListFromCamera -> download photo with mediaFile.pullPreviewFromCamera -> disable MediaManager
Only this method works for me. Listening for states or anything else mentioned in this always caused different problems, that I mentioned above. Closing this as I am pleased with results I've got

from mobile-sdk-android-v5.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.