WP8/VS2013 MediaLibrary Songs collection is empty - c#

I'm having a play with writing a mp3 player app for WP8, using MediaLibrary to handle the phone's own mp3 collection.
I want to test the result in the phone emulator on VS2013, but when I use the following code:
using (MediaLibrary library = new MediaLibrary())
{
SongCollection songs = library.Songs;
Song song = songs[0];
MediaPlayer.Play(song);
}
The song collection is empty, presumably because VS doesn't have any knowledge of a media library with songs in.
Is there any way to test this in the emulator using a fake medialibrary or for VS to use windows' media library? I just want to see (or hear) the code working before I proceed :)

I have managed to find a workaround!
If you add an mp3 file to the app's assets, the following code will add the mp3 to the media player library:
private void AddSong()
{
Uri file = new Uri("Assets/someSong.mp3", UriKind.Relative);
//copy file to isolated storage
var myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
var fileStream = myIsolatedStorage.CreateFile("someSong.mp3");
var resource = Application.GetResourceStream(file);
int chunkSize = 4096;
byte[] bytes = new byte[chunkSize];
int byteCount;
while ((byteCount = resource.Stream.Read(bytes, 0, chunkSize)) > 0)
{
fileStream.Write(bytes, 0, byteCount);
}
fileStream.Close();
Microsoft.Xna.Framework.Media.PhoneExtensions.SongMetadata metaData = new Microsoft.Xna.Framework.Media.PhoneExtensions.SongMetadata();
metaData.AlbumName = "Some Album name";
metaData.ArtistName = "Some Artist Name";
metaData.GenreName = "test";
metaData.Name = "someSongName";
var ml = new MediaLibrary();
Uri songUri = new Uri("someSong.mp3", UriKind.RelativeOrAbsolute);
var song = Microsoft.Xna.Framework.Media.PhoneExtensions.MediaLibraryExtensions.SaveSong(ml, songUri, metaData, Microsoft.Xna.Framework.Media.PhoneExtensions.SaveSongOperation.CopyToLibrary);
}
I also needed to add:
using System.IO.IsolatedStorage;
I would love to claim credit for this, but I found the answer here:
http://social.msdn.microsoft.com/forums/wpapps/en-US/f5fa73da-176b-4aaa-8960-8f704236bda5/medialibrary-savesong-method

By default the media library on the emulator is empty. I also do not think it is possible to automagically hook up your dev machine's music folder to the emulator to test that way. It might be possible to manually configure the emulated phone with an email account! and save music onto it that way, but even if that worked you'd have to do it each and every time you restart the emulator.
Best way to test would be t deploy to a real device.

Related

Playing audio from network on Xamarin.Forms

Is it possible to play audio on Xamarin.Forms (Android only, no iOS required) which is received from network over TCP or UDP? In WPF, I'm using NAudio and I have something like this:
// set output device
var provider = new BufferedWaveProvider(codec.RecordFormat);
outputDevice = new WaveOut();
outputDevice.DeviceNumber = 0;
outputDevice.Init(provider);
outputDevice.Play();
Data is received from TCP connection:
if (outputDevice != null)
{
byte[] decoded = codec.Decode(data, 0, data.Length);
provider.AddSamples(decoded, 0, decoded.Length);
}
In this case, data is byte[] - its added to circular buffer and WaveOut handles it like stream, playing it continously. That solution works great.
I need same thing in Xamarin - I guess I need some kind of wrapper around AudioTrack since it apparently supports playing from byte stream. How should I do this, what is the "best" or preferred way? Basically, how to play streamed audio received over pure TCP/UDP socket?
Google's Android ExoPlayer can stream that media format properly.
The following code is a really simple example of ExoPlayer, but it will show you that it does play that stream:
var mediaUrl = "http://api-streaming.youscribe.com/v1/products/2919465/documents/3214936/audio/stream";
var mediaUri = Android.Net.Uri.Parse(mediaUrl);
var userAgent = Util.GetUserAgent(this, "ExoPlayerDemo");
var defaultHttpDataSourceFactory = new DefaultHttpDataSourceFactory(userAgent);
var defaultDataSourceFactory = new DefaultDataSourceFactory(this, null, defaultHttpDataSourceFactory);
var extractorMediaSource = new ExtractorMediaSource(mediaUri, defaultDataSourceFactory, new DefaultExtractorsFactory(), null, null);
var defaultBandwidthMeter = new DefaultBandwidthMeter();
var adaptiveTrackSelectionFactory = new AdaptiveTrackSelection.Factory(defaultBandwidthMeter);
var defaultTrackSelector = new DefaultTrackSelector(adaptiveTrackSelectionFactory);
exoPlayer = ExoPlayerFactory.NewSimpleInstance(this, defaultTrackSelector);
exoPlayer.Prepare(extractorMediaSource);
exoPlayer.PlayWhenReady = true;
Note:
1.exoPlayer is a class-level variable of SimpleExoPlayer type;
2.this is using the Xamarin.Android binding libraries from the Xam.Plugins.Android.ExoPlayer package
ExoPlayer Docs:
https://developer.android.com/guide/topics/media/exoplayer

