Quantcast
Channel: NAudio
Viewing all 5831 articles
Browse latest View live

New Post: NAudio 1.6 - Wasapi Loopback COMException

$
0
0

Hi Mark,

 

i think this worth notice: the below code works fine (despite the audio is set to "dataflow.render" mode , rather than "dataflow.capture" mode) as per the discussion in the above link.

the only thing i noticed is : when calling the "wasapi.stoprecording method, the software freezes, i am still working on it.

 

 

the code now looks as follows:

 

Imports naudio
Imports naudio.wave
Imports NAudio.CoreAudioApi


Public Class Form1
    Dim WithEvents Wasapi As WasapiLoopbackCapture
    Dim Writer As WaveFileWriter
    Dim mmdev As MMDeviceEnumerator
    Dim Audio As MMDevice



    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        mmdev = New MMDeviceEnumerator
        'Audio.AudioClient.Initialize(AudioClientShareMode.Shared, AudioClientStreamFlags.Loopback, 10000000, 0, Audio.AudioClient.MixFormat, System.Guid.Empty)
        Audio = mmdev.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia)
        Wasapi = New WasapiLoopbackCapture(Audio)
        Writer = New WaveFileWriter("E:\4.wav", Audio.AudioClient.MixFormat)
        Wasapi.WaveFormat = Audio.AudioClient.MixFormat

    End Sub

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        Application.Exit()
    End Sub

    Private Sub Wasapi_DataAvailable(sender As Object, e As WaveInEventArgs) Handles Wasapi.DataAvailable
        Writer.Write(e.Buffer, 0, e.BytesRecorded)

    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        If Wasapi IsNot Nothing Then
            Wasapi.StartRecording()
        End If
        ''''
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        If Wasapi IsNot Nothing Then
            Wasapi.StopRecording()
            Wasapi.Dispose()
            Wasapi = Nothing
        End If
        ''
        ''
        If Writer IsNot Nothing Then
            Writer.Flush()
            Writer.Close()
            Writer.Dispose()
            Writer = Nothing
        End If
        ''
       
    End Sub

    Private Sub Wasapi_RecordingStopped(sender As Object, e As EventArgs) Handles Wasapi.RecordingStopped
        '''''
        If Writer IsNot Nothing Then
            Writer.Flush()
            Writer.Close()
            Writer.Dispose()
            Writer = Nothing
        End If

        ''''
        If Wasapi IsNot Nothing Then
            Wasapi.StopRecording()
            Wasapi.Dispose()
            Wasapi = Nothing
        End If

        ''''
    End Sub

  
End Class

 


New Post: Multiple WaveIn MMException

$
0
0

Hi all,

I must mix multiple wavein sources from different wavein devices for switching the output of mixer to another waveOut device.

Also, I must mix udp source wave streams with wavein streams, too.

First of all, I have decided to code the analog part like this below.

public void LoadWaveInToMixer(int deviceNumberIN)           

{

WaveIn ss = new WaveIn();               

ss.DeviceNumber = deviceNumberIN;     //always different device numbers           

ss.WaveFormat = new WaveFormat(8000, 16, 2);               

ss.StartRecording();                               

WaveInProvider wp = new WaveInProvider(ss);               

WaveProviderToWaveStream ws = new WaveProviderToWaveStream(wp); 

WaveChannel32 wc = new WaveChannel32(ws);

mixer.AddInputStream(wc);  //WaveMixerStream32 object

if (mixer.InputCount == 1)                

{                   

waveOutDevice.Init(mixer);                   

waveOutDevice.Play();               

}

}

 

My problem is if I add second waveIn device to the mixer(call this functon twice), I am getting and MMEXception (already allocated)

I have set deviceNumberIN to different device numbers every time I call this function. I have collected devices present in the system at the beginning of the program.

Thanks,

New Post: wma arggggggg

$
0
0

Hello,

