The code:
private async Task<int> Save()
{
StorageFile file = await DownloadsFolder.CreateFileAsync("a.exe");
IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite);
DataWriter writer = new DataWriter(stream);
byte[] buffer = new byte[4096];
writer.WriteBytes(buffer);
await writer.StoreAsync();
await writer.FlushAsync(); //Hang for a long time
writer.Dispose();
return 1001; //eventually it can get to this line, no exception is thrown
}
Edit:
It is found on Win8 CP build 8250, after upgraded to build 8375, the problem goes away. So I guess it is a bug that have been fixed either in winrt or win8.
You can try something more like this:
using (var fs = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (var outStream = fs.GetOutputStreamAt(0))
{
using (var dataWriter = new DataWriter(outStream))
{
byte[] buffer = new byte[4096];
dataWriter.WriteBytes(buffer)
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
await outStream.FlushAsync();
}
}
Related
I´m using Windows.Media.SpeechSynthesis for TTS and playing an audio signal works fine in my WPF application. I have wanted to save an audio signal but if I call StorageFolder I get an error: HRESULT: 0x80073D54 - The process has no package identity. How to fix it? The whole code is below. I would also like to know what rights apply to the use of an audio file from Win 10 TTS? I didn't find it anywhere - but I wasn't looking for that much...
private async void Talk(string text)
{
var stream = await speechSynthesizer.SynthesizeTextToStreamAsync(text);
StorageFolder localfolder = ApplicationData.Current.LocalFolder;
StorageFile sampleFile = await localfolder.CreateFileAsync("sample.wav", CreationCollisionOption.ReplaceExisting);
using (var reader = new DataReader(stream))
{
await reader.LoadAsync((uint)stream.Size);
IBuffer buffer = reader.ReadBuffer((uint)stream.Size);
await FileIO.WriteBufferAsync(sampleFile, buffer);
}
}
Finally, I have found a solution, how to save a stream from tts into *.wav or to *.mp3 by Naudio. I don´t know if it is clear but it is functional:
public bool ByteArrayToFile(string fileName, byte[] byteArray)
{
try
{
using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
fs.Write(byteArray, 0, byteArray.Length);
return true;
}
}
catch (Exception ex)
{
Console.WriteLine("Exception caught in process: {0}", ex);
return false;
}
}
private async Task SaveAudio(string text)
{
var stream = await speechSynthesizer.SynthesizeTextToStreamAsync(text);
using (var reader = new DataReader(stream))
{
await reader.LoadAsync((uint)stream.Size);
IBuffer buffer = reader.ReadBuffer((uint)stream.Size);
DataReader dataReader = DataReader.FromBuffer(buffer);
byte[] bytes = new byte[buffer.Length];
dataReader.ReadBytes(bytes);
//ByteArrayToFile("sample.wav", bytes);
ConvertWavStreamToMp3File(bytes, TB_File.Text);
MessageBox.Show("Audio was saved to file: " + TB_File.Text, "Info");
}
}
public static void ConvertWavStreamToMp3File(byte[] wavFile, string savetofilename)
{
using (var retMs = new MemoryStream())
using (var ms = new MemoryStream(wavFile))
using (var rdr = new WaveFileReader(ms))
using (var wtr = new LameMP3FileWriter(savetofilename, rdr.WaveFormat, LAMEPreset.VBR_90))
{
rdr.CopyTo(wtr);
}
}
i've an issue in my application. I'm trying to send an image into FTP server. I'm able to connect with server, authenticate, and other. But when i try to send file, if the file is big (usually bigger than 40-50kb) i got System.ObjectDisposedException.
This is the code that i use to send:
public async Task <byte[]> GetResultingBuffer(IRandomAccessStreamWithContentType readStream, IBuffer buffer)
{
var resultingBuffer = new byte[0];
while (true)
{
IBuffer readBuffer = await readStream.ReadAsync(buffer, 1024, InputStreamOptions.Partial);
if (readBuffer.Length == 0) break;
resultingBuffer = resultingBuffer.Concat(readBuffer.ToArray()).ToArray();
}
return resultingBuffer;
}
public async Task UploadFileAsync(StorageFile file, string destination)
{
using (var stream = await OpenWriteAsync(destination))
{
//
// A more efficient way, maybe a DataReader can be used here
using (var readStream = await file.OpenReadAsync())
{
var buffer = new byte[1024].AsBuffer();
var resultingBuffer = new byte[0];
resultingBuffer = await GetResultingBuffer(readStream, buffer);
await stream.WriteAsync(resultingBuffer.AsBuffer());
await stream.FlushAsync();
}
}
}
I tried to edit it, before editing GetResultingBuffer was not a task, but a cycle inside UploadFileAsnc. How can i prevent to dispose the buffer? Is there another solution? Thanks!
I solved it in this way
using (var readStream = await file.OpenReadAsync())
{
var buffer = new byte[3000000].AsBuffer();
//var resultingBuffer = new byte[10000000];
Debug.Write("-------");
//while (true)
//{
IBuffer readBuffer = await readStream.ReadAsync(buffer, 3000000, InputStreamOptions.Partial);
//if (readBuffer.Length == 0) break;
//resultingBuffer = resultingBuffer.Concat(readBuffer.ToArray()).ToArray();
//}
// await stream.WriteAsync(resultingBuffer.AsBuffer());
var resultingBuffer = new byte[readBuffer.Length];
readBuffer.CopyTo(resultingBuffer);
await stream.WriteAsync(resultingBuffer.AsBuffer());
}
Debug.Write("-------");
await stream.FlushAsync();
How can I finalize/close the BitmapEncoder on UWP?
InMemoryRandomAccessStream imras = new InMemoryRandomAccessStream();
await [...] //Fill stream
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(imras);
[...] //Do something
StorageFile sf = await ApplicationData.Current.LocalFolder.CreateFileAsync("123.jpg", CreationCollisionOption.ReplaceExisting);
BitmapEncoder bmpEncoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, await sf.OpenAsync(FileAccessMode.ReadWrite));
[...]
await bmpEncoder.FlushAsync();
imras.Dispose();
Now when I try to access the file, I get a System.UnauthorizedAccessException, I have to close the UWP app to be able to access this file... How can I close it?
You need to dispose every IDisposable object. The easiest way is to use using keyword.
using (var stream = await storageFile.OpenAsync()) // Or any other method that will open a stream.
{
var bitmapDecoder = await BitmapDecoder.CreateAsync(stream);
using (var randomAccessStream = new InMemoryRandomAccessStream())
{
var bitmapEncoder = await BitmapEncoder.CreateForTranscodingAsync(randomAccessStream, bitmapDecoder);
// Do stuff.
await bitmapEncoder.FlushAsync();
var buffer = new byte[randomAccessStream.Size];
await randomAccessStream.AsStream().ReadAsync(buffer, 0, buffer.Length);
var someNewFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("SomeFileName", CreationCollisionOption.ReplaceExisting);
await FileIO.WriteBytesAsync(someNewFile, buffer);
}
}
I recorded sound with the device's microphone but I don't know how to save it. Is it with the help of MediaCapture element, and if yes, then how to do it?
Here is a basic idea how to convert to mp3 and save in a file with Datawriter.
I wrote this code on the fly so its not tested.
MediaEncodingProfile _Profile = Windows.Media.MediaProperties.MediaEncodingProfile.CreateMp3(AudioEncodingQuality.High);
MediaTranscoder _Transcoder = new Windows.Media.Transcoding.MediaTranscoder();
CancellationTokenSource _cts = new CancellationTokenSource();
private void ConvertSteamToMp3()
{
IRandomAccessStream audio = buffer.CloneStream(); //your recoreded InMemoryRandomAccessStream
var folder = KnownFolders.MusicLibrary.CreateFolderAsync("MyCapturedAudio", CreationCollisionOption.OpenIfExists);
outputFile = await folder.CreateFileAsync("record.mp3", CreationCollisionOption.GenerateUniqueName);
using (IRandomAccessStream fileStream = await outputFile.OpenAsync(FileAccessMode.ReadWrite))
{
var preparedTranscodeResult = await _Transcoder.PrepareStreamTranscodeAsync(audio, fileStream, _Profile);
if (preparedTranscodeResult.CanTranscode)
{
var progress = new Progress<double>(TranscodeProgress);
await preparedTranscodeResult.TranscodeAsync().AsTask(_cts.Token, progress);
}
using (IOutputStream outputStream = fileStream.GetOutputStreamAt(0))
{
using (DataWriter dataWriter = new DataWriter(outputStream))
{
//TODO: Replace "Bytes" with the type you want to write.
dataWriter.WriteBytes(bytes);
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
await outputStream.FlushAsync();
}
}
}
Or just save the stream in a file
public async SaveToFile()
{
IRandomAccessStream audio = buffer.CloneStream(); //your recoreded InMemoryRandomAccessStream
var folder = KnownFolders.MusicLibrary.CreateFolderAsync("MyCapturedAudio", CreationCollisionOption.OpenIfExists);
outputFile = await folder.CreateFileAsync("record.mp3", CreationCollisionOption.GenerateUniqueName);
using (IRandomAccessStream fileStream = await outputFile.OpenAsync(FileAccessMode.ReadWrite))
{
await RandomAccessStream.CopyAndCloseAsync(audio.GetInputStreamAt(0), fileStream.GetOutputStreamAt(0));
await audio.FlushAsync();
audio.Dispose();
}
});
}
I would like to have a method which takes as an input a System.IO.Stream and use it to write data from it to file. So far I have the following:
public async Task SaveStreamToFileX(Stream stream, string filePath, IProgress<long> progress)
{
var folder = await StorageFolder.GetFolderFromPathAsync(Path.GetDirectoryName(filePath));
var fileName = Path.GetFileName(filePath);
StorageFile file = await folder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists);
var istream = stream.AsInputStream();
var canRead = stream.CanRead; //this returns true
using (var reader = new DataReader(istream))
{
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (IOutputStream outputStream = fileStream.GetOutputStreamAt(0))
{
using (DataWriter writer = new DataWriter(outputStream))
{
IBuffer buffer;
long readBytes = 0;
const int bufferSize = 8192;
while ((buffer = reader.ReadBuffer(bufferSize)).Length > 0) //exception System.Exception with message: Out of range ...
{
writer.WriteBuffer(buffer);
readBytes += bufferSize;
progress.Report(readBytes);
}
}
}
}
}
}
Problem is, that an exception (Out of range) is thrown when I try to read data in while cycle (first read). Stream should have data. I am not sure if so long code is neccesarry, if somebody has better solution it would be great.
Side note:
If I try await reader.LoadAsync(50) it returns 50. I am not sure what LoadAsync should do. Maybe I have to call it before read to prepare data for the read? I will investigate this further ...
Also, the Stream.CanRead returns true.
The problem was not with converting streams as I orginally thought. It was just lack of the knowlidge how the work with files is done in WinRT (the docs from microsoft are really terrible in my opinion).
In the end with help of my collegue with tried several ways and end up with the following:
public async Task SaveStreamToFile(Stream stream, string filePath, IProgress<long> progress )
{
var folder = await StorageFolder.GetFolderFromPathAsync(Path.GetDirectoryName(filePath));
var fileName = Path.GetFileName(filePath);
StorageFile file = await folder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists);
var istream = stream.AsInputStream();
using (var reader = new DataReader(istream))
{
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (IOutputStream outputStream = fileStream.GetOutputStreamAt(0))
{
using (DataWriter writer = new DataWriter(outputStream))
{
long writtenBytes = 0;
const int bufferSize = 8192;
uint loadedBytes = 0;
while ((loadedBytes = (await reader.LoadAsync(bufferSize))) > 0) //!!!
{
IBuffer buffer = reader.ReadBuffer(loadedBytes);
writer.WriteBuffer(buffer);
uint tmpWritten = await writer.StoreAsync(); //!!!
writtenBytes += tmpWritten;
progress.Report(writtenBytes);
}
}
}
}
}
}
I would like to see some simpler implementation, but this works. The problems were that LoadAsync was missing (which seems to be necessary to call) and during write operation the StoreAsync must be called in order to commit the data (flushing was not sufficient).
I hope this help somebody.
I would advise against that kind of code and instead take advantage of Windows Runtime Interop extension methods. That would produce a neater and more readable code, ex :
private async Task CopyToTempFile(Stream stream, string temporaryFileName) {
var file = await ApplicationData.Current.TemporaryFolder.CreateFileAsync(temporaryFileName, CreationCollisionOption.ReplaceExisting);
using (var outputstream = await file.OpenStreamForWriteAsync()) {
await stream.CopyToAsync(outputstream);
}
}