Flashlight App crashing every time in Windows Phone - c#

I am trying to operate a flashlight app through TorchControl Class in Windows Phone application:
Here is my code
private static async Task<DeviceInformation> GetCameraID(Windows.Devices.Enumeration.Panel desiredCamera)
{
DeviceInformation deviceID = (await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture))
.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == desiredCamera);
if (deviceID != null) return deviceID;
else throw new Exception(string.Format("Camera {0} doesn't exist", desiredCamera));
}
async private void Button_Click(object sender, RoutedEventArgs e)
{
var cameraID = await GetCameraID(Windows.Devices.Enumeration.Panel.Back);
var mediaDev = new MediaCapture();
await mediaDev.InitializeAsync(new MediaCaptureInitializationSettings
{
StreamingCaptureMode = StreamingCaptureMode.Video,
PhotoCaptureSource = PhotoCaptureSource.VideoPreview,
AudioDeviceId = String.Empty,
VideoDeviceId = cameraID.Id
});
var videoDev = mediaDev.VideoDeviceController;
var tc = videoDev.TorchControl;
if (tc.Supported)
tc.Enabled = true;
mediaDev.Dispose();
}
But the problem is that the app crashes everytime i click on the button second time. I have been told to use the mediaDev.Dispose() method but it is also not working.
Here's the exception:
A first chance exception of type 'System.Exception' occurred in
mscorlib.ni.dll WinRT information: The text associated with this error
code could not be found.
This is showing while the text in "initializeasync" is highlighted

MediaCapture will throw exception when it is re-initialized. To solve this issue, Just make sure you do not initialize MediaCapture twice when you navigate back to Camera page, or when you click the camera button.
MediaCapture mediacapture = new MediaCapture();
bool initialized;
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
if (initialized == false)
{
var cameraID = await GetCameraID(Windows.Devices.Enumeration.Panel.Back);
await mediacapture.InitializeAsync(new MediaCaptureInitializationSettings
{
StreamingCaptureMode = StreamingCaptureMode.Video,
PhotoCaptureSource = PhotoCaptureSource.Photo,
AudioDeviceId = string.Empty,
VideoDeviceId = cameraID.Id
});
}
//Selecting Maximum resolution for Video Preview
var maxPreviewResolution = mediacapture.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.VideoPreview).Aggregate((i1, i2) => (i1 as VideoEncodingProperties).Height > (i2 as VideoEncodingProperties).Height ? i1 : i2);
//Selecting 4rd resolution setting
var selectedPhotoResolution = mediacapture.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.Photo).ElementAt(3);
await mediacapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.Photo, selectedPhotoResolution);
await mediacapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoPreview, maxPreviewResolution);
// in my .xaml <CaptureElement Name="viewfinder" />
viewfinder.Source = mediacapture;
mediacapture.SetPreviewRotation(VideoRotation.Clockwise90Degrees);
await mediacapture.StartPreviewAsync();
initialized = true;
}
Also, make sure the camera stops previewing before you navigate to other page, or before camera starts preview again. There's no need to dispose MediaCapture.
private async void GoBack_Click(object sender, RoutedEventArgs e)
{
await mediacapture.StopPreviewAsync();
this.Frame.Navigate(typeof(MainPage));
//Not needed
//mediacapture.Dispose();
}
GetCameraID method credit to Romasz's blog. http://www.romasz.net/how-to-take-a-photo-in-windows-runtime/

This issue may be related to multithreading: using the defaults (ie not changing the SynchronizationContext) calls to await will continue methods on another thread, something which is not always supported by graphics and media libraries (I have firsthand experience with SFML, WPF, and AutoCAD getting very crash-happy, to name a few). While the presence of an InitializeAsync method indicates otherwise, make sure disposal doesn't need to happen on the main thread or such.

Related

Xamarin MediaElement: setDataSource failed on URL