I have a good start solution without any change.
Just MediaFoundation initialized in the procedure Read and everyone is under the same background processes.
It works with all drivers.
Well, it is not very elegant as a method but it is a start.

New Post: wma arggggggg

$
0
0

OK that's interesting. You could put the MF initialization into the ThreadProc on WasapiOut and maybe that will do it. ASIO would be a more difficult solution, since we don't creat the threads, but you could do a one-time initialization, with the hope that the callback always comes back on the same thread.

New Post: wma arggggggg

$
0
0

I tested this solution in the driver but without success.
In idea I rotated the routine WaveStream MediaFoundationReader Read
Adding a Flag (MfStart) and initialized the mediaFoundation once.
Thus procésus MF is valid for all drivers (even ASIO)
I suspect that your choice is a more elegant solution.
I just downloaded the new version to make an example.

 

New Post: wma arggggggg

$
0
0

I'd be interested to see the code you are using. I was thinking of having some kind of class in NAudio that ensured it was only called once, but maybe it should be called once per thread.

New Post: wma arggggggg

$
0
0

I think I'm having problems (position, stop, ...)

New Post: wma arggggggg

$
0
0

this is a example.

Only Procedure modified

privatestring _file = "";private IMFSourceReader pReaderTh;privatebool MFStart = false;

       // Change pReader = Init()
        public MediaFoundationReader(string file)
        {
			_file = file;
			pReader = Init();
			length = GetLength();
        }// Init MediaFoundation private IMFSourceReader Init()
		{
			IMFSourceReader retReader;//if (!initialized)//{// once only per app - TODO, maybe move this elsewhere
				MediaFoundationInterop.MFStartup(MediaFoundationInterop.MF_VERSION);//	initialized = true;//}var uri = new Uri(_file);
			MediaFoundationInterop.MFCreateSourceReaderFromURL(uri.AbsoluteUri, IntPtr.Zero, out retReader);
			retReader.SetStreamSelection(MediaFoundationInterop.MF_SOURCE_READER_ALL_STREAMS, false);
			retReader.SetStreamSelection(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, true);/*IMFMediaType currentMediaType;
			pReader.GetCurrentMediaType(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, out currentMediaType);
			Guid currentMajorType;
			currentMediaType.GetMajorType(out currentMajorType);
			IMFMediaType nativeMediaType;
			pReader.GetNativeMediaType(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, out nativeMediaType);*/// Create a partial media type indicating that we want uncompressed PCM audio
			IMFMediaType partialMediaType = null;
			MediaFoundationInterop.MFCreateMediaType(ref partialMediaType);
			partialMediaType.SetGUID(MediaFoundationInterop.MF_MT_MAJOR_TYPE, MediaFoundationInterop.MFMediaType_Audio);
			partialMediaType.SetGUID(MediaFoundationInterop.MF_MT_SUBTYPE, MediaFoundationInterop.MFAudioFormat_PCM);// set the media type
			retReader.SetCurrentMediaType(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, IntPtr.Zero, partialMediaType);
			Marshal.ReleaseComObject(partialMediaType);// now let's find out what we actually got
			IMFMediaType uncompressedMediaType;
			retReader.GetCurrentMediaType(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, out uncompressedMediaType);// Two ways to query it, first is to ask for properties (section is to convet into WaveFormatEx using MFCreateWaveFormatExFromMFMediaType)
			Guid actualMajorType;
			uncompressedMediaType.GetGUID(MediaFoundationInterop.MF_MT_MAJOR_TYPE, out actualMajorType);
			Debug.Assert(actualMajorType == MediaFoundationInterop.MFMediaType_Audio);
			Guid audioSubType;
			uncompressedMediaType.GetGUID(MediaFoundationInterop.MF_MT_SUBTYPE, out audioSubType);
			Debug.Assert(audioSubType == MediaFoundationInterop.MFAudioFormat_PCM);int channels;
			uncompressedMediaType.GetUINT32(MediaFoundationInterop.MF_MT_AUDIO_NUM_CHANNELS, out channels);int bits;
			uncompressedMediaType.GetUINT32(MediaFoundationInterop.MF_MT_AUDIO_BITS_PER_SAMPLE, out bits);int sampleRate;
			uncompressedMediaType.GetUINT32(MediaFoundationInterop.MF_MT_AUDIO_SAMPLES_PER_SECOND, out sampleRate);

			waveFormat = new WaveFormat(sampleRate, bits, channels);

			retReader.SetStreamSelection(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, true);return retReader;
		}///<summary>/// Reads from this wave stream///</summary>///<param name="buffer">Buffer to read into</param>///<param name="offset">Offset in buffer</param>///<param name="count">Bytes required</param>///<returns>Number of bytes read; 0 indicates end of stream</returns>publicoverrideint Read(byte[] buffer, int offset, int count)
		{
// Here Init MF if (MFStart == false)
			{
				pReaderTh = Init();var pv = PropVariant.FromLong(position);
				pReaderTh.SetCurrentPosition(Guid.Empty, ref pv);
				MFStart = true;
			}int bytesWritten = 0;// read in any leftovers from last timeif (decoderOutputCount > 0)
			{
				bytesWritten += ReadFromDecoderBuffer(buffer, offset, count - bytesWritten);
			}while (bytesWritten < count)
			{
				IMFSample pSample;int dwFlags;ulong timestamp;int actualStreamIndex;
				pReaderTh.ReadSample(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, out actualStreamIndex, out dwFlags, out timestamp, out pSample);if (dwFlags != 0)
				{// reached the end of the stream or media type changedbreak;
				}/*
                if (dwFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)
                {
                    printf("Type change - not supported by WAVE file format.\n");
                    break;
                }
                if (dwFlags & MF_SOURCE_READERF_ENDOFSTREAM)
                {
                    printf("End of input file.\n");
                    break;
                }*/

				IMFMediaBuffer pBuffer;
				pSample.ConvertToContiguousBuffer(out pBuffer);
				IntPtr pAudioData = IntPtr.Zero;int cbBuffer;int pcbMaxLength;
				pBuffer.Lock(out pAudioData, out pcbMaxLength, out cbBuffer);
				EnsureBuffer(cbBuffer);
				Marshal.Copy(pAudioData, decoderOutputBuffer, 0, cbBuffer);
				decoderOutputOffset = 0;
				decoderOutputCount = cbBuffer;

				bytesWritten += ReadFromDecoderBuffer(buffer, offset + bytesWritten, count - bytesWritten);


				pBuffer.Unlock();
				Marshal.ReleaseComObject(pBuffer);
				Marshal.ReleaseComObject(pSample);
			}
			position += bytesWritten;
			return bytesWritten;
		}


