Read audio file to stream with MediaPlayer (WPF) - c#

I use MediaPlayer to play audio files
var mediaPlayer = new MediaPlayer();
mediaPlayer.Open(new Uri(s));
mediaPlayer.Play();
Sometimes I need to delete files that MediaPlayer is still playing.
I guess I have somehow read file to stream to be get free access to it in order to delete it. I mean i sthere way to read file to stream or I have to create some temp. file to play and in this case I can delete the original one or there are other options?
How to implement it?
Thank you!

Actually, when you call MediaPlayer.Open it reads in the file via a stream automatically. The problem is that the stream is still open when you try to delete the file.
MediaPlayer has a .Close method on it. Calling this will close the stream that's reading in the file.
here's the documentation on the MediaPlayer class so you can see what other methods are available to use: http://msdn.microsoft.com/en-us/library/system.windows.media.mediaplayer.aspx
EDIT: If you don't mind that the player stops playback when you call Close then you can just Close & then delete your file. If you do need playback to continue then you'll need a different approach.
If you're using Silverlight then you can just load the stream directly into a MediaElement:
var bytes = File.ReadAllBytes(#"c:\yourfile.ext");
var mStream = new MemoryStream(bytes);
mediaElement1.SetSource(mStream);
Sadly, WPF does not have the same stream support. I attempted to get a Uri for the MemoryStream by writing the stream into the resource pack. Though, i couldn't get it to playback correctly in my testing. I'll include my source that i had just in case you want to fiddle with it and maybe get it to work:
var bytes = File.ReadAllBytes(#"C:\Bill\TestWaveFiles\14043.wav");
MemoryStream packStream = new MemoryStream()
Package pack = Package.Open(packStream, FileMode.Create, FileAccess.ReadWrite);
Uri packUri = new Uri("bla:");
PackageStore.AddPackage(packUri, pack);
Uri packPartUri = new Uri("/MemoryResource", UriKind.Relative);
PackagePart packPart = pack.CreatePart(packPartUri, "Media/MemoryResource");
packPart.GetStream().Write(bytes, 0, bytes.Length);
var inMemoryUri = PackUriHelper.Create(packUri, packPart.Uri);
mediaElement1.LoadedBehavior = MediaState.Manual;
mediaElement1.Source = inMemoryUri;
mediaElement1.Play();
Another option is to simply make a copy of the file before you open it. that way you can always delete the original. Though, you could also just "mark" the file to be deleted. When the user is done playing the the file then you could close & delete it.
One additional option is to use a 3rd party library called BoxedApp. It seemingly will allow you to have a "Virtual File" that contains a memory stream. You could then get a Uri that points to this virtual file and load it into the media player. Look at this answer by
user1108125 to see how to use this BoxedApp library (which i've never used). https://stackoverflow.com/a/8587166/1721136

Related

Can't Use Stream.Write method while playing same file in MediaElement

So lets say I have a file which has around 2MB already downloaded and written which is being played using a MediaElement. So while the media is being played, I want to download and write the rest of the file.
If I use this method, I get an IOExecption error indicating the file is already in use.
using (Stream WriteStream = new FileStream(filename, FileMode.OpenOrCreate))
{
WriteStream.Seek(seekpos, SeekOrigin.Begin);
WriteStream.Write(buffer, 0, buffer.Length);
WriteStream.Close();
}
But if I use this method, it works fine.
FileStream1 = new System.IO.FileStream(filename, System.IO.FileMode.Append, System.IO.FileAccess.Write, System.IO.FileShare.ReadWrite);
FileStream1.Write(buffer, 0, buffer.Length);
So I could use the second method, but I want to be able to seek and write at certain positions which I can't do using the second method. So is there anyway in which I can use the first method. Does it have something to do with the FILEMODE or FILEACCESS?
Thanks :)
The closest you might get might be displayed here with what's known as a synchronized stream. Essentially, it's multiple threads acting on the same stream. You'd have to get the locking issue resolved, especially since you may have no way of making the MediaElement open the file with a shared lock.
Another approach might be to write to one file while the MediaElement plays from another. When the MediaElement's done with file A, play B and stream downloads to new file C. Repeat. Then, at the end, merge them together.
Never-mind I figured it out. I can use this to seek and write at any position. Stupid of me to not realise this.
FileStream1 = new System.IO.FileStream(filename, System.IO.FileMode.Append, System.IO.FileAccess.Write, System.IO.FileShare.ReadWrite);
FileStream1.Seek(seekpos,SeekOrigin.Begin);
FileStream1.Write(buffer, 0, buffer.Length);

Response.BinaryWrite creating a .partial file?

I am attempting to write an audio file as a .wav in a memorystream out to the response so the client can download it. It looks like on client side when trying to open the file it has a ".partial" extension. It is almost as if the file is not getting released to the client.
The below is my code... Attempting to write the bytes directly to the local machine works fine (you will see that code commented out).
// Initialize a new instance of the speech synthesizer.
using (SpeechSynthesizer synth = new SpeechSynthesizer())
using (MemoryStream stream = new MemoryStream())
{
// Create a SoundPlayer instance to play the output audio file.
MemoryStream streamAudio = new MemoryStream();
// Configure the synthesizer to output to an audio stream.
synth.SetOutputToWaveStream(streamAudio);
synth.Speak("This is sample text-to-speech output. How did I do?");
streamAudio.Position = 0;
// Set the synthesizer output to null to release the stream.
synth.SetOutputToNull();
// Insert code to persist or process the stream contents here.
// THIS IS NOT WORKING WHEN WRITING TO THE RESPONSE, .PARTIAL FILE CREATED
Response.Clear();
Response.ContentType = "audio/wav";
Response.AppendHeader("Content-Disposition", "attachment; filename=mergedoutput.wav");
Response.BinaryWrite(streamAudio.GetBuffer());
Response.Flush();
// THIS WORKS WRITING TO A FILE
//System.IO.File.WriteAllBytes("c:\\temp\\als1.wav", streamAudio.GetBuffer());
}
MemoryStream.GetBuffer is not the correct method to call:
Note that the buffer contains allocated bytes which might be unused.
For example, if the string "test" is written into the MemoryStream
object, the length of the buffer returned from GetBuffer is 256, not
4, with 252 bytes unused. To obtain only the data in the buffer, use
the ToArray method; however, ToArray creates a copy of the data in
memory.
so use MemoryStream.ToArray instead:
Response.BinaryWrite(streamAudio.ToArray());
Looks like the issue was the fact the speak method needs to be run on its own thread. The following provides the solution to get back the byte array properly and then be able to write that to the response.
C# SpeechSynthesizer makes service unresponsive

Load PDF from memory into telerik:RadPdfViewer

I have a PDF file stored in a database as a byte array.
I'm reading the PDF byte array from my database back into my application.
Now, I'm trying to display the PDF with the RadPdfViewer but it is not working.
Here is my code:
byte[] pdfAsByteArray= File.ReadAllBytes(#"C:\Users\Username\Desktop\Testfile.pdf");
//Save "pdfAsByteArray" into database
//...
//Load pdf from database into byte[] variable "pdfAsByteArray"
using (var memoryStream = new MemoryStream(pdfAsByteArray))
{
this.PdfViewer.DocumentSource = new PdfDocumentSource(memoryStream);
}
when I execute the application I just get an empty PdfViewer.
Question: How do I set the DocumentSource the right way?
Question: How do I dispose the stream? (note that using doesn't works)
Note: I wan't to avoid things like writing a temp file to disk
Edit:
I figured it out but I am not completely satisfied with this solution:
Not working:
using (var memoryStream = new MemoryStream(pdfAsByteArray))
{
this.PdfViewer.DocumentSource = new PdfDocumentSource(memoryStream);
}
Working:
var memoryStream = new MemoryStream(pdfAsByteArray);
this.PdfViewer.DocumentSource = new PdfDocumentSource(memoryStream);
I don't know how teleriks RadPdfViewer component works but I wan't to dispose the Stream.
From the Telerik documentation (particularly with regards to the "Caution" stating that this loading is done asynchronously), I believe this should work while still providing you a way to close the stream (not as cleanly as if you were able to use a using block, but still better than leaving it open):
//class variable
private MemoryStream _stream;
_stream = new MemoryStream(pdfAsByteArray);
var docSource = new PdfDocumentSource(memoryStream);
docSource.Loaded += (sender, args) => { if (_stream != null) _stream.Dispose();};
this.PdfViewer.DocumentSource = docSource;
I did this free-hand and don't have access to the Telerik API so the exact details of the Loaded event are not available to me.
EDIT
Here's the relevant details from documentation I found (emphasis mine):
The PdfDocumentSource loads the document asynchronously. If you want
to obtain a reference to the DocumentSource after you have imported a
document, you should use the Loaded event of the PdfDocumentSource
object to obtain the loaded document. This is also a convenient method
that can be used to close the stream if you are loading a PDF from a
stream.
You need to implement PdfDocumentSource Loaded event. This is when the stream gets loaded and used up, and can be closed / disposed at that time.
Another method I've used is:
this.PdfViewer.PdfjsProcessingSettings.FileSettings.Data = Convert.ToBase64String(File.ReadAllBytes(#"C:\Users\Username\Desktop\Testfile.pdf"));

Out of memory crash when trying to change image?

(C#) I get an out-of-memory crash when I try setting the image of a "picture box" with one opened from a file.
My code:
string file = openImageBox.Text; // Our file
if (File.Exists(file))
{
File.Open(file, FileMode.Open); // Open the file for use.
Output.Text = "File Open Success!"; //Informing the user on how sucessful they are.
Output.ForeColor = System.Drawing.Color.Black;
Image img = Image.FromFile(file);
Display.Image = img;
}
Probably not the right answer (who knows.. it could be causing you all sorts of issues).
You don't need to "Open the file for use". This is holding a handle to the file you don't need. Just call Image.FromFile directly and it will work fine.
So remove this:
File.Open(file, FileMode.Open); // Open the file for use.
EDIT:
For completeness (and to help you learn), you need to store a reference to the stream if you want to close it. What I told you to remove above holds a handle to the file. The file is essentially open now.. until you close it.
For other code (where you're not using a method like Image.FromFile), you would either store a handle to the file so you can close it.. or use a using statement to close it for you.
Option A:
var stream = File.Open(file, FileMode.Open);
// do stuff here
stream.Close();
Option B (preferred):
using (var stream = File.Open(file, FileMode.Open)) {
// do stuff here
} // stream.Close automatically called for you

can't Get stream of mp3 file in wp7 application

i'm building a wp7 application for a game using silverlight & XNA
i have an mp3 file called "Punch1.mp3" (Build action : resource ) stored inside a folder called "SoundEffects" inside the project folder
and i want to play the file using this code
StreamResourceInfo info;
Uri myuri = new Uri("/SoundEffects/Punch1.mp3", UriKind.Relative);
info = App.GetResourceStream (myuri);
punch1 = SoundEffect.FromStream(info.Stream ) ;
punch is defined in the code here :
public static SoundEffect punch1;
the problem is that it raises a nullreference exception in the third line claiming that info is null
and that's true in the debugging mode , i found that the resource stream info is null
i think this is because the it can't read the file although the uri is correct
You can try two things
- Clean and rebuild the project
- Try appending project name in URI "/PhoneApp1;component/SoundEffects/Punch.mp3"
Since you're using the XNA assembly anyway, you can use TitleContainer.OpenStream instead (with a relative URI) and have the audio file build set as Content.
I agree with Haris Haqsan that your URI string is bad.
Uri myuri = new Uri("/PhoneBoxing;component/SoundEffects/Punch1.mp3", UriKind.Relative);
But you should also consider switching to using content files instead embedding them at resources as it can help your application start up time. Depending on the amount of files we are talking about, it can make a big difference.
Set your Build Action to content and your code should look like:
FileStream stream = new FileStream("/SoundEffects/Punch1.mp3", FileMode.Open, FileAccess.Read);
in the following code :
Uri myuri = new Uri("/SoundEffects/Punch1.mp3", UriKind.Relative);
info = App.GetResourceStream (myuri);
punch1 = SoundEffect.FromStream(info.Stream ) ;
SoundEffect.FromStream() expects a wave file stream not an MP3 as shown here : http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.audio.soundeffect.fromstream.aspx .
so solution to find a mp3 > wav convertor or just find another way to load mp3 to WP7
considering the picture this is normal URI in normal cases can't evaluate expression of isfile .
I was experiencing the same issue on my machine, the InvalidOperationException is a little confusing. All I had to do was re-encode the wav file to the specifications listed on MSDN.
After I did that, it worked perfectly.

Categories