The following works ok:
using Plugin.FilePicker;
using Plugin.FilePicker.Abstractions;
using Xamarin.CommunityToolkit.Core;`
...
private void btnPlaySource_Clicked(object sender, EventArgs e)
{
FileData fileData = await CrossFilePicker.Current.PickFile();
if (fileData == null)
return; // user canceled file picking
mediaElement.Source = MediaSource.FromFile(fileData.FilePath);
mediaElement.Play();
}
But these lines throw an exception with a delay of ~7 secs (it's not immediately thrown):
private void btnPlayURL_Clicked(object sender, EventArgs e)
{
//http://docs.google.com/uc?export=open&id=XXXXXXXXXXXXXXXXXX
var fileURL = GetGDriveFileURL();
mediaElement.Source = MediaSource.FromUri(fileURL);
mediaElement.Play();
}
Java.Lang.RuntimeException: 'setDataSource failed: status = 0x80000000'
What could be the reason of the exception? The URL is 100% working, I tested it on a WPF application's MediaElement and it played fine. I also build the application for Android with Android API level 29 SDK.
<Grid><xct:MediaElement x:Name="mediaElement" Grid.Row="0" AutoPlay="False" ShowsPlaybackControls="True"/>
Some of the problems were solved using Xamarin.Essentials.FilePicker. It allows picking audio from Google Drive if it's connected to the Android device. Although, the problem with URL still remains.
//var fileResult = await App.PickAndShow(Xamarin.Essentials.PickOptions.Default);
//if (fileResult == null) return false;
public static async Task<string> PickAndShow(Xamarin.Essentials.PickOptions options)
{
try {
Xamarin.Essentials.FileResult result =
await Xamarin.Essentials.FilePicker.PickAsync(options);
if (result != null) {
// For certain types of files, like ".mp3"
if (result.FileName.EndsWith("mp3", StringComparison.OrdinalIgnoreCase) ||
result.FileName.EndsWith("wav", StringComparison.OrdinalIgnoreCase))
{
// for debug purposes
bool exists = File.Exists(result.FullPath);
}
}
return result.FullPath;
} catch (Exception ex) {
// The user canceled or something went wrong
}
return null;
}

Compulsary requirement to take and store users photo using Xam.Plugin.Media

I have a PCL type app and I'm using the Xam.Plugin.Media plugin. I need it to ensure a user submits a photo from the camera before they can continue.
To do this I show the camera page from a button click event and I want to ensure that in case the user cancels out of this that the app launches the camera again, this would repeat until a photograph is stored.
Currenty my app falls in the onActivityResumed method of the MainApplication file when the user cancels out of the camera
Attached photo of my code, My code.
private async void TakePicture()
{
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await App.Current.MainPage.DisplayAlert("No Camera", ":( No camera available.", "Aceptar");
}
file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
Directory = "Sample",
Name = "test.jpg",
PhotoSize = PhotoSize.Small,
});
//IsRunning = true;
if (file != null)
{
ImageSource = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
return stream;
});
}
IsRunning = false;
}
Aside from the fact that it is usually a bit of a UX issue to force a user into anything nowadays, the question still has some merits.
this is the approach that I would consider, it involves recursion.
private async void TakePicture()
{
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await App.Current.MainPage.DisplayAlert("No Camera", ":( No camera available.", "Aceptar");
}
file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
Directory = "Sample",
Name = "test.jpg",
PhotoSize = PhotoSize.Small,
});
//IsRunning = true;
if (file != null)
{
ImageSource = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
return stream;
});
}
else
{
// Recursion - I believe that this would continue until the file is not null, then it would carry on.
TakePicture();
}
IsRunning = false;
}
I can't say I use recursion that often, but I think it might do the trick here.

Turn on torch with MediaCapture on Windows Phone Silverlight 8.1

My problem is quite simple, I cannot turn on the flash light with the MediaCapture API from windows phone 8.1. (I succedded with the 8.0 API)
I built a very simple project with 2 buttons, one to toggle the FlashControl and the other one to toggle TorchControl.
There is no crash, no exception. My phones support FlashControl and TorchControl. I also debug step-by-step and everything looks good, values are changed when buttons are clicked.
Here is my code:
MediaCapture m_captureManager;
public MainPage()
{
InitializeComponent();
}
private static async Task<DeviceInformation> GetCameraID(Windows.Devices.Enumeration.Panel desiredCamera)
{
DeviceInformation deviceID = (await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture))
.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == desiredCamera);
if (deviceID != null) return deviceID;
else throw new Exception(string.Format("Camera {0} doesn't exist", desiredCamera));
}
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
var cameraID = await GetCameraID(Windows.Devices.Enumeration.Panel.Back);
m_captureManager = new MediaCapture();
await m_captureManager.InitializeAsync(new MediaCaptureInitializationSettings
{
StreamingCaptureMode = StreamingCaptureMode.Video,
PhotoCaptureSource = PhotoCaptureSource.VideoPreview,
AudioDeviceId = string.Empty,
VideoDeviceId = cameraID.Id
});
}
private void button_ClickTorch(object sender, RoutedEventArgs e)
{
var torch = m_captureManager.VideoDeviceController.TorchControl;
if (torch.Supported)
{
if (torch.Enabled)
torch.Enabled = false;
else
torch.Enabled = true;
}
}
private void button_ClickFlash(object sender, RoutedEventArgs e)
{
if (captureManager.VideoDeviceController.FlashControl.Supported)
{
if (captureManager.VideoDeviceController.FlashControl.Enabled)
captureManager.VideoDeviceController.FlashControl.Enabled = false;
else
captureManager.VideoDeviceController.FlashControl.Enabled = true;
}
}
It's a simple piece of code and I cannot make it works... I was quite desperate so I tried to toggle by using an intermediate object and without, as you can see, but it did not change the result (which is in conformity).
I finally found out what was wrong. To be able to use camera services, we have to start a preview.
Since with Silverlight we can’t use a CaptureElement, we have to use a CustomPreviewSink with a VideoBrush
This is how to do it ( from microsoft doc)
private async void StartPreview()
{
previewSink = new Windows.Phone.Media.Capture.MediaCapturePreviewSink();
// List of supported video preview formats to be used by the default preview format selector.
var supportedVideoFormats = new List<string> { "nv12", "rgb32" };
// Find the supported preview format
var availableMediaStreamProperties = mediaCaptureManager.VideoDeviceController.GetAvailableMediaStreamProperties(
Windows.Media.Capture.MediaStreamType.VideoPreview)
.OfType<Windows.Media.MediaProperties.VideoEncodingProperties>()
.Where(p => p != null
&& !String.IsNullOrEmpty(p.Subtype)
&& supportedVideoFormats.Contains(p.Subtype.ToLower()))
.ToList();
var previewFormat = availableMediaStreamProperties.FirstOrDefault();
// Start Preview stream
await mediaCaptureManager.VideoDeviceController.SetMediaStreamPropertiesAsync(
Windows.Media.Capture.MediaStreamType.VideoPreview, previewFormat);
await mediaCaptureManager.StartPreviewToCustomSinkAsync(
new Windows.Media.MediaProperties.MediaEncodingProfile { Video = previewFormat }, previewSink);
// Set the source of the VideoBrush used for your preview
Microsoft.Devices.CameraVideoBrushExtensions.SetSource(viewfinderBrush, previewSink);
}
Add this piece of code to previous code and it will work. The important point is to start the preview before changing any parameters

How to display push notification for user in windows 8.1?

I am currently working on Windows 8.1 Push Notification part. I have read different links and found that first we need to register the app and get all the information like SID and Client Secret and send to our server team so they can send push notification.
Then after this, I implemented the following code at my side to get channelUri and Expiration date of that Uri from WNS.
PushNotificationChannel channel = null;
try
{
channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
if (channel != null)
{
var notificationUri = channel.Uri;
var expiration_time = channel.ExpirationTime;
}
channel.PushNotificationReceived += channel_PushNotificationReceived;
}
catch (Exception ex)
{
if (ex != null)
{
System.Diagnostics.Debug.WriteLine(ex.HResult);
}
}
I have received all the values perfectly and my server team added a logic to send me push notification. Now, the problem which I am facing is that I am not aware how to display the received push notification sent by server to that user. Also, can we display the notification is the app is not running or is in background?
Background Tasks solved my problem.
First you need to create a WindowsRuntimeComponent Project and add the code below
public sealed class PushNotification:IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
RawNotification notification = (RawNotification)taskInstance.TriggerDetails as RawNotification;
if (notification != null)
{
ToastTemplateType toastTemplate = ToastTemplateType.ToastImageAndText01;
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);
var textElemets = toastXml.GetElementsByTagName("text");
textElemets[0].AppendChild(toastXml.CreateTextNode(notification.Content));
var imageElement = toastXml.GetElementsByTagName("image");
imageElement[0].Attributes[1].NodeValue = "ms-appx:///Assets/50.png";
ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification(toastXml));
}
}
}
Then register the background task in any of the page( i added in Home Page) using below code
private async void RegisterBackgroundTask()
{
await BackgroundExecutionManager.RequestAccessAsync();
try
{
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
try
{
task.Value.Unregister(false);
}
catch
{
//
}
}
BackgroundTaskBuilder builder = new BackgroundTaskBuilder();
builder.Name = "Push Notifcation Task";
builder.TaskEntryPoint = typeof(PushNotification).FullName;
builder.SetTrigger(new PushNotificationTrigger());
builder.Register();
}
catch(Exception e)
{
if(e != null)
{
System.Diagnostics.Debug.WriteLine(e.HResult);
System.Diagnostics.Debug.WriteLine(e.InnerException);
}
}
}
Please don't forget to add this background task in Declarations section in Package.appmanifest file and name of Entry Point should match with builder.TaskEntryPoint = typeof(PushNotification).FullName; else you will get exception.
Hope it helps someone.

Error in async method

In WinRT app I have one FlipView myFlipView with some pictures and one Image myImage. On myFlipView's event SelectionChanged there is the following method:
async private void myFlipView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (myFlipView == null) return;
Uri newUri = new Uri("ms-appx://" + (((BitmapImage)(((Image)(((ContentControl)(myFlipView.SelectedItem)).Content)).Source)).UriSource.AbsolutePath));
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(newUri);
WriteableBitmap wb = new WriteableBitmap(1, 1);
if (file != null)
{
using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
await wb.SetSourceAsync(fileStream);
}
}
wb = ModifyPicture(wb);
myImage.Source = wb;
}
To sum up it finds uri of current image in myFlipView and set that image in myImage but with some modifications defined in ModifyPicture. It works perfectly on tablets but on computers with mouses there is one error. When I click arrows attached to FlipView very fast then myImage shows wrong picture. For example if in myFlipView I have 10 pictures (p1, p2, ..., p10) and currently p1 is chosen, when I change to p2 on myImage also p2 appears. But when I click very fast sometimes in FlipView I have for example p9 and in myImage p8. I suppose it is connected with fact that method is called many times but I don't know how to fix it. Thank you in advance for help :)
You should probably save the Task/IAsyncOperation that's already running and cancel it if the event handler is called again before it completes.
See this article on how to cancel running tasks.
Pseudo-code (as I don't know C#):
Task loadAndSetImage(uri) {
return new Task...
}
flipView_SelectionChanged {
if (myFlipView == null) return;
if (this.runningTask && !this.runningTask.IsCanceled) {
this.runningTask.Cancel();
}
Uri newUri = new Uri("ms-appx://" + (((BitmapImage)(((Image)(((ContentControl)(myFlipView.SelectedItem)).Content)).Source)).UriSource.AbsolutePath));
this.runningTask = loadAndSetImage(newUri);
this.runningTask.ContinueWith( (t) => this.runningTask = null; );
}
In addition to or instead of cancelling internal tasks as ma_il mentions - you could break/cancel your async method execution if you detect that it should be canceled. E.g.
private int myFlipView_SelectionChangedCallId;
async private void myFlipView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (myFlipView == null) return;
var callId = ++myFlipView_SelectionChangedCallId;
Uri newUri = new Uri("ms-appx://" + (((BitmapImage)(((Image)(((ContentControl)(myFlipView.SelectedItem)).Content)).Source)).UriSource.AbsolutePath));
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(newUri);
if (callId != myFlipView_SelectionChangedCallId) return;
WriteableBitmap wb = new WriteableBitmap(1, 1);
if (file != null)
{
using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
await wb.SetSourceAsync(fileStream);
if (callId != myFlipView_SelectionChangedCallId) return;
}
}
wb = ModifyPicture(wb);
myImage.Source = wb;
}
Also if your ModifyPicture method does any heavy pixel processing - you would want to run it on a background thread and await it.

Categories

Resources