New Post: wma arggggggg

$
0
0

oupsss only add & change

// Add Varprivatestring _file = "";private IMFSourceReader pReaderTh;privatebool MFStart = false;// change thispublic MediaFoundationReader(string file)
        {
			_file = file;
			pReader = Init();
			length = GetLength();
        }// Add Init procedureprivate IMFSourceReader Init()
	{
		IMFSourceReader retReader;
.... 
}// Add in Readpublicoverrideint Read(byte[] buffer, int offset, int count)
{if (MFStart == false)
	{
		pReaderTh = Init();var pv = PropVariant.FromLong(position);
		pReaderTh.SetCurrentPosition(Guid.Empty, ref pv);
		MFStart = true;
	}

........ same 

}

New Post: wma arggggggg

$
0
0

OK, so you are creating a completely different stream for reading to the one you created in the constructor which was used to get the file duration. You might run into problems with reposition, because those will come in from the GUI thread.

New Post: wma arggggggg

$
0
0

Modified  for Position

///<summary>/// Current position within this stream///</summary>publicoverridelong Position
        {get { return position; }set
            {// should pass in a variant of type VT_I8 which is a long containing time in 100nanosecond unitslong nsPosition = (10000000L * value) / waveFormat.AverageBytesPerSecond;var pv = PropVariant.FromLong(nsPosition);
                pReader.SetCurrentPosition(Guid.Empty, ref pv);
                position = value;// ADD THISif (pReaderTh != null)
		{
			pReaderTh.SetCurrentPosition(Guid.Empty, ref pv);
		}// END ADD
                decoderOutputCount = 0;
                decoderOutputOffset = 0;
            }
        }