Cant play created mp3 file, but can play existing file

I am trying to play a file with the written content of my stream to it. It's really strange because if i just go in and play it manually, that works but whenever i try to play it with the program, there is no sound comming from the clip. (There is content in the file). I downloaded a music file just for test and swapped that name with the "fileName" string variable and that works fine playing the file with the program.
public void PlayAudio(object sender, GenericEventArgs<Stream> args)
{
string fileName = $"{ Guid.NewGuid() }.mp3";
using (var file = File.OpenWrite(Path.Combine(Directory.GetCurrentDirectory(), fileName)))
{
args.EventData.CopyTo(file);
file.Flush();
}
WaveOut waveOut = new WaveOut();
Mp3FileReader reader = new Mp3FileReader(fileName); // If i change "fileName" to my music test file, the program can play it fine. But whenever i switch to the created file name from the Stream. It doesnt play it :O
waveOut.Init(reader);
waveOut.Play();
}
I need to use NAudio because this is going to be running on .net core. So i cant use SoundPlayer just for general information.
Background on project. Before i needed it to .net core, i was just running this code which works perfectly. Plays up the audio directly from the api. However, now i cant use this because .net core doesnt support system.media. hens why i have figured out that i need to load the data into a file, mp3 or wav doesnt mather for me and then play that file up with the content inside.
public void PlayAudio(object sender, GenericEventArgs<Stream> args)
{
SoundPlayer player = new SoundPlayer(args.EventData);
player.PlaySync();
args.EventData.Dispose();
}
I managed to solve it. I do not really know what i did. Because i am certain that i tried this earlier. I did restart pc etc but ye it works now ..
public void PlayAudio(object sender, GenericEventArgs<Stream> args)
{
string fileName = $"{ Guid.NewGuid() }.wav";
using (var file = File.OpenWrite(Path.Combine(Directory.GetCurrentDirectory(), fileName)))
{
args.EventData.CopyTo(file);
file.Flush();
Console.WriteLine(fileName);
}
WaveOut waveOut = new WaveOut();
WaveFileReader reader = new WaveFileReader(fileName);
waveOut.Init(reader);
waveOut.Play();
}

c#, mp3 and file path

