I'm implementing a Windows Phone 8.1 App with a QR Code reader. I use ZXing.NET to analyze the taken image and try to parse the QR. To increase it's efficiency I also set autofocus to the camera. It works pretty well at the first start, but not with the second try (f.e. after suspend - resume or restart capturing). As I tested, the FocusAsync method doesn't return sometimes and blocks everything.
What happens here? What could be the problem?
Here is my current code.
Focus
var focusSettings = new Windows.Media.Devices.FocusSettings();
focusSettings.AutoFocusRange = Windows.Media.Devices.AutoFocusRange.Normal;
focusSettings.Mode = Windows.Media.Devices.FocusMode.Auto;
CaptureManager.VideoDeviceController.FocusControl.Configure(focusSettings);
MainProcess
... Initialization ...
ImageEncodingProperties imaggeProperties = ImageEncodingProperties.CreateJpeg();
imaggeProperties.Width = ViewModel.ImageWidth;
imaggeProperties.Height = ViewModel.ImageHeight;
InMemoryRandomAccessStream memoryStream = new InMemoryRandomAccessStream();
LoggingAdapter.Instance.WriteDebugLog("Scanning is in progress. " + Environment.CurrentManagedThreadId);
await CaptureManager.VideoDeviceController.FocusControl.FocusAsync();
await CaptureManager.CapturePhotoToStreamAsync(imaggeProperties, memoryStream);
LoggingAdapter.Instance.WriteDebugLog("Photo captured.");
var bcReader = new BarcodeReader();
... Processing the barcode ...
Cleaning
if (CaptureManager != null)
{
if (InProgress)
{
InProgress = false;
await CaptureManager.StopPreviewAsync();
}
CaptureManager.Dispose();
Capture.Source = null;
}
Thanks for advance!
I succeeded to implement a working solution. I set the the WaitForFocus to false in the FocusSettings and it seems to be working fine, also with suspending or cancelling.
Related
I just converted one of my apps to target Android API 9 (was targeting API 8); now when notifications are sent out, the volume of media is lowered and never comes back to full volume.
The app uses WebView to play media files. This was not happening prior to targeting API 9. I had to convert the app into level 9 so that I could upload to the Google Play Store. I am running a Samsung S7 which was originally designed for API level 6 (with the OS upgraded to 8.0), not sure if that has something to do with the issue. Another detail is that I use Xamarin.Android for development, not sure if that matters either.
Additionally, I forced the notifications to play a blank sound (a very short[couple ms] blank mp3) in the same build that I converted the app to target API 9:
var channelSilent = new Android.App.NotificationChannel(CHANNEL_ID, name + " Silent", Android.App.NotificationImportance.High)
{
Description = description
};
var alarmAttributes = new Android.Media.AudioAttributes.Builder()
.SetContentType(Android.Media.AudioContentType.Sonification)
.SetUsage(Android.Media.AudioUsageKind.Notification).Build()
//blank is blank mp3 file with nothing in it, a few ms in duration
var uri = Android.Net.Uri.Parse("file:///Assets/blank.mp3")
channelSilent.SetSound(uri, alarmAttributes);
...so it could also be the blank sound that is causing the ducking to malfunction, not the API change. Is there something to do with notification sound ducking that could be causing the issue? Is there any other way to mute a notification with Xamarin.Android other than playing a blank sound? That is one route I think would be worth trying to fix this issue.
Here is the code I am using to generate notifications:
private static List<CustomNotification> _sentNotificationList = new List<CustomNotification>();
private static NotificationManagerCompat _notificationManager;
public async void SendNotifications(List<CustomNotification> notificationList)
{
await Task.Run(() =>
{
try
{
var _ctx = Android.App.Application.Context;
if (_notificationManager == null)
{
_notificationManager = Android.Support.V4.App.NotificationManagerCompat.From(_ctx);
}
if (notificationList.Count == 0)
{
return;
}
int notePos = 0;
foreach (var note in notificationList)
{
var resultIntent = new Intent(_ctx, typeof(MainActivity));
var valuesForActivity = new Bundle();
valuesForActivity.PutInt(MainActivity.COUNT_KEY, _count);
valuesForActivity.PutString("URL", note._noteLink);
resultIntent.PutExtras(valuesForActivity);
var resultPendingIntent = PendingIntent.GetActivity(_ctx, MainActivity.NOTIFICATION_ID, resultIntent, PendingIntentFlags.UpdateCurrent);
resultIntent.AddFlags(ActivityFlags.SingleTop);
var alarmAttributes = new Android.Media.AudioAttributes.Builder()
.SetContentType(Android.Media.AudioContentType.Sonification)
.SetUsage(Android.Media.AudioUsageKind.Notification).Build();
//I am playing this blank sound to prevent android from spamming sounds as the notifications get sent out
var uri = Android.Net.Uri.Parse("file:///Assets/blank.mp3");
//if the notification is the first in our batch then use this
//code block to send the notifications with sound
if (!_sentNotificationList.Contains(note) && notePos == 0)
{
var builder = new Android.Support.V4.App.NotificationCompat.Builder(_ctx, MainActivity.CHANNEL_ID + 1)
.SetAutoCancel(true)
.SetContentIntent(resultPendingIntent) // Start up this activity when the user clicks the intent.
.SetContentTitle(note._noteText) // Set the title
.SetNumber(1) // Display the count in the Content Info
.SetSmallIcon(Resource.Drawable.bitchute_notification2)
.SetContentText(note._noteType)
.SetPriority(NotificationCompat.PriorityMin);
MainActivity.NOTIFICATION_ID++;
_notificationManager.Notify(MainActivity.NOTIFICATION_ID, builder.Build());
_sentNotificationList.Add(note);
notePos++;
}
//if the notification isn't the first in our batch, then use this
//code block to send the notifications without sound
else if (!_sentNotificationList.Contains(note))
{
var builder = new Android.Support.V4.App.NotificationCompat.Builder(_ctx, MainActivity.CHANNEL_ID)
.SetAutoCancel(true) // Dismiss the notification from the notification area when the user clicks on it
.SetContentIntent(resultPendingIntent) // Start up this activity when the user clicks the intent.
.SetContentTitle(note._noteText) // Set the title
.SetNumber(1) // Display the count in the Content Info
.SetSmallIcon(Resource.Drawable.bitchute_notification2)
.SetContentText(note._noteType)
.SetPriority(NotificationCompat.PriorityHigh);
MainActivity.NOTIFICATION_ID++;
_notificationManager.Notify(MainActivity.NOTIFICATION_ID, builder.Build());
_sentNotificationList.Add(note);
notePos++;
}
ExtStickyService._notificationsHaveBeenSent = true;
}
}
catch
{
}
});
}
In my MainActivity I've created two different notification channels: one is silent; the other uses default notification setting for the device:
void CreateNotificationChannel()
{
var alarmAttributes = new Android.Media.AudioAttributes.Builder()
.SetContentType(Android.Media.AudioContentType.Sonification)
.SetUsage(Android.Media.AudioUsageKind.Notification).Build();
var uri = Android.Net.Uri.Parse("file:///Assets/blank.mp3");
if (Build.VERSION.SdkInt < BuildVersionCodes.O)
{
// Notification channels are new in API 26 (and not a part of the
// support library). There is no need to create a notification
// channel on older versions of Android.
return;
}
var name = "BitChute";
var description = "BitChute for Android";
var channelSilent = new Android.App.NotificationChannel(CHANNEL_ID, name + " Silent", Android.App.NotificationImportance.High)
{
Description = description
};
var channel = new Android.App.NotificationChannel(CHANNEL_ID + 1, name, Android.App.NotificationImportance.High)
{
Description = description
};
channel.LockscreenVisibility = NotificationVisibility.Private;
//here is where I set the sound for the silent channel... this could be the issue?
var notificationManager = (Android.App.NotificationManager)GetSystemService(NotificationService);
channelSilent.SetSound(uri, alarmAttributes);
notificationManager.CreateNotificationChannel(channel);
notificationManager.CreateNotificationChannel(channelSilent);
}
Full source: https://github.com/hexag0d/BitChute_Mobile_Android_BottomNav/tree/APILevel9
EDIT: something really interesting is that if I pulldown the system ui bar, the volume goes back to normal. Very strange workaround but it might help diagnose the cause.
DOUBLE EDIT: I used .SetSound(null, null) instead of using the blank .mp3 and the ducking works fine now. See comments
My issue is quite simple.
I want to turn the flash On (and keep it On) on a Windows 10 universal app project but nothing I try works.
This is the code
MediaCapture MyMediaCapture = new MediaCapture();
var allVideoDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
DeviceInformation cameraDevice =
allVideoDevices.FirstOrDefault(x => x.EnclosureLocation != null &&
x.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back);
cameraDevice = cameraDevice ?? allVideoDevices.FirstOrDefault();
if (cameraDevice == null)
{
Debug.WriteLine("No camera device found!");
}
else
{
await MyMediaCapture.InitializeAsync(new MediaCaptureInitializationSettings
{
VideoDeviceId = cameraDevice.Id
});
var MyVideoDeviceController = MyMediaCapture.VideoDeviceController;
var MyTorch = MyVideoDeviceController.TorchControl;
if (MyTorch.Supported)
{
var captureElement = new CaptureElement();
captureElement.Source = MyMediaCapture;
await MyMediaCapture.StartPreviewAsync();
FileStream tmp = new FileStream(System.IO.Path.GetTempFileName() + Guid.NewGuid().ToString() + ".mp4", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, 10000, FileOptions.RandomAccess | FileOptions.DeleteOnClose);
var videoFile = await KnownFolders.VideosLibrary.CreateFileAsync(tmp.Name, CreationCollisionOption.GenerateUniqueName);
var encodingProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Wvga);
await MyMediaCapture.StartRecordToStorageFileAsync(encodingProfile, videoFile);
MyTorch.PowerPercent = 100;
MyTorch.Enabled = true;
}
}
Edit: add code
It looks like you're trying to use an old method of accessing the flashlight which we no longer have to use in Windows 10 UWP development. Take a look at the new Lamp feature in Windows.Devices.Lights in this sample on GitHub.
It's a great starting point for using the flash independent of access the camera APIs.
You're on the right path. Depending on the device (because of driver-specific implementations), you'll have to start the preview or maybe even start a video recording session for the light to turn on.
Because of that, and to guarantee compatibility with most devices, I'd recommend you actually do both.
I am trying to record audio and play it directly (I want to hear my voice in the headphone without saving it) however the MediaElement and the MediaCapture seems non to work at the same time.
I initialized my MediaCapture so:
_mediaCaptureManager = new MediaCapture();
var settings = new MediaCaptureInitializationSettings();
settings.StreamingCaptureMode = StreamingCaptureMode.Audio;
settings.MediaCategory = MediaCategory.Other;
settings.AudioProcessing = AudioProcessing.Default;
await _mediaCaptureManager.InitializeAsync(settings);
However I don't really know how to proceed; I am wonderign if one of these ways could work (I tryied implement them without success, and I have not found examples):
Is there a way to use StartPreviewAsync() recording Audio, or it only works for Videos? I noticed that I get the following error:"The specified object or value does not exist" while setting my CaptureElement Source; it only happens if I write "settings.StreamingCaptureMode = StreamingCaptureMode.Audio;" while everyting works for .Video.
How can I record to a stream using StartRecordToStreamAsync(); I mean, how have I to initialize the IRandomAccessStream and read from it? Can I write on a stream while I keep reading for it?
I read that changing AudioCathegory of the MediaElement and the MediaCathegory of the MediaCapture to Communication there is a possibility it could work. However, while my code works (it just have to record and save in a file) with the previous setting, it don't works if I wrote "settings.MediaCategory = MediaCategory.Communication;" instead of "settings.MediaCategory = MediaCategory.Other;". Can you tell me why?
Here is my current program that just record, save and play:
private async void CaptureAudio()
{
try
{
_recordStorageFile = await KnownFolders.VideosLibrary.CreateFileAsync(fileName, CreationCollisionOption.GenerateUniqueName);
MediaEncodingProfile recordProfile = MediaEncodingProfile.CreateWav(AudioEncodingQuality.Auto);
await _mediaCaptureManager.StartRecordToStorageFileAsync(recordProfile, this._recordStorageFile);
_recording = true;
}
catch (Exception e)
{
Debug.WriteLine("Failed to capture audio:"+e.Message);
}
}
private async void StopCapture()
{
if (_recording)
{
await _mediaCaptureManager.StopRecordAsync();
_recording = false;
}
}
private async void PlayRecordedCapture()
{
if (!_recording)
{
var stream = await _recordStorageFile.OpenAsync(FileAccessMode.Read);
playbackElement1.AutoPlay = true;
playbackElement1.SetSource(stream, _recordStorageFile.FileType);
playbackElement1.Play();
}
}
If you have any suggestion I'll be gratefull.
Have a good day.
Would you consider targeting Windows 10 instead? The new AudioGraph API allows you to do just this, and the Scenario 2 (Device Capture) in the SDK sample demonstrates it well.
First, the sample populates all output devices into a list:
private async Task PopulateDeviceList()
{
outputDevicesListBox.Items.Clear();
outputDevices = await DeviceInformation.FindAllAsync(MediaDevice.GetAudioRenderSelector());
outputDevicesListBox.Items.Add("-- Pick output device --");
foreach (var device in outputDevices)
{
outputDevicesListBox.Items.Add(device.Name);
}
}
Then it gets to building the AudioGraph:
AudioGraphSettings settings = new AudioGraphSettings(AudioRenderCategory.Media);
settings.QuantumSizeSelectionMode = QuantumSizeSelectionMode.LowestLatency;
// Use the selected device from the outputDevicesListBox to preview the recording
settings.PrimaryRenderDevice = outputDevices[outputDevicesListBox.SelectedIndex - 1];
CreateAudioGraphResult result = await AudioGraph.CreateAsync(settings);
if (result.Status != AudioGraphCreationStatus.Success)
{
// TODO: Cannot create graph, propagate error message
return;
}
AudioGraph graph = result.Graph;
// Create a device output node
CreateAudioDeviceOutputNodeResult deviceOutputNodeResult = await graph.CreateDeviceOutputNodeAsync();
if (deviceOutputNodeResult.Status != AudioDeviceNodeCreationStatus.Success)
{
// TODO: Cannot create device output node, propagate error message
return;
}
deviceOutputNode = deviceOutputNodeResult.DeviceOutputNode;
// Create a device input node using the default audio input device
CreateAudioDeviceInputNodeResult deviceInputNodeResult = await graph.CreateDeviceInputNodeAsync(MediaCategory.Other);
if (deviceInputNodeResult.Status != AudioDeviceNodeCreationStatus.Success)
{
// TODO: Cannot create device input node, propagate error message
return;
}
deviceInputNode = deviceInputNodeResult.DeviceInputNode;
// Because we are using lowest latency setting, we need to handle device disconnection errors
graph.UnrecoverableErrorOccurred += Graph_UnrecoverableErrorOccurred;
// Start setting up the output file
FileSavePicker saveFilePicker = new FileSavePicker();
saveFilePicker.FileTypeChoices.Add("Pulse Code Modulation", new List<string>() { ".wav" });
saveFilePicker.FileTypeChoices.Add("Windows Media Audio", new List<string>() { ".wma" });
saveFilePicker.FileTypeChoices.Add("MPEG Audio Layer-3", new List<string>() { ".mp3" });
saveFilePicker.SuggestedFileName = "New Audio Track";
StorageFile file = await saveFilePicker.PickSaveFileAsync();
// File can be null if cancel is hit in the file picker
if (file == null)
{
return;
}
MediaEncodingProfile fileProfile = CreateMediaEncodingProfile(file);
// Operate node at the graph format, but save file at the specified format
CreateAudioFileOutputNodeResult fileOutputNodeResult = await graph.CreateFileOutputNodeAsync(file, fileProfile);
if (fileOutputNodeResult.Status != AudioFileNodeCreationStatus.Success)
{
// TODO: FileOutputNode creation failed, propagate error message
return;
}
fileOutputNode = fileOutputNodeResult.FileOutputNode;
// Connect the input node to both output nodes
deviceInputNode.AddOutgoingConnection(fileOutputNode);
deviceInputNode.AddOutgoingConnection(deviceOutputNode);
Once all of that is done, you can record to a file while at the same time playing the recorded audio like so:
private async Task ToggleRecordStop()
{
if (recordStopButton.Content.Equals("Record"))
{
graph.Start();
recordStopButton.Content = "Stop";
}
else if (recordStopButton.Content.Equals("Stop"))
{
// Good idea to stop the graph to avoid data loss
graph.Stop();
TranscodeFailureReason finalizeResult = await fileOutputNode.FinalizeAsync();
if (finalizeResult != TranscodeFailureReason.None)
{
// TODO: Finalization of file failed. Check result code to see why, propagate error message
return;
}
recordStopButton.Content = "Record";
}
}
I am developing a voice recorder app for Windows Phone 8.1 that stores the recordings on the local storage and a cloud storage service.
Everything's almost done except the fact that being able to pause an ongoing recording is a strong requirement for this app and I have to get it done.
Now, since PauseRecordAsync() and ResumeRecordAsync() are not available for Windows Phone 8.1 in the MediaCapture class but they will be available in Windows 10, I had to make a workaround: Every time the pause button is pressed, an audio chunk is saved in the temp folder and that file is stored in an array. When the stop button is pressed, the last chunk is stored in the array and the following Concatenation function is called and a final audio temp file is created:
public async Task<IStorageFile> ConcatenateAudio([ReadOnlyArray]IStorageFile[] audioFiles, IStorageFolder outputFolder, string outputfileName)
{
IStorageFile _OutputFile = await outputFolder.CreateFileAsync(outputfileName, CreationCollisionOption.ReplaceExisting);
MediaComposition _MediaComposition = new MediaComposition();
MediaEncodingProfile _MediaEncodingProfile = MediaEncodingProfile.CreateM4a(AudioEncodingQuality.High);
foreach (IStorageFile _AudioFile in audioFiles)
{
if(_AudioFile != null)
{
BackgroundAudioTrack _BackgroundAudioTrack = await BackgroundAudioTrack.CreateFromFileAsync(_AudioFile);
MediaClip _MediaClip = MediaClip.CreateFromColor(Windows.UI.Colors.Black, _BackgroundAudioTrack.TrimmedDuration); // A dummy black video is created witn the size of the current audio chunk.
// Without this, the duration of the MediaComposition object is always 0.
// It's a messy workaround but it gets the job done.
// Windows 10 will dirrectly support PauseRecordAsync() and ResumeRecordAsync() for MediaCapture tho'. Yay! :D
_MediaClip.Volume = 0;
_BackgroundAudioTrack.Volume = 1;
_MediaComposition.Clips.Add(_MediaClip);
_MediaComposition.BackgroundAudioTracks.Add(_BackgroundAudioTrack);
}
}
TranscodeFailureReason _TranscodeFailureReason = await _MediaComposition.RenderToFileAsync(_OutputFile, MediaTrimmingPreference.Fast, _MediaEncodingProfile);
if (_TranscodeFailureReason != TranscodeFailureReason.None)
{
throw new Exception("Audio Concatenation Failed: " + _TranscodeFailureReason.ToString());
}
return _OutputFile;
}
The problem is that when I play the file, all the audio chunks are played from the beginning of the final audio file at the same time instead of playing the second one right after the first one ended and so on. They are all playing one over the other. The length of the file on the other hand is correct and after all audio files finished playing, it's total silence.
I figured it out. I had to manually set the delay for BackgroundAudioTrack.
Here is the working code:
public async Task<IStorageFile> ConcatenateAudio([ReadOnlyArray]IStorageFile[] audioFiles, IStorageFolder outputFolder, string outputfileName)
{
IStorageFile _OutputFile = await outputFolder.CreateFileAsync(outputfileName, CreationCollisionOption.ReplaceExisting);
MediaComposition _MediaComposition = new MediaComposition();
MediaEncodingProfile _MediaEncodingProfile = MediaEncodingProfile.CreateM4a(AudioEncodingQuality.High);
TimeSpan totalDelay = TimeSpan.Zero;
foreach (IStorageFile _AudioFile in audioFiles)
{
if (_AudioFile != null)
{
BackgroundAudioTrack _BackgroundAudioTrack = await BackgroundAudioTrack.CreateFromFileAsync(_AudioFile);
MediaClip _MediaClip = MediaClip.CreateFromColor(Windows.UI.Colors.Black, _BackgroundAudioTrack.TrimmedDuration); // A dummy black video is created witn the size of the current audio chunk.
// Without this, the duration of the MediaComposition object is always 0.
// It's a messy workaround but it gets the job done.
// Windows 10 will dirrectly support PauseRecordAsync() and ResumeRecordAsync() for MediaCapture tho'. Yay! :D
_MediaClip.Volume = 0;
_BackgroundAudioTrack.Volume = 1;
_MediaComposition.Clips.Add(_MediaClip);
_MediaComposition.BackgroundAudioTracks.Add(_BackgroundAudioTrack);
_BackgroundAudioTrack.Delay = totalDelay;
totalDelay += _BackgroundAudioTrack.TrimmedDuration;
}
}
TranscodeFailureReason _TranscodeFailureReason = await _MediaComposition.RenderToFileAsync(_OutputFile, MediaTrimmingPreference.Fast, _MediaEncodingProfile);
if (_TranscodeFailureReason != TranscodeFailureReason.None)
{
throw new Exception("Audio Concatenation Failed: " + _TranscodeFailureReason.ToString());
}
return _OutputFile;
}
I'm trying to share an image through my app, everything works just fine when I run the app on my phone through visual studio, but when I try to run it from my phone, it crashes everytime I click the share button
private async void dataTransferManager_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
args.Request.Data.Properties.Title = "Let's Celebrate";
args.Request.Data.Properties.Description = "It's time to celebrate!";
DataRequestDeferral deferral = args.Request.GetDeferral();
try
{
var finalImg = await GenerateImage();
var folder = Package.Current.InstalledLocation;
const CreationCollisionOption option = CreationCollisionOption.ReplaceExisting;
var file = await folder.CreateFileAsync("letscelebrateshare.png", option);
var logicalDpi = DisplayInformation.GetForCurrentView().LogicalDpi;
var pixelBuffer = await finalImg.GetPixelsAsync();
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied,
(uint)finalImg.PixelWidth,
(uint)finalImg.PixelHeight,
logicalDpi,
logicalDpi,
pixelBuffer.ToArray());
await encoder.FlushAsync();
StorageFile logoFile =
await Package.Current.InstalledLocation.GetFileAsync("letscelebrateshare.png");
List<IStorageItem> storageItems = new List<IStorageItem>();
storageItems.Add(logoFile);
args.Request.Data.SetStorageItems(storageItems);
}
}
finally
{
deferral.Complete();
}
}
private async void bla... [..]
{
Exception exc= null;
try
{
//All your stuff
}
catch(Exception ex)
{
exc = ex;
}
if(exc!=null)
await msg.ShowAsync();
}
Edit: Since I don't use WP in C#. I guess you could try this. Hope this helps ^^
I had the same issue while opening a file open picker. I found a weird solution. When I removed the navigation parameters in every pages and used static variables instead, worked fine for me. I guess this will help you
If the App is there crashing without debugger, try while debugging and the share targets are visible to "suspend and shutdown" ("Lifecycle Events" in visual studio). In most cases you app will then crash because it is suspended and serialize the data.