New Post: wma arggggggg

$
0
0

there's no point keeping two instances open. You might as well dispose the one created in the constructor after you've got the length from it. Also, you will need some kind of locking as the Position setter and Read could run at the same time, meaning that decoderOutputCount and decoderOutputOffset could run at the same time. I'm surprised it lets you access pReaderTh from the GUI thread, but maybe the fact it was created on an MTAThread makes it safe to call from an STAThread.

New Post: wma arggggggg

$
0
0

Position actually I have problems.

Well it was a good idea :-) No :-(

New Post: wma arggggggg

$
0
0

 

Position :: SOLVED (for the moment)

// Modifiedpublicoverridelong Position
        {
            get { return position; }
            set
            {
		
                position = value;
	        IsChangePosition = true;
			
            }
        }

// Read Changedpublicoverrideint Read(byte[] buffer, int offset, int count)
{

	if (MFStart == false)
	{
		pReaderTh = Init();
		decoderOutputCount = 0;
		decoderOutputOffset = 0;
		MFStart = true;
	}

	if (IsChangePosition)
	{
		long nsPosition = (10000000L * position) / waveFormat.AverageBytesPerSecond;
		var pv = PropVariant.FromLong(nsPosition);
		pReaderTh.SetCurrentPosition(Guid.Empty, ref pv);
		IsChangePosition = false;
				
	}

......
}

 

I deleted the pReader

New Post: wma arggggggg

$
0
0

yes, this is one of the best ways to do repositioning with multithreaded code. You basically just set a reposition flag (still needs to be threadsafe). The only disadvantage is that when you reposition while paused, it looks as if nothing has happened. You also must move these lines into the Read method:

                decoderOutputCount = 0;
                decoderOutputOffset = 0;

New Post: wma arggggggg

$
0
0
The only disadvantage is that when you reposition while paused, it looks as if nothing has happened. You also must move these lines into the Read method:

 

??

the latest version (read) works even during the Pause !

 

For information

Test with your Demo (AudioPlaybackDemo) (just add WmaInputFilePlugin.cs)

New Post: wma arggggggg

$
0
0

The issue is that you either have to "pretend" the reposition has happened, by setting position to the supplied value, or leave position as it was and change it when the reposition is actually performed. The former is probably preferable. You really do need to move those decoder variables being set to 0 into the Read function though, or you could get corruption in the playback thread if you were repositioning while a Read was in progress.

New Post: Multiple WaveIn MMException

$
0
0

what device IDs are you using? Do you definitely have two soundcards?

New Post: Converting WAVs to AIFFs

New Post: wma arggggggg

$
0
0

I'm afraid, I do not quite understand your comment

To clarify the situation:

 

 

publicoverrideint Read(byte[] buffer, int offset, int count)
{

	if (MFStart == false)
	{
		pReaderTh = Init();
		//SetPosition();
		MFStart = true;
	}

	SetPosition();

..................
}

			
// Position pReaderThprivatevoid SetPosition()
	{
			
		if (IsChangePosition)
		{
			long nsPosition = (10000000L * position) / waveFormat.AverageBytesPerSecond;
			var pv = PropVariant.FromLong(nsPosition);
			pReaderTh.SetCurrentPosition(Guid.Empty, ref pv);
			IsChangePosition = false;
			decoderOutputCount = 0;
			decoderOutputOffset = 0;
		}
	}
Viewing all 5831 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>