locked
Synchronizing two ppl task on Windows 8 metro app

    Question


  • This is metro camera app from msdn. This code is to show preview from the camera.here list of camera will be displayed in the combo box.user can select the camera to see the preview of the selected camera,but when i change the camera it first release the resource and than start the preview of the selected camera.since release process is asynchronous process and it runs in the background, so before releasing, it starts the preview of selected camera and in the mean time release delete the "m_MediaCaptureMgr" pointer and program crashes.

    In Win 32 I can use waitforSingle object to synchronize it.I wanted to know how best I can synchronize in WinRT and ppl task.

    void CameraApp::MainPage::cmbCameraSelector_SelectionChanged(Platform::Object^ sender,  Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e)
    {
    if(m_DeviceVector.size() > 0)
    {
        m_CaptureInitSettings->VideoDeviceId = m_DeviceVector[cmbCameraSelector->SelectedIndex]->Id;
        InitMediaCapture();
    }
    }

    void CameraApp::MainPage::InitMediaCapture()
    {
    ReleaseMediaCapture();

    //Sleep(3000);
    auto _this = this;
    m_MediaCaptureMgr = ref new MediaCapture();

    task<void> stratPreview(m_MediaCaptureMgr->InitializeAsync(m_CaptureInitSettings));
    stratPreview.then([_this]
    {
        _this->previewElement->Source = _this->m_MediaCaptureMgr;
        task<void> startPrev(_this->m_MediaCaptureMgr->StartPreviewAsync());
        startPrev.then([=]
        {

            return _this->GetCameraSettings();
        });     
    });

    }    
    void CameraApp::MainPage::ReleaseMediaCapture()
    {
    if (m_MediaCaptureMgr )
    {
        auto prevOp = m_MediaCaptureMgr->StopPreviewAsync();
        task<void> releaseMediaCapture(m_MediaCaptureMgr->StopPreviewAsync());
        releaseMediaCapture.then([=]
        {
            m_MediaCaptureMgr = nullptr;
            bRelease = false;
        });
    }
    }
    Thursday, September 6, 2012 12:45 PM

Answers

  • I came with this solution working fine with my case

    if (m_MediaCaptureMgr )
    {
    task<void> releaseMediaCapture(m_MediaCaptureMgr->StopPreviewAsync());
    releaseMediaCapture.then([=]
    {
    m_MediaCaptureMgr = nullptr;
    bRelease = false;
    auto _this = this;
    m_MediaCaptureMgr = ref new MediaCapture();

    task<void> stratPreview(m_MediaCaptureMgr->InitializeAsync(m_CaptureInitSettings));
    stratPreview.then([_this]
    {
    _this->previewElement->Source = _this->m_MediaCaptureMgr;
    task<void> startPrev(_this->m_MediaCaptureMgr->StartPreviewAsync());
    startPrev.then([=]
    {

    return _this->GetCameraSettings();
    });
    });
    });
    }
    else
    {
    auto _this = this;
    m_MediaCaptureMgr = ref new MediaCapture();

    task<void> stratPreview(m_MediaCaptureMgr->InitializeAsync(m_CaptureInitSettings));
    stratPreview.then([_this]
    {
    _this->previewElement->Source = _this->m_MediaCaptureMgr;
    task<void> startPrev(_this->m_MediaCaptureMgr->StartPreviewAsync());
    startPrev.then([=]
    {

    return _this->GetCameraSettings();
    });
    });

    }

    • Marked as answer by Jesse Jiang Monday, September 10, 2012 10:59 AM
    Monday, September 10, 2012 10:35 AM