Hello I am new at c# and I am doing a small game that I need to play mp3 files.
I've been searching about this and using wmp to do it, like this:
WindowsMediaPlayer myplayer = new WindowsMediaPlayer();
myplayer.URL = #"c:\somefolder\project\music.mp3";
myplayer.controls.play();
I am able to play the file successfully with the full path of the mp3 file. The problem is that I can't find a way to use the file directly from the project folder, I mean, if I copy the project to another computer the path of the mp3 file will be invalid and no sound will be played. I feel that I am at a dead end now, so if someone can help me I would appreciate it! Thanks in advance
Another simple option to use would be:
WindowsMediaPlayer myplayer = new WindowsMediaPlayer();
string mp3FileName = "music.mp3";
myplayer.URL = AppDomain.CurrentDomain.BaseDirectory + mp3FileName;
myplayer.controls.play();
This will play the MP3 from the directory that your executable is located in. It is also important to note that no reflection is needed, which can add unnecessary performance cost.
As a follow up to the comment about embedding the MP3 as a resource, the following code can be implemented once it has been added:
Assembly assembly = Assembly.GetExecutingAssembly();
string tmpMP3 = AppDomain.CurrentDomain.BaseDirectory + "temp.mp3";
using (Stream stream = assembly.GetManifestResourceStream("YourAssemblyName.music.mp3"))
using (Stream tmp = new FileStream(tmpMP3, FileMode.Create))
{
byte[] buffer = new byte[32 * 1024];
int read;
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
{
// Creates a temporary MP3 file in the executable directory
tmp.Write(buffer, 0, read);
}
}
WindowsMediaPlayer myplayer = new WindowsMediaPlayer();
myplayer.URL = tmpMP3;
myplayer.controls.play();
// Checks the state of the player, and sends the temp file path for deletion
myplayer.PlayStateChange += (NewState) =>
{
Myplayer_PlayStateChange(NewState, tmpMP3);
};
private static void Myplayer_PlayStateChange(int NewState, string tmpMP3)
{
if (NewState == (int)WMPPlayState.wmppsMediaEnded)
{
// Deletes the temp MP3 file
File.Delete(tmpMP3);
}
}
Add the MP3 file to your project. Also flag it to always copy to output folder. Here you have a tutorial of how to do it (How to include other files to the output directory in C# upon build?). Then you can reference this way:
You have to use:
using System.Windows.Forms;
And then you can use like this:
WindowsMediaPlayer myplayer = new WindowsMediaPlayer();
myplayer.URL = Application.StartupPath + "\music.mp3";
myplayer.controls.play();
This should work for any machine, provided your mp3 & exe are in same folder.
string mp3Path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + mp3filename

How to play a sound that was imported into C# WPF project?

I have an issue with trying to play sound in my WPF application. When I reference the sound from its actual file location, like this,
private void playSound()
{
//location on the C: drive
SoundPlayer myNewSound = new SoundPlayer(#"C:\Users\...\sound.wav");
myNewSound.Load();
myNewSound.Play();
}
it works fine. However, I recently imported the same sound into my project, and when I try to do this,
private void playSound()
{
//location imported in the project
SoundPlayer myNewSound = new SoundPlayer(#"pack://application:,,,/sound.wav");
myNewSound.Load();
myNewSound.Play();
}
it produces an error and the sound won't play. How can I play the sound file imported into my project?
Easiest/shortest way for me is to change Build Action of added file to Resource, and then just do this:
SoundPlayer player = new SoundPlayer(Properties.Resources.sound_file);//sound_file is name of your actual file
player.Play();
You are using pack Uri as argument, but it needs either a Stream or a filepath .
As you have added the file to your project, so change its Build Action to Content , and Copy To Output Directory to Always.
using (FileStream stream = File.Open(#"bird.wav", FileMode.Open))
{
SoundPlayer myNewSound = new SoundPlayer(stream);
myNewSound.Load();
myNewSound.Play();
}
You can do it with reflection.
Set the property Build Action of the file to Embedded Resource.
You can then read it with:
var assembly = Assembly.GetExcetutingAssembly();
string name = "Namespace.Sound.wav";
using (Stream stream = assembly.GetManifestResourceStream(name))
{
SoundPlayer myNewSound = new SoundPlayer(stream);
myNewSound.Load();
myNewSound.Play();
}

Multiple audio stream in Universal App(Runtime API), XNA SoundEffect replacement

As the XNA SoundEffect is no longer available in the Windows Runtime API (for developing Universal App), I need something similar to play multiple audio streams at the same time.
Requirements:
Play the same audio file multiple times, simultaneously.
Previous Silverlight implementation with SoundEffect:
// Play sound 10 times, sound can be played together.
// i.e. First sound continues playing while second sound starts playing.
for(int i=0; i++; i < 10)
{
Stream stream = TitleContainer.OpenStream("sounds/Ding.wav");
SoundEffect effect = SoundEffect.FromStream(stream);
FrameworkDispatcher.Update();
effect.Play();
// Wait a while before playing again.
Thread.Sleep(500);
}
SoundEffect supports multiple (up to 16 I think) SoundEffectInstance being played simultaneously.
The standard MediaElement API only supports 1 audio stream for Windows Phone 8.1.
I bumped into this: https://github.com/rajenki/audiohelper which uses the XAudio2 API but it doesn't seem to support simultaneous audio either.
Solved. I used SharpDX. Huge thanks to the author here: http://www.hoekstraonline.net/2013/01/13/how-to-play-a-wav-sound-file-with-directx-in-c-for-windows-8/?utm_source=rss&utm_medium=rss&utm_campaign=how-to-play-a-wav-sound-file-with-directx-in-c-for-windows-8
Here is the code to the solution:
Initialization:
xAudio = new XAudio2();
var masteringVoice = new MasteringVoice(xAudio);
var nativeFileStream = new NativeFileStream("Assets/Ding.wav", NativeFileMode.Open, NativeFileAccess.Read, NativeFileShare.Read);
stream = new SoundStream(nativeFileStream);
waveFormat = stream.Format;
buffer = new AudioBuffer
{
Stream = stream.ToDataStream(),
AudioBytes = (int)stream.Length,
Flags = BufferFlags.EndOfStream
};
Event handler:
var sourceVoice = new SourceVoice(xAudio, waveFormat, true);
sourceVoice.SubmitSourceBuffer(buffer, stream.DecodedPacketsInfo);
sourceVoice.Start();
The officially provided code by SharpDX's sample does not use NativeFileStream, it is required to make it work.

Categories