I am trying to output a text-to-speech wav file and play it with the HTML5 <audio> tag. The text-to-speech method is outputting the bytes, but the html5 control isn't playing it.
If instead of streaming the bytes directly to the control, i save it as a file first, then convert the file to bytes with filestream and output them, it starts to play, but i don't want to have to save the file every time. I'm using MVC 4.
// in a class library
public byte[] GenerateAudio(string randomText)
{
MemoryStream wavAudioStream = new MemoryStream();
SpeechSynthesizer speechEngine = new SpeechSynthesizer();
speechEngine.SetOutputToWaveStream(wavAudioStream);
speechEngine.Speak(randomText);
wavAudioStream.Flush();
Byte[] wavBytes = wavAudioStream.GetBuffer();
return wavBytes;
}
// in my controller
public ActionResult Listen()
{
return new FileContentResult(c.GenerateAudio(Session["RandomText"].ToString()), "audio/wav");
}
// in my view
<audio controls autoplay>
<source src="#Url.Content("~/Captcha/Listen")" type="audio/wav" />
Your browser does not support the <audio> element.
</audio>
I am also playing back a wav file to an audio element, and your code has the same logic as mine. I just noticed that you are flushing your stream before you return the byte array, which will seem to be empty.
Also, you can use file as return type and pass the byte array to its constructor. The content type is just the same as in your code. I would like to mention (maybe it could be a help also) that I used 2 streams: an outside scope stream and the actual stream where the data will be saved. After I have populated the actual stream I copied its contents to the outside stream using stream.CopyTo() and the instance of that outside stream is the one I used in my return statement. This avoids the error "Cannot Access Closed stream" (not the exact the error statement).
Related
I want to add a button that will download a dynamically generated CSV file.
I think I need to use FileStreamResult (or possibly FileContentResult) but I have been unable to find an example that shows how to do this.
I've seen examples that create a physical file, and then download that. But my ideal solution would write directly to the response stream, which would be far more efficient than creating a file or first building the string in memory.
Has anyone seen an example of dynamically generating a file for download in Razor Pages (not MVC)?
So here's what I came up with.
Markup:
<a class="btn btn-success" asp-page-handler="DownloadCsv">
Download CSV
</a>
Handler:
public IActionResult OnGetDownloadCsv()
{
using MemoryStream memoryStream = new MemoryStream();
using CsvWriter writer = new CsvWriter(memoryStream);
// Write to memoryStream using SoftCircuits.CsvParser
writer.Flush(); // This is important!
FileContentResult result = new FileContentResult(memoryStream.GetBuffer(), "text/csv")
{
FileDownloadName = "Filename.csv""
};
return result;
}
This code works but I wish it used memory more efficiently. As is, it writes the entire file contents to memory, and then copies that memory to the result. So a large file would exist twice in memory before anything is written to the response stream. I was curious about FileStreamResult but wasn't able to get that working.
If someone can improve on this, I'd gladly mark your answer as the accepted one.
UPDATE:
So I realized I can adapt the code above to use FileStreamResult by replacing the last block with this:
memoryStream.Seek(0, SeekOrigin.Begin);
FileStreamResult result = new FileStreamResult(memoryStream, "text/csv")
{
FileDownloadName = "Filename.csv"
};
return result;
This works almost the same except that, instead of calling memoryStream.GetBuffer() to copy all the bytes, it just passes the memory stream object. This is an improvement as I am not needlessly copying the bytes.
However, the downside is that I have to remove my two using statements or else I'll get an exception:
ObjectDisposedException: Cannot access a closed Stream.
Looks like it's a trade off between copying the bytes an extra time or not cleaning up my streams and CSV writer.
In the end, I'm able to prevent the CSV writer from closing the stream when it's disposed, and since MemoryStream does not have unmanaged resources there should be no harm in leaving it open.
In my c# program, I have an image which is successfully stored in a byte[] data called bytes. I successfully write it into a .txt file using the following code
using (FileStream file = new FileStream("text.txt", FileMode.Create, FileAccess.Write))
{
file.Write(bytes, 0, numToWrite);
file.Close();
}
The above code stores the exact content I wish to store.
Whenever I wish to read the content of the file, text.txt, into textbox I only get the first line or little part of the first line. But when I open the file, text.txt, I see the complete content.
This is the code I use to read the file
string kk = File.ReadAllText("text.txt");
You have said at the start of the question that you have a byte[] that you are writing into the file. It's not clear why you decided not to use File.WriteAllBytes but let's assume that your code is correctly writing all the data into the file called "text.txt", which has been explained in comments does not magically make this a text file.
Using File.ReadAllText is not going to work because The data in the file is binary data, not text. As you can see from the remarks on the documentation, it will try to decide the encoding of the text file (which won't work because it contains binary data) and will do end of line processing which you won't want for a binary file.
The best way to read the data back is to use File.ReadAllBytes, which gives you back a byte[], just like you started with.
I'm using C#.NET I'm getting a live video stream from a url(rtsp://streamurl). Now I want to know if we can convert this live stream into a byte array so that I can use NReco.VideoConverter component to encode this Stream using .h264 and then stream it via a server.
I'm currently gathering details and studying basics on NReco.VideoEncoder. It has a method to convert a live video stream, but for the input file, it requires System.IO.Stream instead of a URL path. That's why I'm asking this question. Thanks!
I have no experience with NReco.VideoEncoder, so this is just a guess:
When looking at your link to the interface you'll see:
public ConvertLiveMediaTask ConvertLiveMedia(
Stream inputStream,
string inputFormat,
string outputFile,
string outputFormat,
ConvertSettings settings
)
Stream is very flexible (first input param), so you should be able to use anything from file as well as web... so you should be able to do it this way (haven't compiled this code):
// convert url to stream
WebRequest request=WebRequest.Create(url); // your rtsc url?
request.Timeout=30*60*1000;
request.UseDefaultCredentials=true;
request.Proxy.Credentials=request.Credentials;
WebResponse response=(WebResponse)request.GetResponse();
using (Stream stream = response.GetResponseStream())
{
var converter = new FFMpegConverter(); // init converter
converter.ConvertLiveMedia(stream, // put your stream here
"???", // problem here... no rtsc support in Formats enum found, so you might need to know the video format
"C:\whateverpath\whatever.hevc", // extension?
Format.h265);
}
I don't see how rtsc is supported here and you might need to now what kind of video encoding is packed into rtsc first, otherwise the converter doesn't understand the input (at least when using this interface you mentioned).
And that's what I meant in my comment: You need to know the data structure of the (byte) stream to know how to interpret the bits or you have to make a guess.
Their website states the feature:
Live video stream transcoding from C# Stream (or Webcam, RTSP URL, file) to C#
Stream (or streaming server URL, 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
I planning to load PDF files into it, but I can't save those to disk. PDFs exist only as byte arrays in my program.
For text data I can use something like this:
webBrowser1.DocumentText = "<html>page content</html>";
But PDF is not text, so I need some other way, but can't find any.
I tried this:
byte[] file_content = File.ReadAllBytes("C:\\Users\\Metafalica\\Documents\\DatabaseSQLLanguageRzheutskaya.pdf");
MemoryStream ms = new MemoryStream(file_content);
ms.Flush();
ms.Position = 0;
webBrowser1.DocumentStream = ms;
But getting this:
It's not possible to load and render a PDF via webBrowser.DocumentStream. What happens behind the scene is that an instance of MSHTML Document Object gets created and initialized with the supplied stream. You could possibly load an image (which MIME type is recognized by MSHTML), but not a PDF. On the other hand, when webBrowser.Navigate is used, an instance of Adobe Acrobat Reader PDF Document gets created, rather than MSHTML.