All replies

  • Perhaps you can use continuations, something like this (not directly compilable):

    void CameraApp::MainPage::InitMediaCapture()
    {
        auto prevOp = m_MediaCaptureMgr->StopPreviewAsync();
        task<void> releaseMediaCapture(m_MediaCaptureMgr->StopPreviewAsync());
        releaseMediaCapture.then([=](task<void> t) -> task<void>
        {
            m_MediaCaptureMgr = nullptr;
            bRelease = false;
            auto _this = this;
            m_MediaCaptureMgr = ref new MediaCapture();
            return create_task(m_MediaCaptureMgr->InitializeAsync(m_CaptureInitSettings));
        }).then([](task<void> t) -> task<void>
        {
            _this->previewElement->Source = _this->m_MediaCaptureMgr;
            return create_task(m_MediaCaptureMgr->StartPreviewAsync());
        }).then([this](task<void> t) {
            try
            {
                t.get();
            }
            catch (Platform::COMException^ e)
            {	
                HandleException ( e );
            }
        });
    }


    Thursday, September 6, 2012 6:43 PM
  • 1. You can use task chain of ppltask for maintaining the sequence of your task. See Asynchronous programming in C++

    2. You can also use waitforSingleEx, CreateEventEx for synchronizing it in WinRT like as win32.

    3. You can use wait() function of ppltask for synchronizing it. like following code snapped..

    create_task( your_task ) .then( [] (){

    // Some code

    }).then([] (task<void> previousTask) {

               try
                {
                    previousTask.get();
                   //Success
                }
                catch(Exception^ e)
                {
                    //Failed
                }

    }).wait();

    Note: In case of 2 and 3 you must have run it in a separate worker thread, because UI thread does not allow any kind of wait or blocking.

    Monday, September 10, 2012 8:46 AM
  • Perhaps you can use continuations, something like this (not directly compilable):

    void CameraApp::MainPage::InitMediaCapture()
    {
        auto prevOp = m_MediaCaptureMgr->StopPreviewAsync();
        task<void> releaseMediaCapture(m_MediaCaptureMgr->StopPreviewAsync());
        releaseMediaCapture.then([=](task<void> t) -> task<void>
        {
            m_MediaCaptureMgr = nullptr;
            bRelease = false;
            auto _this = this;
            m_MediaCaptureMgr = ref new MediaCapture();
            return create_task(m_MediaCaptureMgr->InitializeAsync(m_CaptureInitSettings));
        }).then([](task<void> t) -> task<void>
        {
            _this->previewElement->Source = _this->m_MediaCaptureMgr;
            return create_task(m_MediaCaptureMgr->StartPreviewAsync());
        }).then([this](task<void> t) {
            try
            {
                t.get();
            }
            catch (Platform::COMException^ e)
            {	
                HandleException ( e );
            }
        });
    }


    Thanks Gary! this will work on scenario when one switch between the camera,since preview of previous camera need to be stopped before starting with selected camera. It doesn't work for the first time when we launch the app at that time there is no previous preview operation.
    Monday, September 10, 2012 10:22 AM
  • I came with this solution working fine with my case

    if (m_MediaCaptureMgr )
    {
    task<void> releaseMediaCapture(m_MediaCaptureMgr->StopPreviewAsync());
    releaseMediaCapture.then([=]
    {
    m_MediaCaptureMgr = nullptr;
    bRelease = false;
    auto _this = this;
    m_MediaCaptureMgr = ref new MediaCapture();

    task<void> stratPreview(m_MediaCaptureMgr->InitializeAsync(m_CaptureInitSettings));
    stratPreview.then([_this]
    {
    _this->previewElement->Source = _this->m_MediaCaptureMgr;
    task<void> startPrev(_this->m_MediaCaptureMgr->StartPreviewAsync());
    startPrev.then([=]
    {

    return _this->GetCameraSettings();
    });
    });
    });
    }
    else
    {
    auto _this = this;
    m_MediaCaptureMgr = ref new MediaCapture();

    task<void> stratPreview(m_MediaCaptureMgr->InitializeAsync(m_CaptureInitSettings));
    stratPreview.then([_this]
    {
    _this->previewElement->Source = _this->m_MediaCaptureMgr;
    task<void> startPrev(_this->m_MediaCaptureMgr->StartPreviewAsync());
    startPrev.then([=]
    {

    return _this->GetCameraSettings();
    });
    });

    }

    • Marked as answer by Jesse Jiang Monday, September 10, 2012 10:59 AM
    Monday, September 10, 2012 10:35 AM