Player Notifications with Xamarin MediaManager plugin - xamarin

I'm using the media manager nuget plugin and it's great, but for the life of me, I can't get the lock screen or car bluetooth to show the notifications. I'm using the following to display the notifications (set within OnAppearing)
ViewModel.PropertyChanged += (sender, e) =>
{
switch (e.PropertyName)
{
case "RadioSchedule":
if (listData != null)
{
listData.ItemsSource = null;
var first = ViewModel.RadioSchedule[0];
Device.BeginInvokeOnMainThread(() =>
{
listData.ItemsSource = ViewModel.RadioSchedule;
MediaFile.Metadata.Artist = MediaFile.Metadata.DisplaySubtitle = MediaFile.Metadata.AlbumArtist = first.Artist;
MediaFile.Metadata.Title = MediaFile.Metadata.DisplayTitle = first.Track;
MediaFile.Metadata.DisplayIcon = new Image { Source = "icon".CorrectedImageSource() };
MediaFile.Metadata.BluetoothFolderType = "1";
MediaFile.Type = MediaFileType.Audio;
MediaFile.Url = Constants.RadioStream;
MediaFile.Availability = ResourceAvailability.Remote;
MediaFile.MetadataExtracted = true;
MediaFile.Metadata.Date = DateTime.Now;
MediaFile.Metadata.Duration = 300;
MediaFile.Metadata.Genre = "Rock";
MediaFile.Metadata.TrackNumber = MediaFile.Metadata.NumTracks = 1;
MediaFile.Metadata.DisplayDescription = "Radio Station";
if (!ViewModel.NotificationStarted)
{
if (CrossMediaManager.Current.MediaNotificationManager != null)
CrossMediaManager.Current.MediaNotificationManager.StartNotification(MediaFile);
ViewModel.NotificationStarted = true;
}
CrossMediaManager.Current.MediaNotificationManager?.UpdateNotifications(MediaFile, MediaPlayerStatus.Playing);
});
}
break;
The code itself is being hit (I can set break points and they are hit). I've tried it on and off the UI thread as well.
The playlist comes from a webapi which works fine. The notifier gives unknown/unknown on the device media player (both iOS and Android) and nothing in-car. For Android, the permissions the readme file says to use have also been set.
Is there some sort of magic I have to do to get this to work? This is a Xam.Forms package rather than something native.
The MediaPlayer is started further in the class using the following code
CrossMediaManager.Current.Play(Constants.RadioStream, MediaFileType.Audio, ResourceAvailability.Remote);
Where Constants.RadioStream is the URL of the radio stream.

Related

App MediaFrameReader always returns null Bitmap

I am using MediaCapture to preview camera on the screen, which is working fine.
However, I need to access the current frames in my App. Therefore I added FrameReader to the MediaCapture to get the event Reader_FrameArrived.
So the event is working, however the bitmap itself is always null.
I implemented the ecent callback just like shown in the examples:
var mediaFrameReference = sender.TryAcquireLatestFrame();
var videoMediaFrame = mediaFrameReference?.VideoMediaFrame;
var softwareBitmap = videoMediaFrame?.SoftwareBitmap;
if (softwareBitmap != null)
{
Debug.WriteLine("here");
}
else
{
return;
}
and this is how I initialize the reader:
var frameSourceGroups = await MediaFrameSourceGroup.FindAllAsync();
var allGroups = await MediaFrameSourceGroup.FindAllAsync();
var eligibleGroups = allGroups.Select(g => new
{
Group = g,
// For each source kind, find the source which offers that kind of media frame,
// or null if there is no such source.
SourceInfos = new MediaFrameSourceInfo[]
{
g.SourceInfos.FirstOrDefault(info => info.SourceKind == MediaFrameSourceKind.Color),
g.SourceInfos.FirstOrDefault(info => info.SourceKind == MediaFrameSourceKind.Depth),
g.SourceInfos.FirstOrDefault(info => info.SourceKind == MediaFrameSourceKind.Infrared),
}
}).Where(g => g.SourceInfos.Any(info => info != null)).ToList();
if (eligibleGroups.Count == 0)
{
System.Diagnostics.Debug.WriteLine("No source group with color, depth or infrared found.");
return;
}
var selectedGroupIndex = 0; // Select the first eligible group
MediaFrameSourceGroup selectedGroup = eligibleGroups[selectedGroupIndex].Group;
MediaFrameSourceInfo colorSourceInfo = eligibleGroups[selectedGroupIndex].SourceInfos[0];
MediaFrameSourceInfo infraredSourceInfo = eligibleGroups[selectedGroupIndex].SourceInfos[1];
MediaFrameSourceInfo depthSourceInfo = eligibleGroups[selectedGroupIndex].SourceInfos[2];
//_mediaCapture.FrameSources.TryGetValue(cameraDevice.Id, out _source);
var colorFrameSource = _mediaCapture.FrameSources[colorSourceInfo.Id];
if (colorFrameSource != null)
{
_reader = await _mediaCapture.CreateFrameReaderAsync(colorFrameSource, MediaEncodingSubtypes.Argb32);
_reader.FrameArrived += Reader_FrameArrived;
MediaFrameReaderStartStatus result = await _reader.StartAsync();
Debug.WriteLine(result.ToString());
}
Any ideas why the bitmap could be null?
I am using MediaCapture to preview camera on the screen, which is working fine.
For the scenario, we suggest you use MediaCapture class capture bitmap, it contains GetPreviewFrameAsync method gets a preview frame from the capture device than convert it to SoftwareBitmap.
private async Task GetPreviewFrameAsSoftwareBitmapAsync()
{
// Get information about the preview
var previewProperties = _mediaCapture.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoPreview) as VideoEncodingProperties;
// Create the video frame to request a SoftwareBitmap preview frame
var videoFrame = new VideoFrame(BitmapPixelFormat.Bgra8, (int)previewProperties.Width, (int)previewProperties.Height);
// Capture the preview frame
using (var currentFrame = await _mediaCapture.GetPreviewFrameAsync(videoFrame))
{
// Collect the resulting frame
SoftwareBitmap previewFrame = currentFrame.SoftwareBitmap;
// Show the frame information
FrameInfoTextBlock.Text = String.Format("{0}x{1} {2}", previewFrame.PixelWidth, previewFrame.PixelHeight, previewFrame.BitmapPixelFormat);
// Add a simple green filter effect to the SoftwareBitmap
if (GreenEffectCheckBox.IsChecked == true)
{
ApplyGreenFilter(previewFrame);
}
// Show the frame (as is, no rotation is being applied)
if (ShowFrameCheckBox.IsChecked == true)
{
// Create a SoftwareBitmapSource to display the SoftwareBitmap to the user
var sbSource = new SoftwareBitmapSource();
await sbSource.SetBitmapAsync(previewFrame);
// Display it in the Image control
PreviewFrameImage.Source = sbSource;
}
// Save the frame (as is, no rotation is being applied)
if (SaveFrameCheckBox.IsChecked == true)
{
var file = await _captureFolder.CreateFileAsync("PreviewFrame.jpg", CreationCollisionOption.GenerateUniqueName);
Debug.WriteLine("Saving preview frame to " + file.Path);
await SaveSoftwareBitmapAsync(previewFrame, file);
}
}
}
And here is official code sample that you could refer directly.

How do you programmatically run Static Code Analysis in Visual Studio 2017?

I'm working on a solution to localize legacy applications. I've written a Visual studio add-in using EnvDte that automates the process of setting the "Localizable" flag for every form in the solution to true, which is a critical step for extracting resources on form designers. I am now trying to deal with any text that is set programmatically, text that trigger the Globalization (CA13##) warnings.
designer.Visible = true;
var host = (IDesignerHost)designer.Object;
var provider = TypeDescriptor.GetProvider(host.RootComponent);
var typeDescriptor = provider.GetExtendedTypeDescriptor(host.RootComponent);
if (typeDescriptor == null)
continue;
var propCollection = typeDescriptor.GetProperties();
var propDesc = propCollection["Localizable"];
if (propDesc != null && host.RootComponent != null &&
(bool?)propDesc.GetValue(host.RootComponent) != true)
{
try
{
propDesc.SetValue(host.RootComponent, true);
}
catch (Exception ex)
{
// log the error
}
// save changes
}
I've been able to run it manually from the menu using: Analyze -> Run Code Analysis -> On Solution to get a list of issues, but I would like to automate this step with another add-in that runs and extracts the results.
Are there any resources that point to accessing the build warnings or the results of the code analysis?
Are there any solutions that already do this using EnvDte or Roslyn?
Ok, I've managed to glean enough information to put together the add-in. Put simply, you use _dte.ExecuteCommand()
Initialize the command:
// nothing to see here...
_package = package ?? throw new ArgumentNullException(nameof(package));
var commandService = ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if (commandService == null)
return;
_dte = (DTE2)ServiceProvider.GetService(typeof(DTE));
var menuCommandId = new CommandID(CommandSet, CommandId);
var menuItem = new MenuCommand(MenuItemCallback, menuCommandId);
commandService.AddCommand(menuItem);
_events = _dte.Events.BuildEvents;
// since static code analysis is a sort of build you need to hook into OnBuildDone
_events.OnBuildDone += OnBuildDone;
Trigger the analysis
private void MenuItemCallback(object sender, EventArgs e)
{
_dte.ExecuteCommand("Build.RunCodeAnalysisonSolution");
}
Extract errors in the OnBuildDone event
private void OnBuildDone(vsBuildScope scope, vsBuildAction action)
{
Dispatcher.CurrentDispatcher.InvokeAsync(new Action(() =>
{
_dte.ExecuteCommand("View.ErrorList", " ");
var errors = _dte.ToolWindows.ErrorList.ErrorItems;
for (int i = 1; i <= errors.Count; i++)
{
ErrorItem error = errors.Item(i);
var code = error.Collection.Item(1);
var item = new
{
error.Column,
error.Description,
error.ErrorLevel,
error.FileName,
error.Line,
error.Project
};
error.Navigate(); // you can navigate to the error if you wanted to.
}
});
}

create local notification in xamarin ios with http request

i have xamarin forms app that support notification, i have done it in android with broadcast receiver now i have to do notification in ios ! , my service is depending on API REST so i want every 60 second ios app run HTTP request and get data then show it as notification, i searched for many days but i can't reach to my approach ?
if this is impossible can i use nuget or something like that in ios project only "in xamarin forms solution " or not ?
content = new UNMutableNotificationContent();
content.Title = "Notification Title";
content.Subtitle = "Notification Subtitle";
content.Body = "This is the message body of the notification.";
content.Badge = 1;
content.CategoryIdentifier = "message";
var trigger = UNTimeIntervalNotificationTrigger.CreateTrigger(60, true);
var requestID = "sampleRequest";
var request = UNNotificationRequest.FromIdentifier(requestID, content, trigger);
UNUserNotificationCenter.Current.AddNotificationRequest(request, (err) =>
{
if (err != null)
{
// Do something with error...
}
});
Here is my code for generating a local notification on iOS
var alertsAllowed = false;
UNUserNotificationCenter.Current.GetNotificationSettings((settings) =>
{
alertsAllowed = (settings.AlertSetting == UNNotificationSetting.Enabled);
});
if (alertsAllowed)
{
var content = new UNMutableNotificationContent();
content.Title = "Incident Recorder";
content.Subtitle = "Not Synchronised";
content.Body = "There are one or more new incidents that have not been synchronised to the server.";
var trigger = UNTimeIntervalNotificationTrigger.CreateTrigger(5, false);
var requestID = "sampleRequest";
var request = UNNotificationRequest.FromIdentifier(requestID, content, trigger);
UNUserNotificationCenter.Current.AddNotificationRequest(request, (err) =>
{
if (err != null)
{
Console.WriteLine(err.LocalizedFailureReason);
}
});
}
The first parameter in CreateTrigger is how long before the notification is generated. I notice you have 60 in yours. Also bear in mind a notification will not appear if your app is foregrounded.

Can ZXing be stopped or dispose so i can use it again?

im using ZXing.Net.Mobile for Forms like this
var scanPage = new ZXingScannerPage();
scanPage.OnScanResult += (result) => {
// Stop scanning
scanPage.IsScanning = false;
// Pop the page and show the result
Device.BeginInvokeOnMainThread(async () => {
// await Navigation.PopAsync();
await Navigation.PushModalAsync(new Pages.DataGridPage(PladsId));
});
};
from https://components.xamarin.com/gettingstarted/zxing.net.mobile.forms
but after i have scanned once the carmera is frozen when i try again
i have tried to Dispose/stop the scanner but without success
can ZXing be stopped or dispose so i can use it again ?
im using visual studio 2015 community, xamarin.Forms 2.3.3.168, Syncfusion 14.4.0.15 and ZXing.Net.Mobile 2.1.47. running it on a sony xperia z3 with Android version 6.0.1 and using API 23
Any help is deeply appreciated
Found the solution....
Use IsScanning=true only once... In ScannerView Constructor or in OnAppearing of the Page..
_zxing = new ZXingScannerView
{
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center,
HeightRequest = 250,
WidthRequest = 250,
IsAnalyzing = true,
IsScanning = true,
};
Don't write anything in OnDisappearing...
protected override void OnDisappearing()
{
// _zxing.IsScanning = false;
base.OnDisappearing();
}
IsAnalysing to be set false once scanning complete and should be set true in OnAppearing...
_zxing.OnScanResult += (result) =>
Device.BeginInvokeOnMainThread(async () =>
{
if (!string.IsNullOrWhiteSpace(result.Text))
{
_zxing.IsAnalyzing = false;
await OnGettingResult(result.Text);
}
});
protected override void OnAppearing()
{
base.OnAppearing();
_zxing.IsAnalyzing = true;
//Not required if already set while intialization
//_zxing.IsScanning = true;
}
Why don't you use it with async? After its done scanning, it returns me back in the navigation stack. It looks like your using the generic Scanner Page so the following solution would work.
var scanner = new ZXing.Mobile.MobileBarcodeScanner();
var result = await scanner.Scan();
if (result != null)
{
variableToAssign = result.Text;
}
If like me, you wanted the scanner to not switch off after one scan, or only scan the same code once, then you want to check if you have already scanned a particular qr code.
var options = new MobileBarcodeScanningOptions();
var scans = new HashSet<string>();
options.PossibleFormats.Add(ZXing.BarcodeFormat.QR_CODE);
ZXingScannerPage scanPage = new ZXingScannerPage(options);
scanPage.Title = "Scan QR Code";
scanPage.OnScanResult += (result) =>
{
//Only scan a particular QR code once
if (!scans.Contains(result.Text))
{
scans.Add(result.Text);
//etc
}
}
there's a workaround that should be work at start of your page and start of your action you will unsubscribe
scanPage.OnScanResult -= YourAction();
after-action finished you should subscribe again for scanning
scanPage.OnScanResult += YourAction();

Xamarin.Android Record Video - Quality Poor

I'm using the following Xamarin tutorial https://developer.xamarin.com/recipes/android/media/video/record_video/
I can successfully record video and audio however the quality is not very good. Can anyone suggest/explain how I can increase the quality please?
I know the device can record in higher quality because the native camera app record in much higher quality.
EDIT here is my code so far
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.RecordVideo);
var record = FindViewById<Button>(Resource.Id.Record);
var stop = FindViewById<Button>(Resource.Id.Stop);
var play = FindViewById<Button>(Resource.Id.Play);
var video = FindViewById<VideoView>(Resource.Id.SampleVideoView);
var videoPlayback = FindViewById<VideoView>(Resource.Id.PlaybackVideoView);
string path = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/test.mp4";
if (Camera.NumberOfCameras < 2)
{
Toast.MakeText(this, "Front camera missing", ToastLength.Long).Show();
return;
}
video.Visibility = ViewStates.Visible;
videoPlayback.Visibility = ViewStates.Gone;
_camera = Camera.Open(1);
_camera.SetDisplayOrientation(90);
_camera.Unlock();
recorder = new MediaRecorder();
recorder.SetCamera(_camera);
recorder.SetAudioSource(AudioSource.Mic);
recorder.SetVideoSource(VideoSource.Camera);
recorder.SetOutputFormat(OutputFormat.Default);
recorder.SetAudioEncoder(AudioEncoder.Default);
recorder.SetVideoEncoder(VideoEncoder.Default);
//var cameraProfile = CamcorderProfile.Get(CamcorderQuality.HighSpeed1080p);
// recorder.SetProfile(cameraProfile);
recorder.SetOutputFile(path);
recorder.SetOrientationHint(270);
recorder.SetPreviewDisplay(video.Holder.Surface);
record.Click += delegate
{
recorder.Prepare();
recorder.Start();
};
stop.Click += delegate
{
if (recorder != null)
{
video.Visibility = ViewStates.Gone;
videoPlayback.Visibility = ViewStates.Visible;
recorder.Stop();
recorder.Release();
}
};
play.Click += delegate
{
video.Visibility = ViewStates.Gone;
videoPlayback.Visibility = ViewStates.Visible;
var uri = Android.Net.Uri.Parse(path);
videoPlayback.SetVideoURI(uri);
videoPlayback.Start();
};
}
I don't see the example specifying the CamcorderProfile anywhere so you might want to start from that. It's possible that the default framerate, bitrate and video frame size are lower than you'd expect. I'm not an a computer right now but try to set the profile to for example QUALITY_1080p using the SetProfile method in MediaRecorder.
You need to set the profile after setting the video and audio sources but before calling SetOutputFile method.

Resources