MediaElement not playing after changing position - c#

I have a video player which downloads a video file in chunks. After a chunk of 1MB has been downloaded, an event is called giving the MediaElement its source, and making it play. Whilst the video is being played, the rest of the 1MB chunks are downloaded until the file is complete. If only 1MB of the video is downloaded, the playback time is equal to 17 seconds(This will come in later).
When the file is completely downloaded, permission is given to the user to change the position of the video or seek it. If the user seeks to a position under or equal to 17 seconds, the MediaElement will change its position and keep on playing, however if the user seeks to a position greater than 17s, the video freezes.
This could be for the fact that the MediaElement has buffered only 1MB of the video so it'll only seek withing that timeframe, but it doesn't make sense because if I let it play without interruption, it'll play the whole video without any problem. Can someone tell me whats going on?
Code:
private void downloadchunks()
for (int i = 1; i <= 20; i++)
{
WriteStream = new System.IO.FileStream(DownloadLocation, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.ReadWrite);
//request and receive a response of 1MB of a file
rpstream = response.GetResponseStream();
byte[] buffer;
using (var SReader = new MemoryStream())
{
rpstream.CopyTo(SReader);
buffer =SReader.ToArray();
WriteStream.Seek(WritePos,SeekOrigin.Begin);
WriteStream.Write(buffer, 0, buffer.Length);
WriteStream.Close();
}
if (i==1)
{
PlayVideo();
}
}
private void PlayVideo()
{
MediaElement.Source = new uri(DownloadLocation);
MediaElement.Play();
}

I've figured it out. Just create a dummmy file before you assign it to the MediaElement, and then start the download.
File.WriteAllBytes(location, new byte[filesize]);

Related

Playing from wav stream

