There will be broken sounds at the beginning and end of the playing sound when using Microsoft Azure Text To Speech with Unity - azure

I am using Microsoft Azure Text To Speech with Unity. But there will be broken sounds at the beginning and end of the playing sound. Is this normal, or result.AudioData is broken. Below is the code.
public AudioSource audioSource;
void Start()
{
SynthesisToSpeaker("你好世界");
}
public void SynthesisToSpeaker(string text)
{
var config = SpeechConfig.FromSubscription("[redacted]", "southeastasia");
config.SpeechSynthesisLanguage = "zh-CN";
config.SpeechSynthesisVoiceName = "zh-CN-XiaoxiaoNeural";
// Creates a speech synthesizer.
// Make sure to dispose the synthesizer after use!
SpeechSynthesizer synthesizer = new SpeechSynthesizer(config, null);
Task<SpeechSynthesisResult> task = synthesizer.SpeakTextAsync(text);
StartCoroutine(CheckSynthesizer(task, config, synthesizer));
}
private IEnumerator CheckSynthesizer(Task<SpeechSynthesisResult> task,
SpeechConfig config,
SpeechSynthesizer synthesizer)
{
yield return new WaitUntil(() => task.IsCompleted);
var result = task.Result;
// Checks result.
string newMessage = string.Empty;
if (result.Reason == ResultReason.SynthesizingAudioCompleted)
{
var sampleCount = result.AudioData.Length / 2;
var audioData = new float[sampleCount];
for (var i = 0; i < sampleCount; ++i)
{
audioData[i] = (short)(result.AudioData[i * 2 + 1] << 8
| result.AudioData[i * 2]) / 32768.0F;
}
// The default output audio format is 16K 16bit mono
var audioClip = AudioClip.Create("SynthesizedAudio", sampleCount,
1, 16000, false);
audioClip.SetData(audioData, 0);
audioSource.clip = audioClip;
audioSource.Play();
}
else if (result.Reason == ResultReason.Canceled)
{
var cancellation = SpeechSynthesisCancellationDetails.FromResult(result);
}
synthesizer.Dispose();
}

The default audio format is Riff16Khz16BitMonoPcm, which has a riff header in the beginning of result.AudioData. If you pass the audioData to audioClip, it will play the header, then you hear some noise.
You can set the format to a raw format without header by speechConfig.SetSpeechSynthesisOutputFormat(SpeechSynthesisOutputFormat.Raw16Khz16BitMonoPcm);, see this sample for details.

Related

I can't see Videos in Processing, I only hear the audio from it

