Playing audio in Xamarin UWP crashes - c#

I am building a Xamarin app for UWP (Target Version 10.0.19041.0) and I am trying to play audio through my speakers based on a certain condition. It utilizes the Xam.Plugin.SimpleAudioPlayer (version 1.6.0) to do this (I have not been able to load/use the built-in MediaPlayer).
Based on the other StackOverflow questions (here and here) similar to this one, I made a function that should allow me to load a .mp3 or .wav as a stream and then use the Xam.Plugin.SimpleAudioPlayer to play it through my speakers.
Here is the definition of my function that attempts to load audio files as a stream. I have two files in the Assets folder of my UWP app, beep.wav and beep.mp3, both with Build Action set to Content.
Stream GetStreamFromFile(string filename) {
var assembly = typeof(Application).GetType().Assembly;
var stream = assembly.GetManifestResourceStream(
"Assets/" + filename // have also tried "Assets." since that was in a stackoverflow response
);
return stream;
}
Here is the function that calls the GetStreamFromFile function. I included all the nested conditionals/switches/etc. just in case that could be a possible reason for the issue. If I comment out the audio code lines, my code runs without error and with the expected behavior.
private void AddOrUpdateData() {
InvokeOnMainThread(() => {
...
switch (SensorType) {
case 0:
...
case 1:
...
default:
try {
...
}
finally {
if (my_value < 20) {
var stream = GetStreamFromFile("beep-09.mp3");
// stream.Seek(0L, SeekOrigin.Begin); // Have tried with and without this, not really sure what Seek does
var audio = Plugin.SimpleAudioPlayer.CrossSimpleAudioPlayer.Current;
audio.Load(stream);
audio.Play();
}
...
}
}
...
}
}
When this code runs, I get the null reference exception:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
It occurs whenever 'stream' is called; if stream.Seek is uncommented, it crashes there, otherwise it crashes when audio.Load(stream) occurs since stream appears to be None.
If I try to do it without a stream, and just loading the file from the AudioPlayer, I get this error:
System.Runtime.InteropServices.COMException: 'Error HRESULT E_FAIL has been returned from a call to a COM component.'
The code for that looks like this:
var audio = Plugin.SimpleAudioPlayer.CrossSimpleAudioPlayer.Current;
// Have tried both the mp3 and wav, with/without the Assets directory, all get the same error
audio.Load("Assets/beep.mp3");
audio.Play();
Are there any suggestions on how to fix this? I would try to use MediaPlayer but I cannot seem to import it correctly in Xamarin Forms since I am coding within a generic C# file that compiles to all of my platforms. I am also not sure if it has something to do with the nested locks, switches, and conditionals that maybe mess up how the rest of the code runs (I am not an expert at Xamarin so there are likely processes going on above my head).

If you put files(e.g. beep.mp3) in the Assets folder of your UWP app,you can try the following code:
var player = Plugin.SimpleAudioPlayer.CrossSimpleAudioPlayer.Current;
player.Load("beep.mp3");
player.Play();
Note: Here you don't need add Assets as the prefix.And make sure set the build action to Content.
audio.Load("Assets/beep.mp3");
There is samples here SimpleAudioPlayer, you can refer to it's code.
When you put your files in the folder of xamarin forms, we can use following code to get the stream:
Stream GetStreamFromFile(string filename)
{
var assembly = typeof(App).GetTypeInfo().Assembly;
var stream = assembly.GetManifestResourceStream("SAPlayerSample." + filename);
return stream;
}
And use following code to load the mp3:
ISimpleAudioPlayer player;
var stream = GetStreamFromFile("Diminished.mp3");
player = CrossSimpleAudioPlayer.CreateSimpleAudioPlayer();
player.Load(stream);
And use function Seek to seek to the special postion.
player.Seek(sliderPosition.Value);
For more information, you can check sample: LibraryAudioPage.xaml.cs .

Related

How do you load an audio asset from "the standard locations" in Xamarin.Forms?

I am trying to play an audio asset in my Xamarin.Forms app, and following this guide I always get a System.NullReferenceException. I have placed my two audio files, "device_off.mp3" and "device_on.mp3", in the Android "Assets" folder with the build action AndroidAsset and in the Apple Resources folder with the build action BundleResource. According to the tutorial, I should be able to simply reference the file names to load the files since they are in what Microsoft there terms "the standard locations". My code to play the audio files is as follows:
using(var player = Plugin.SimpleAudioPlayer.CrossSimpleAudioPlayer.Current)
{
if(color == Color.Green)
{
string filepath = "device_on.mp3";
player.Load(filepath);
player.Play();
}else
{
string filepath = "device_off.mp3";
player.Load(filepath);
player.Play();
}
}
What should I be doing differently so I no longer get a System.NullReferenceException when the program reaches the line "player.Load(filepath);"?

Problem with extracting audio from a video file (android)

I need to convert an mp4 (or any other video format) to mp3 or wav file. I am using C# Xamarin.Forms. Any library I used either doesn't work for me, or isn't compatible with android. I have tried using Xamarin.Android.FFMpeg and Xobe.FFMpeg.
I repost this because it was marked as duplicate and I clearly stated that that solution isn't working for me. This is the post that was flagged as duplicate: How can I extract the audio out of a video file? (android) . Please, I tried it but it just gives me the "Downloading Video Converter" dialog with a progress bar when I try to run the code in the solution, Also, it doesn't even extract the audio so after the user waits such a long time, it turned out as a waste of time.
Thanks in advance! :)
EDIT 1:
This is the code I am using:
private async Task<string> ExtractAudioAsync(string path, Action<string> logger = null,
Action<int, int> onProgress = null)
{
List<string> cmd = new List<string>();
cmd.Add("-i");
cmd.Add(path + ".mp4");
cmd.Add("-vn");
cmd.Add("-acodec");
cmd.Add("copy");
cmd.Add(path + ".mp3");
string cmdParams = string.Join(' ', cmd);
await FFMpeg.Xamarin.FFMpegLibrary.Run(Context, cmdParams);
return path + ".mp3";
}
There are no exceptions thrown. When the Run method is called it just shows on the application the following dialog:
After that, it just closes the dialog and goes to the return line without even extracting the audio out of the video. Even if I run this code again it does the same thing, downloading it again.
EDIT 2:
I tried adding the -report option but it just did the same thing and did not save any log file. Am I doing something wrong?