var result = service.Synthesize(
text: text,
accept: "audio/wav",
voice: "en-US_AllisonVoice"
//voice: "en-US_HenryV3Voice"
);
using (FileStream fs = File.Create(#"C:\Users\nkk01\Desktop\voice.wav"))
{
result.Result.WriteTo(fs);
fs.Close();
result.Result.Close();
}
var waveStream = new WaveFileReader(#"C:\Users\nkk01\Desktop\voice.wav");
var waveOut = new WaveOutEvent();
waveOut.Init(waveStream);
Console.WriteLine("Playing");
waveOut.Play();
Console.WriteLine("Finished playing");
Hi this is my current code which is extremely inefficient as it has to save an audio stream to a file to play it. I would like to pass the audio stream directly to my laptop's speaker using the NAudio library. I still have not managed to find a solution. It will be of great help, thanks.
i'm not familiar with naudio but as far as i can see from their git hub repo, the constructor for WaveFileReader also accepts a stream instead of a filename ...
simply try writing everything you have to a memory stream instead of a file... don't forget to reposition the memory stream before you read it ('seek' to offset 0)

How to stop MediaPlayer from starting each time?

How would I fix my MediaPlayer code, that receives bytes, than creates a temp file, that is saving input, but for each input, the player starts from the beginning, and I want it to just play. This is my code:
Java.IO.File temp = Java.IO.File.CreateTempFile("temp", "mp3");
Java.IO.FileOutputStream fos = new Java.IO.FileOutputStream(temp);
Java.IO.FileInputStream fis = new Java.IO.FileInputStream(temp);
temp.DeleteOnExit();
MediaPlayer player = new MediaPlayer();
player.SetDataSource(fis.FD);
// If set here, there is an error
//12-09 17:29:44.472 V/MediaPlayer( 9927): setDataSource(58, 0, 576460752303423487)
//12-09 17:29:44.472 E/MediaPlayer( 9927): Unable to to create media player
while (true)
{
try
{
byte[] myReadBuffer = new byte[10000]; //Input array
mmInStream.Read(myReadBuffer, 0, myReadBuffer.Length); //Reads the incoming array into myReadBuffer
fos.Write(myReadBuffer, 0, myReadBuffer.Length); //Writes it into temp file
MediaPlayer player = new MediaPlayer(); //Creates a new object
player.SetDataSource(fis.FD); // If here, it would just start from the start each time and add more // Sets the data source to temp file
player.Prepare();
player.Start();
while (true)
{
// Checks if it can release resources
if (!player.IsPlaying)
{
player.Release();
break;
}
}
}
catch (System.IO.IOException ex)
{
System.Diagnostics.Debug.WriteLine("Input stream was disconnected", ex);
}
}
I am using Xamari Forms.
Basicaly, I get an array of bytes, that I store in a temporary file, and than try to play them. I know the MediaPlayer is recreated on every loop, since there I define the data source, but if I put it outside of the loop, it would get an error(as above).
Example:
The song starts, is played for about 2s and than it starts over but is now played for 4s, and over again and now for 6s. Each time, more of the song is revealed.
If it was a string it would be like this:
123
123456
123456789
How would I make it to play continuously, but each time it would play a only the new part?
This is a logic issue. Essentially you're writing chunks to a stream, then playing that chunk, then writing more without resetting the stream, then playing from the beginning of that stream.
What you need it to do is write a chunk to your stream, play that stream, then write a new chunk to the stream and play that stream.
Move your Java.IO.FileOutputStream fos = new Java.IO.FileOutputStream(temp); inside of your outer while() loop.
The reason this works is that you're writing to your fos then playing, then writing again but not disposing of your initial buffer data. Moving fos into your while loop forces a new object to be created which will contain the new buffer data, then it will play that. There's going to be an issue with audio skipping because of the loop and having to re-load the new data to be played.
To correct the skip you'll need to load your buffer asynchronously while it's being played. You can do this with a separate thread. You might need to adjust your buffer size or set a buffer condition. MediaPlayer contains a BufferingProgress property that might help.

How to use track bar in NAudio MP3 streaming section

I am using NAudio Library in C# and I need a track bar to control the music. In NAudio Mp3Stream example project we have standard controls such as play, stop, pause, volume but there is no track bar.
Can I use track bar in Mp3Stream at all ? because when I set the break point on do command, CanSeek property is false in readFullyStream variable.
How can I use track bar on streaming ?
using (var responseStream = resp.GetResponseStream())
{
var readFullyStream = new ReadFullyStream(responseStream);
do
{
if (IsBufferNearlyFull)
{
Debug.WriteLine("Buffer getting full, taking a break");
Thread.Sleep(500);
}
else
{
Mp3Frame frame;
try
{
frame = Mp3Frame.LoadFromStream(readFullyStream);
}
catch (EndOfStreamException)
{
fullyDownloaded = true;
// reached the end of the MP3 file / stream
break;
}
catch (WebException)
{
// probably we have aborted download from the GUI thread
break;
}
if (decompressor == null)
{
// don't think these details matter too much - just help ACM select the right codec
// however, the buffered provider doesn't know what sample rate it is working at
// until we have a frame
decompressor = CreateFrameDecompressor(frame);
bufferedWaveProvider = new BufferedWaveProvider(decompressor.OutputFormat);
bufferedWaveProvider.BufferDuration = TimeSpan.FromSeconds(20); // allow us to get well ahead of ourselves
//this.bufferedWaveProvider.BufferedDuration = 250;
}
int decompressed = decompressor.DecompressFrame(frame, buffer, 0);
//Debug.WriteLine(String.Format("Decompressed a frame {0}", decompressed));
bufferedWaveProvider.AddSamples(buffer, 0, decompressed);
}
} while (playbackState != StreamingPlaybackState.Stopped);
Debug.WriteLine("Exiting");
// was doing this in a finally block, but for some reason
// we are hanging on response stream .Dispose so never get there
decompressor.Dispose();
}
the NAudio streaming demo simply decompresses and plays MP3 frames as they arrive. There is no code to store previously received audio. So if you wanted the ability to rewind, you'd need to implement that.
One option you could consider is using the MediaFoundationReader, passing in the stream URL as the path. This can play audio as it downloads, and should support repositioning as well.

High Memory Usage playing MP3's with NAudio on Key Press

I'm using C#, WPF, and NAudio.
I play an embedded resource mp3 in the application exe when a key is pressed.
If a key is pressed repeatedly, RAM usage continues to climb past 400MB and never drops.
Using Flush() and Dispose() on the objects doesn't seem to free memory even when GC is called.
This did not used to happen when I played from external resource on the hard drive using string path instead of MemoryStream. It used to stay around 50MB RAM.
public static MemoryStream ms = null;
public static WaveStream wav = null;
public static WaveOutEvent output = null;
// Embedded Resource sound1.mp3
MemoryStream sound1 = new MemoryStream(Properties.Resources.sound1);
// Key Press
//
if (e.Key == Key.Space) {
ms = new MemoryStream(StreamToBytes(sound1));
wav = new Mp3FileReader(ms);
output = new WaveOutEvent();
output.PlaybackStopped += new EventHandler<StoppedEventArgs>(Media_Ended);
output.Init(wav);
output.Play();
}
// MP3 Playback Ended
//
public static void Media_Ended(object sender, EventArgs e)
{
if (output.PlaybackState == PlaybackState.Stopped)
{
ms.Flush();
ms = null;
wav.Close();
output.Dispose();
}
}
// Convert Stream to Byte Array
//
public static byte[] StreamToBytes(MemoryStream stream)
{
...
}
Stream to Byte Array
https://stackoverflow.com/a/1080445/6806643
I convert to Byte Array back to a new Stream or the playback will not layer and will crash if 2 sounds play at once.
It's because you clicking space bar too fast :)
Each key click overwrites variables with new values. So when you click space bar 10 times in few seconds it will create 10 resources. But you keep reference to only last one created. When Media_Ended will start incoming, it will try to dispose only latest created resource.

Play real-time sound buffer using C# Media.SoundPlayer

I have developed a system in which a C# program receives sound buffers (byte arrays) from another subsystem. It is supposed to play the incoming buffers continuously. I searched in the web and I decided to use SoundPlayer. It works perfectly in the offline mode (play the buffers after receiving them all). However, I have a problem in the real-time mode.
In the real-time mode the program at first waits for a number of buffer arrays (for example 200) to receive and accumulate them. Then it adds a wav header and plays it. However, after that for each next 200 arrays it plays repeatedly the first buffer.
I have read following pages:
Play wav/mp3 from memory
https://social.msdn.microsoft.com/Forums/vstudio/en-US/8ac2847c-3e2f-458c-b8ff-533728e267e0/c-problems-with-mediasoundplayer?forum=netfxbcl
and according to their suggestions I implemented my code as follow:
public class MediaPlayer
{
System.Media.SoundPlayer soundPlayer;
public MediaPlayer(byte[] buffer)
{
byte[] headerPlusBuffer = AddWaveHeader(buffer, false, 1, 16, 8000, buffer.Length / 2); //add wav header to the **first** buffer
MemoryStream memoryStream = new MemoryStream(headerPlusBuffer, true);
soundPlayer = new System.Media.SoundPlayer(memoryStream);
}
public void Play()
{
soundPlayer.PlaySync();
}
public void Play(byte[] buffer)
{
soundPlayer.Stream.Seek(0, SeekOrigin.Begin);
soundPlayer.Stream.Write(buffer, 0, buffer.Length);
soundPlayer.PlaySync();
}
}
I use it like this:
MediaPlayer _mediaPlayer;
if (firstBuffer)
{
_mediaPlayer = new MediaPlayer(dataRaw);
_mediaPlayer.Play();
}
else
{
_mediaPlayer.Play(dataRaw);
}
Each time _mediaPlayer.Play(dataRaw) is called, the first buffer is played again and again; the dataRaw is updated though.
I appreciate your help.

Categories

Resources