I'm trying to play one of two videos based on sensor from Arduino (for a University project)
The issue is that I can't see any of the videos in Processing but I only hear the audio.
I rendered the videos using the H264 codec and they are in Full HD.
I am using Processing 4.1.1.
This is my attempt at playing back video based on sensor values:
import processing.serial.*;
import processing.video.*;
Movie movie1, movie2;
boolean playing = false;
char previousIn;
Serial mySerial;
String myString = null;
int nl = 10;
float myVal;
void setup() {
size(1000, 1000);
frameRate(25);
String myPort =Serial.list()[2];
mySerial = new Serial(this, myPort, 9600);
movie1 = new Movie(this, "Final_Clips_HD.mp4");
movie2 = new Movie(this, "Final_Clips_HD_2.mp4");
}
void movieEvent(Movie movie) {
movie.read();
}
void draw() {
while (mySerial.available() > 0) {
myString = mySerial.readStringUntil(nl);
if (myString != null) {
myVal = float(myString);
println(myVal);
if (myVal > 10 && myVal < 20) {
movie1.play();
movie2.stop();
myVal = previousIn;
if (myVal == previousIn) {
movie1.jump(0);
}
}
image(movie1, 0, 0, width, height);
//fill(0,255,0);
if (myVal < 10 && myVal > 0) {
movie2.play();
movie1.stop();
myVal = previousIn;
if (myVal == previousIn) {
movie2.jump(0);
}
}
image(movie2, 0, 0, width, height);
}
}
}
You've got all the "ingredients" right, you might just need to shuffle them a bit. Well done on using H264 with Processing (I've seen previous errors with other video codecs) (and checking for null, etc.)
Currenty the movies are played only if there is a serial connection, a formatted string (sensor value) is sent and that value is within a range.
I would re-organise the code slightly so it can display a movie frame anytime (whatever that movie may be), then simply change the reference to the movie which is currently updated (based on the float value from serial).
(Additionally I'd also check for errors just in case the arduino isn't connected, is busy open in Serial Monitor, etc. Another minor tip is that yuo can use bufferUntil() once in setup and after that, just readString() from serialEvent()).
Here's a revised version of your code (with comments):
import processing.serial.*;
import processing.video.*;
Movie movie1, movie2;
Movie currentMovie;
boolean playing = false;
Serial mySerial;
// sensor values (current and previous)
float myVal;
float previousIn;
void setup() {
size(1000, 1000);
frameRate(25);
String myPort = Serial.list()[2];
// try to open the serial connection, but print error message if it fails
try{
mySerial = new Serial(this, myPort, 9600);
// tell arduino once to buffer until new line character is found
mySerial.bufferUntil('\n');
}catch(Exception e){
println("error opening serial connection to " + myPort);
e.printStackTrace();
}
// load movies
movie1 = new Movie(this, "Final_Clips_HD.mp4");
movie2 = new Movie(this, "Final_Clips_HD_2.mp4");
// reference one of the movies for updating
currentMovie = movie1;
}
void movieEvent(Movie movie) {
movie.read();
}
void draw() {
// render the current movie
image(currentMovie, 0, 0);
}
void serialEvent(Serial mySerial){
String myString = mySerial.readString();
if (myString != null) {
myVal = float(myString);
println(myVal);
if (myVal > 10 && myVal < 20) {
movie1.play();
movie2.stop();
myVal = previousIn;
if (myVal == previousIn) {
movie1.jump(0);
}
// update reference to the currently playing movie
currentMovie = movie1;
}
if (myVal < 10 && myVal > 0) {
movie2.play();
movie1.stop();
myVal = previousIn;
if (myVal == previousIn) {
movie2.jump(0);
}
// update reference to the currently playing movie
currentMovie = movie2;
}
}
}
Note that the above code isn't tested, so may not be 100% accurate: hopefully it illustrates the logic.

Combining WasapiLoopbackCapture with google Stream Recognition