Windows 10 UWP App XElement.Save() "Access is denied" exception

I'm writing a Windows 10 UWP App, and I'm hitting a snag. I have a Settings.xml in the root of the app folder that I will use to store the DB connection information, as well as a few ancillary settings. I can load the XML fine, and my function to edit works (I can extract the XML through debug and see the changes). My problem comes when trying to write the edited file. I understand that I don't have direct access to the file system with UWP, however I've tried several different methods I've found online to work within my constraints and still can't find one that works. I always come back with an "Access is denied" error in some form or another. Here is a snippet of what my Save function looks like right now. Any help would be greatly appreciated.
try
{
XElement xmlSettings = XElement.Load(uri: "Settings.xml");
XElement xmlNode;
//Do Stuff (clipped for brevity).
StorageFolder folder = ApplicationData.Current.LocalFolder;
StorageFile file = await folder.CreateFileAsync(desiredName: "Settings.xml", options: CreationCollisionOption.ReplaceExisting);
Stream stream = await file.OpenStreamForWriteAsync();
xmlSettings.Save(stream);
Error = "";
}
catch (Exception e)
{
Error = "SaveSettings";
}
I added an xml file to my solution (in the root) and copy pasted your code.
It runs the first time, but gets the exception the second time. The reason is that your stream is not closed. You should use it with using:
using (Stream stream = await file.OpenStreamForWriteAsync())
{
xmlSettings.Save(stream);
}
With this change the code worked even the second time.

Can't understand C# windows phone 8.1 (SL) file storage

I'm writing a simple quizz game for WP8.1, at some point I decided to add a highscore capability.
I took an option which I know is not the best one but that should work anyhow : include a highscore.txt file in my application with a default value 0 and placed this file in the "Resources" folder. When the actual score is higher than the highscore I want to overwrite.
Here is how I have proceeded :
First: a method to grab the highscore and store it in a variable (This first method works pretty fine, it reads the file and gets the highscore)
public async void getHighScore(){
Uri highScoreFileLoc = new Uri("ms-appx:///Resources/Highscore.txt");
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(highScoreFileLoc);
string highScoreSTR = await FileIO.ReadTextAsync(file);
}
A method to write the highscore into the file. My thought is that if I use the same exact file path and name, I should overwrite the file I have just opened.
private async void ecritHighScore(int highScore)
{
byte[] line = System.Text.Encoding.UTF8.GetBytes(scoreJoueur.ToString());
Uri HighScoreFileLoc = new Uri("ms-appx:///Resources/Highscore.txt");
StorageFile file2 = await StorageFile.GetFileFromApplicationUriAsync(HighScoreFileLoc);
string highScoreSTR = highScore.ToString();
await FileIO.WriteBytesAsync(file2, line);
}
When I run the app, the highscore is written and read correctly the second time.
But if I quit the emulator and run it again, the highscore is back to the default value: the original Highscore.txt file was not overwritten...
To sum up the situation :
I open a file and read it correctly but when I write into the same exact file (Uri is exactly the same), it is another file that is written into.
How is this possible ? It seems to me that I am missing something somewhere, but I could not find out...
Any help would be much appreciated.
You file uri points to the install directory which is read-only. (And your first write will probably fail on a real device.
Use an ms-appdata:// instead, which is the apps local directory.

How to play music in Metro using file URL mechanism

I need to play Music Library files using file URL, that I will set to MediaPlayer object in a XAML c# object.
I constructed URI as followed
StorageFile file = await KnownFolders.MusicLibrary.GetFileAsync(track.Id);
return new Uri("file:///" + file.Path);
URI looks like this: streamingUri = {file:///C:/Users/user/Music/04 - A Train Makes A Lonely Sound.mp3}
I need URL based scheme to play so that I can reuse same logic for web streaming too.
How do I make this work?
Take a look at
this sample. It should give you some ideas of how to do media playback from file.
While I notice you are saying you need a URI-based, you should use a stream for a local file. The only part you need to extract is a call to set the MediaElement's Source. You can just make a function with 2 overrides and it should be relatively clean.
So, for a web stream:
void SetMediaElementSource(Uri webStreamUri)
{
MyMediaElement.Source = webStreamUri;
}
And for a local file:
void SetMediaElementSource(StorageFile file)
{
var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
MyMediaElement.SetSource(stream, file.ContentType);
}

Categories