Windows Phone Camera Preview Deadlock when leaving page.

 

I recently investigated a Windows Phone problem, reported by one of our forum contributors, in which an application encounters a dead-lock scenario when navigating away from a page which is rendering a preview stream from the camera. I found that the deadlock condition was triggered when the VideoBrush object was disposed on the UI thread while still processing a PreviewFrameAvailable event on a different thread.

In an attempt to work around this issue and prevent the deadlock I first used the PreviewFrameAvailable event as a gate for

enabling the navigation menus. I was thinking that it was just a matter of switching too soon after starting, but this was not enough.

I next added code to clear the "SourceName" property from the videoBrush object before disposing the camera Device in order to ensure that the videoBrush was no longer listening for PreviewFrameAvailable events when the destructor was called. This change appears to reliably prevent the dead-lock as I was no longer able to reproduce the problem on my test device even after extended testing.

The following are the changes I made to the CameraExplorer sample: https://github.com/nokia-developer/camera-explorer

1) In “OnNavigatedTo” I added a hook for PreviewFrameAvailable event and commented out the calls to enable menu items:

  1: numFrames = 2; // number of preview frames to receive before enabling menu...
  2: _dataContext.Device.PreviewFrameAvailable += Device_PreviewFrameAvailable;
  3:       
  4: // I moved the following lines to: Device_PreviewFrameAvailable
  5: //SetScreenButtonsEnabled(true);
  6: //SetCameraButtonsEnabled(true);

2) In the event handler function I wait for “numFrames” events before unhooking the event and enabling the menus:

  1: private int numFrames;
  2: void Device_PreviewFrameAvailable(ICameraCaptureDevice sender, object args)
  3: {
  4:     if (--numFrames < 1)
  5:     {
  6:         // only need to handle this once...
  7:         _dataContext.Device.PreviewFrameAvailable -= Device_PreviewFrameAvailable;
  8:  
  9:         // tell UI thread to enable menus.(code moved from OnNavigatedTo.)
  10:         Dispatcher.BeginInvoke(() =>
  11:         {
  12:             SetScreenButtonsEnabled(true);
  13:             SetCameraButtonsEnabled(true);
  14:         });
  15:     }
  16: }

 3) And finally, in OnNavigatingFrom I added a call to “videoBrush.Clear(VideoBrush.SourceNameProperty);” just before calling Dispose
on the camera context:

  1: if (_dataContext.Device != null && !e.Uri.ToString().Contains("SettingsPage.xaml"))
  2: {
  3:     Debug.WriteLine("MainPage.OnNavigatingFrom(): Releasing camera.");
  4:     videoBrush.ClearValue(VideoBrush.SourceNameProperty);
  5:     _dataContext.Device.Dispose();
  6:     _dataContext.Device = null;
  7: }

 The key take-away is to be sure to clear the VideoBrush.Source property before any operation which would result in the VideoBrush being disposed.

Don’t forget to follow the Windows Store Developer Solutions team on Twitter @wsdevsol. Comments are welcome, both below and on twitter.