I'm trying to write an app that will listen to my computer audio and transcribe it using Google Speach Recognition.
I've been able to record the system sound using WasapiLoopbackCapture and I've been able to use google streaming recognition api with test files, but I was not able to merge the two togther.
When I stream the audio from the WasapiLoopbackCapture to google it doesn't return any result.
I've based my code on the google code sample at:
https://github.com/GoogleCloudPlatform/dotnet-docs-samples/blob/9588cee6d96bfe484c8e189e9ac2f6eaa3c3b002/speech/api/Recognize/InfiniteStreaming.cs#L225
private WaveInEvent StartListening()
{
var waveIn = new WaveInEvent
{
DeviceNumber = 0,
WaveFormat = new WaveFormat(SampleRate, ChannelCount)
};
waveIn.DataAvailable += (sender, args) =>
_microphoneBuffer.Add(ByteString.CopyFrom(args.Buffer, 0, args.BytesRecorded));
waveIn.StartRecording();
return waveIn;
}
And adjusted it to use the WasapiLoopbackCapture:
private IDisposable StartListening()
{
var waveIn = new WasapiLoopbackCapture();
//var waveIn = new WaveInEvent
//{
// DeviceNumber = 0,
// WaveFormat = new WaveFormat(SampleRate, ChannelCount)
//};
SampleRate = waveIn.WaveFormat.SampleRate;
ChannelCount = waveIn.WaveFormat.Channels;
BytesPerSecond = SampleRate * ChannelCount * BytesPerSample;
Console.WriteLine(SampleRate);
Console.WriteLine(BytesPerSecond);
waveIn.DataAvailable += (sender, args) =>
_microphoneBuffer.Add(ByteString.CopyFrom(args.Buffer, 0, args.BytesRecorded));
waveIn.StartRecording();
return waveIn;
}
But it doesn't return any transcribed text.
I've saved the input stream to a file, and it played ok - so the sound is getting there, my guess is that the waveFormat that is received from the WasapiLoopback is not compatible with what google likes - I tried some conversion and couldn't get it to work.
I've reviewed the following topics on stack overflow, but still couldn't get it to work:
Resampling WasapiLoopbackCapture
Naudio - Convert 32 bit wav to 16 bit wav
And tried combining them both:
private IDisposable StartListening()
{
var waveIn = new WasapiLoopbackCapture();
//var waveIn = new WaveInEvent
//{
//DeviceNumber = 0,
//WaveFormat = new WaveFormat(SampleRate, ChannelCount)
//};
// SampleRate = waveIn.WaveFormat.SampleRate;
// ChannelCount = waveIn.WaveFormat.Channels;
// BytesPerSecond = waveIn.WaveFormat.AverageBytesPerSecond;// SampleRate * ChannelCount * BytesPerSample;
var target = new WaveFormat(SampleRate, 16, 1);
var writer = new WaveFileWriter(#"c:\temp\xx.wav", waveIn.WaveFormat);
Console.WriteLine(SampleRate);
Console.WriteLine(BytesPerSecond);
var stop = false;
waveIn.DataAvailable += (sender, args) =>
{
var a = args;
byte[] newArray16Bit = new byte[args.BytesRecorded / 2];
short two;
float value;
for (int i = 0, j = 0; i < args.BytesRecorded; i += 4, j += 2)
{
value = (BitConverter.ToSingle(args.Buffer, i));
two = (short)(value * short.MaxValue);
newArray16Bit[j] = (byte)(two & 0xFF);
newArray16Bit[j + 1] = (byte)((two >> 8) & 0xFF);
}
var resampleStream = new NAudio.Wave.Compression.AcmStream(new WaveFormat(waveIn.WaveFormat.SampleRate
,16,waveIn.WaveFormat.Channels), target);
Buffer.BlockCopy(newArray16Bit, 0, resampleStream.SourceBuffer, 0, a.BytesRecorded/2);
int sourceBytesConverted = 0;
var bytes = resampleStream.Convert(a.BytesRecorded/2, out sourceBytesConverted);
var converted = new byte[bytes];
Buffer.BlockCopy(resampleStream.DestBuffer, 9, converted,0, bytes);
a = new WaveInEventArgs(converted,bytes);
_microphoneBuffer.Add(ByteString.CopyFrom(a.Buffer, 0, a.BytesRecorded));
if (writer != null)
{
writer.Write(a.Buffer, 0, a.BytesRecorded);
if (writer.Position > waveIn.WaveFormat.AverageBytesPerSecond * 5)
{
stop = true;
writer.Dispose();
writer = null;
Console.WriteLine("Saved file");
}
}
};
waveIn.StartRecording();
return waveIn;
}
But it doesn't work.
I'm not sure if this is the right path.
A code sample of a fix would be highly appreciated
I tried converting the bit rate etc.. but couldn't get this to work.

Detect voice by audio recorder in android studio

Well, I would like to implement a function, such when the application starts, the recorder will start to recording, and when the user keeps silence there is nothing going to happen until the user speaks. Then, it will save the PCM file of user's voice and then stop recording.
Voice Detection in Android Application
Above is the question I have found similar as mine, but the answer of this link can not work. And I don't know how to modify it, since I don't understand the concept of the code.
Please help me~
Well, I solved my problem, here is my solution.
I modified the code came from this url:
Voice Detection in Android Application
private static final String TAG = "MainActivity";
private static int RECORDER_SAMPLERATE = 44100;
private static int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_STEREO;
private static int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
private Button btn, btn_convert, btn_play;
private TextView txv;
boolean isRecording = false;
private File file;
private AudioRecord audioRecord;
int bufferSizeInBytes = 0;
Context context = MainActivity.this;
// path
final String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/final.pcm" ;
final String outpath = path.replace(".pcm", ".wav");
public void autoRecording(){
// Get the minimum buffer size required for the successful creation of an AudioRecord object.
bufferSizeInBytes = AudioRecord.getMinBufferSize( RECORDER_SAMPLERATE,
RECORDER_CHANNELS,
RECORDER_AUDIO_ENCODING
);
// Initialize Audio Recorder.
AudioRecord audioRecorder = new AudioRecord( MediaRecorder.AudioSource.MIC,
RECORDER_SAMPLERATE,
RECORDER_CHANNELS,
RECORDER_AUDIO_ENCODING,
bufferSizeInBytes
);
// Start Recording.
txv.setText("Ing");
audioRecorder.startRecording();
isRecording = true;
// for auto stop
int numberOfReadBytes = 0;
byte audioBuffer[] = new byte[bufferSizeInBytes];
boolean recording = false;
float tempFloatBuffer[] = new float[3];
int tempIndex = 0;
// create file
file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/final.pcm");
Log.d(TAG, "recording: file path:" + file.toString());
if (file.exists()){
Log.d(TAG,"file exist, delete file");
file.delete();
}
try {
Log.d(TAG,"file created");
file.createNewFile();
} catch (IOException e) {
Log.d(TAG,"didn't create the file:" + e.getMessage());
throw new IllegalStateException("did not create file:" + file.toString());
}
// initiate media scan and put the new things into the path array to
// make the scanner aware of the location and the files you want to see
MediaScannerConnection.scanFile(context, new String[] {file.toString()}, null, null);
// output stream
OutputStream os = null;
DataOutputStream dos = null;
try {
os = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(os);
dos = new DataOutputStream(bos);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// While data come from microphone.
while( true )
{
float totalAbsValue = 0.0f;
short sample = 0;
numberOfReadBytes = audioRecorder.read( audioBuffer, 0, bufferSizeInBytes );
// Analyze Sound.
for( int i=0; i<bufferSizeInBytes; i+=2 )
{
sample = (short)( (audioBuffer[i]) | audioBuffer[i + 1] << 8 );
totalAbsValue += (float)Math.abs( sample ) / ((float)numberOfReadBytes/(float)2);
}
// read in file
for (int i = 0; i < numberOfReadBytes; i++) {
try {
dos.writeByte(audioBuffer[i]);
} catch (IOException e) {
e.printStackTrace();
}
}
// Analyze temp buffer.
tempFloatBuffer[tempIndex%3] = totalAbsValue;
float temp = 0.0f;
for( int i=0; i<3; ++i )
temp += tempFloatBuffer[i];
if( (temp >=0 && temp <= 2100) && recording == false ) // the best number for close to device: 3000
{ // the best number for a little bit distance : 2100
Log.i("TAG", "1");
tempIndex++;
continue;
}
if( temp > 2100 && recording == false )
{
Log.i("TAG", "2");
recording = true;
}
if( (temp >= 0 && temp <= 2100) && recording == true )
{
Log.i("TAG", "final run");
//isRecording = false;
txv.setText("Stop Record.");
//*/
tempIndex++;
audioRecorder.stop();
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
}
The function of this function:
if you call this function, the recorder will start recording, and once you make sound(Notify if there are some noise it will stop too.) it will stop recording and save into file(pcm format).

NAudio Mp3 decoding click and pops

I followed this NAudio Demo modified to play ShoutCast.
In my full code I have to resample the incoming audio and stream it again over the network to a network player. Since I get many "clicks and pops", I came back to the demo code and I found that these artifacts are originated after the decoding block.
If I save the incoming stream in mp3 format, it is pretty clear.
When I save the raw decoded data (without other processing than the decoder) I get many audio artifacts.
I wonder whether I am doing some error, even if my code is almost equal to the NAudio demo.
Here the function from the example as modified by me to save the raw data. It is called as a new Thread.
private void StreamMP3(object state)
{
//Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
//SettingsSection section = (SettingsSection)config.GetSection("system.net/settings");
this.fullyDownloaded = false;
string url = "http://icestreaming.rai.it/5.mp3";//(string)state;
webRequest = (HttpWebRequest)WebRequest.Create(url);
int metaInt = 0; // blocksize of mp3 data
int framesize = 0;
webRequest.Headers.Clear();
webRequest.Headers.Add("GET", "/ HTTP/1.0");
// needed to receive metadata informations
webRequest.Headers.Add("Icy-MetaData", "1");
webRequest.UserAgent = "WinampMPEG/5.09";
HttpWebResponse resp = null;
try
{
resp = (HttpWebResponse)webRequest.GetResponse();
}
catch (WebException e)
{
if (e.Status != WebExceptionStatus.RequestCanceled)
{
ShowError(e.Message);
}
return;
}
byte[] buffer = new byte[16384 * 4]; // needs to be big enough to hold a decompressed frame
try
{
// read blocksize to find metadata block
metaInt = Convert.ToInt32(resp.GetResponseHeader("icy-metaint"));
}
catch
{
}
IMp3FrameDecompressor decompressor = null;
byteOut = createNewFile(destPath, "salva", "raw");
try
{
using (var responseStream = resp.GetResponseStream())
{
var readFullyStream = new ReadFullyStream(responseStream);
readFullyStream.metaInt = metaInt;
do
{
if (mybufferedWaveProvider != null && mybufferedWaveProvider.BufferLength - mybufferedWaveProvider.BufferedBytes < mybufferedWaveProvider.WaveFormat.AverageBytesPerSecond / 4)
{
Debug.WriteLine("Buffer getting full, taking a break");
Thread.Sleep(500);
}
else
{
Mp3Frame frame = null;
try
{
frame = Mp3Frame.LoadFromStream(readFullyStream, true);
if (metaInt > 0)
UpdateSongName(readFullyStream.SongName);
else
UpdateSongName("No Song Info in Stream...");
}
catch (EndOfStreamException)
{
this.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
WaveFormat waveFormat = new Mp3WaveFormat(frame.SampleRate, frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frame.FrameLength, frame.BitRate);
decompressor = new AcmMp3FrameDecompressor(waveFormat);
this.mybufferedWaveProvider = new BufferedWaveProvider(decompressor.OutputFormat);
this.mybufferedWaveProvider.BufferDuration = TimeSpan.FromSeconds(200); // allow us to get well ahead of ourselves
framesize = (decompressor.OutputFormat.Channels * decompressor.OutputFormat.SampleRate * (decompressor.OutputFormat.BitsPerSample / 8) * 20) / 1000;
//this.bufferedWaveProvider.BufferedDuration = 250;
}
int decompressed = decompressor.DecompressFrame(frame, buffer, 0);
//Debug.WriteLine(String.Format("Decompressed a frame {0}", decompressed));
mybufferedWaveProvider.AddSamples(buffer, 0, decompressed);
while (mybufferedWaveProvider.BufferedDuration.Milliseconds >= 20)
{
byte[] read = new byte[framesize];
mybufferedWaveProvider.Read(read, 0, framesize);
byteOut.Write(read, 0, framesize);
}
}
} 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();
}
}
finally
{
if (decompressor != null)
{
decompressor.Dispose();
}
}
}
OK i found the problem. I included the shoutcast metadata to the MP3Frame.
See the comment "HERE I COLLECT THE BYTES OF THE MP3 FRAME" to locate the correct point to get the MP3 frame with no streaming metadata.
The following code runs without audio artifacts:
private void SHOUTcastReceiverThread()
{
//-*- String server = "http://216.235.80.18:8285/stream";
//String serverPath = "/";
//String destPath = "C:\\temp\\"; // destination path for saved songs
HttpWebRequest request = null; // web request
HttpWebResponse response = null; // web response
int metaInt = 0; // blocksize of mp3 data
int count = 0; // byte counter
int metadataLength = 0; // length of metadata header
string metadataHeader = ""; // metadata header that contains the actual songtitle
string oldMetadataHeader = null; // previous metadata header, to compare with new header and find next song
//CircularQueueStream framestream = new CircularQueueStream(2048);
QueueStream framestream = new QueueStream();
framestream.Position = 0;
bool bNewSong = false;
byte[] buffer = new byte[512]; // receive buffer
byte[] dec_buffer = new byte[decSIZE];
Mp3Frame frame;
IMp3FrameDecompressor decompressor = null;
Stream socketStream = null; // input stream on the web request
// create web request
request = (HttpWebRequest)WebRequest.Create(server);
// clear old request header and build own header to receive ICY-metadata
request.Headers.Clear();
request.Headers.Add("GET", serverPath + " HTTP/1.0");
request.Headers.Add("Icy-MetaData", "1"); // needed to receive metadata informations
request.UserAgent = "WinampMPEG/5.09";
// execute request
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
// read blocksize to find metadata header
metaInt = Convert.ToInt32(response.GetResponseHeader("icy-metaint"));
try
{
// open stream on response
socketStream = response.GetResponseStream();
var readFullyStream = new ReadFullyStream(socketStream);
frame = null;
// rip stream in an endless loop
do
{
if (IsBufferNearlyFull)
{
Debug.WriteLine("Buffer getting full, taking a break");
Thread.Sleep(500);
frame = null;
}
else
{
int bufLen = readFullyStream.Read(buffer, 0, buffer.Length);
try
{
if (framestream.CanRead && framestream.Length > 512)
frame = Mp3Frame.LoadFromStream(framestream);
else
frame = null;
}
catch (Exception ex)
{
frame = null;
}
if (bufLen < 0)
{
Debug.WriteLine("Buffer error 1: exit.");
return;
}
// processing RAW data
for (int i = 0; i < bufLen; i++)
{
// if there is a header, the 'headerLength' would be set to a value != 0. Then we save the header to a string
if (metadataLength != 0)
{
metadataHeader += Convert.ToChar(buffer[i]);
metadataLength--;
if (metadataLength == 0) // all metadata informations were written to the 'metadataHeader' string
{
string fileName = "";
string fileNameRaw = "";
// if songtitle changes, create a new file
if (!metadataHeader.Equals(oldMetadataHeader))
{
// flush and close old byteOut stream
if (byteOut != null)
{
byteOut.Flush();
byteOut.Close();
byteOut = null;
}
if (byteOutRaw != null)
{
byteOutRaw.Flush();
byteOutRaw.Close();
byteOutRaw = null;
}
timeStart = timeEnd;
// extract songtitle from metadata header. Trim was needed, because some stations don't trim the songtitle
//fileName = Regex.Match(metadataHeader, "(StreamTitle=')(.*)(';StreamUrl)").Groups[2].Value.Trim();
fileName = Regex.Match(metadataHeader, "(StreamTitle=')(.*)(';)").Groups[2].Value.Trim();
// write new songtitle to console for information
if (fileName.Length == 0)
fileName = "shoutcast_test";
fileNameRaw = fileName + "_raw";
framestream.reSetPosition();
SongChanged(this, metadataHeader);
bNewSong = true;
// create new file with the songtitle from header and set a stream on this file
timeEnd = DateTime.Now;
if (bWrite_to_file)
{
byteOut = createNewFile(destPath, fileName, "mp3");
byteOutRaw = createNewFile(destPath, fileNameRaw, "raw");
}
timediff = timeEnd - timeStart;
// save new header to 'oldMetadataHeader' string, to compare if there's a new song starting
oldMetadataHeader = metadataHeader;
}
metadataHeader = "";
}
}
else // write mp3 data to file or extract metadata headerlength
{
if (count++ < metaInt) // write bytes to filestream
{
//HERE I COLLECT THE BYTES OF THE MP3 FRAME
framestream.Write(buffer, i, 1);
}
else // get headerlength from lengthbyte and multiply by 16 to get correct headerlength
{
metadataLength = Convert.ToInt32(buffer[i]) * 16;
count = 0;
}
}
}//for
if (bNewSong)
{
decompressor = createDecompressor(frame);
bNewSong = false;
}
if (frame != null && decompressor != null)
{
framedec(decompressor, frame);
}
// fine Processing dati RAW
}//Buffer is not full
SHOUTcastStatusProcess();
} while (playbackState != StreamingPlaybackState.Stopped);
} //try
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
if (byteOut != null)
byteOut.Close();
if (socketStream != null)
socketStream.Close();
if (decompressor != null)
{
decompressor.Dispose();
decompressor = null;
}
if (null != request)
request.Abort();
if (null != framestream)
framestream.Dispose();
if (null != bufferedWaveProvider)
bufferedWaveProvider.ClearBuffer();
//if (null != bufferedWaveProviderOut)
// bufferedWaveProviderOut.ClearBuffer();
if (null != mono16bitFsinStream)
{
mono16bitFsinStream.Close();
mono16bitFsinStream.Dispose();
}
if (null != middleStream2)
{
middleStream2.Close();
middleStream2.Dispose();
}
if (null != resampler)
resampler.Dispose();
}
}
public class QueueStream : MemoryStream
{
long ReadPosition = 0;
long WritePosition = 0;
public QueueStream() : base() { }
public override int Read(byte[] buffer, int offset, int count)
{
Position = ReadPosition;
var temp = base.Read(buffer, offset, count);
ReadPosition = Position;
return temp;
}
public override void Write(byte[] buffer, int offset, int count)
{
Position = WritePosition;
base.Write(buffer, offset, count);
WritePosition = Position;
}
public void reSetPosition()
{
WritePosition = 0;
ReadPosition = 0;
Position = 0;
}
}
private void framedec(IMp3FrameDecompressor decompressor, Mp3Frame frame)
{
int Ndecoded_samples = 0;
byte[] dec_buffer = new byte[decSIZE];
Ndecoded_samples = decompressor.DecompressFrame(frame, dec_buffer, 0);
bufferedWaveProvider.AddSamples(dec_buffer, 0, Ndecoded_samples);
NBufferedSamples += Ndecoded_samples;
brcnt_in.incSamples(Ndecoded_samples);
if (Ndecoded_samples > decSIZE)
{
Debug.WriteLine(String.Format("Too many samples {0}", Ndecoded_samples));
}
if (byteOut != null)
byteOut.Write(frame.RawData, 0, frame.RawData.Length);
if (byteOutRaw != null) // as long as we don't have a songtitle, we don't open a new file and don't write any bytes
byteOutRaw.Write(dec_buffer, 0, Ndecoded_samples);
frame = null;
}
private IMp3FrameDecompressor createDecompressor(Mp3Frame frame)
{
IMp3FrameDecompressor dec = null;
if (frame != 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
WaveFormat srcwaveFormat = new Mp3WaveFormat(frame.SampleRate, frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frame.FrameLength, frame.BitRate);
dec = new AcmMp3FrameDecompressor(srcwaveFormat);
bufferedWaveProvider = new BufferedWaveProvider(dec.OutputFormat);// decompressor.OutputFormat
bufferedWaveProvider.BufferDuration = TimeSpan.FromSeconds(400); // allow us to get well ahead of ourselves
// ------------------------------------------------
//Create an intermediate format with same sampling rate, 16 bit, mono
middlewavformat = new WaveFormat(dec.OutputFormat.SampleRate, 16, 1);
outwavFormat = new WaveFormat(Fs_out, 16, 1);
// wave16ToFloat = new Wave16ToFloatProvider(provider); // I have tried with and without this converter.
wpws = new WaveProviderToWaveStream(bufferedWaveProvider);
//Check middlewavformat.Encoding == WaveFormatEncoding.Pcm;
mono16bitFsinStream = new WaveFormatConversionStream(middlewavformat, wpws);
middleStream2 = new BlockAlignReductionStream(mono16bitFsinStream);
resampler = new MediaFoundationResampler(middleStream2, outwavFormat);
}
return dec;
}

How to allow a file to be read by multiple users/process at a time on web server

I am using below code in asp.net webapi for audio streaming to allow android application to call api and play songs.
public class AudioController : ApiController
{
ITrackRepository _TrackRepo = new TrackRepository();
public AudioController()
{
}
public HttpResponseMessage Get(int id)
{
var trackd = _TrackRepo.GetPlayfilepath(id);
string filename = System.Web.HttpContext.Current.Server.MapPath(trackd.Select(x => x.FilePath).FirstOrDefault());
var audio = new AudioStream(filename);
string fileExtension = System.IO.Path.GetExtension(filename);
var response = Request.CreateResponse();
response.Content = new PushStreamContent(audio.WriteToStream, new MediaTypeHeaderValue("audio/" + fileExtension));
return response;
}
}
public class AudioStream
{
private readonly string _filename;
public AudioStream(string filename)
{
_filename = filename;
}
public async void WriteToStream(Stream outputStream, HttpContent content, TransportContext context)
{
try
{
var buffer = new byte[65536];
using (var video = File.Open(_filename, FileMode.Open, FileAccess.Read))
{
var length = (int)video.Length;
var bytesRead = 1;
while (length > 0 && bytesRead > 0)
{
bytesRead = video.Read(buffer, 0, Math.Min(length, buffer.Length));
await outputStream.WriteAsync(buffer, 0, bytesRead);
length -= bytesRead;
}
}
}
catch (HttpException ex)
{
return;
}
finally
{
outputStream.Close();
}
}
}
I am able to play song, i tested it with vlc (stream) and its working fine, Issue is when i try to play same song in parallel in another player its giving me below error
The process cannot access the file because it is being used by another
process.
I completely understand error, but i am not able to find any satisfactory solution.
one solution is to create a copy of song before play/stream and delete it on completion but i don't think that is a good solution.
please suggest.
I'm not at a computer with visual studio on it at the moment, but look at this overload for File.Open
Try changing this line:
using (var video = File.Open(_filename, FileMode.Open, FileAccess.Read))
to
using (var video = File.Open(_filename, FileMode.Open, FileAccess.Read, FileShare.Read))
See if that helps.

Resources