Need help to make a Virtual Audio Loop-back Cable

Ab9078ea733a220836e34c8c152c8597
0
syamkumar 101 Sep 25, 2013 at 06:15 windows audio

Hi friends, I am going to make a Virtual Audio Loop-back Cable/Pipeline(a Virtual Audio Device). MSVAD source code getting along with WDK only perform capture and save audio data which appears at the input port of the device, I don’t know how to implement CopyTo and CopyFrom functions to make a VALC such that any audio data appears at the input port of VALC (Virtual Audio Device) is available at the output port of VALC (similar to Virtual Audio Cable v4.13).Please help me to code CopyTo and CopyFrom functions? I got a source code of an Audio Loop-back Driver whose functions similar to VALC.The audio looping part of the code is given below. The code is working but output have clicking and crackling sounds along with music when increased number of channels. I expect valuable suggestions/codes to reduce latency,also specify what is wrong with this code? -Thanks in advance. Code:

//================================================
STDMETHODIMP_(void) CMiniportWaveCyclicStream::CopyFrom( 
IN PVOID Destination,
IN PVOID Source,
IN ULONG ByteCount 
)
/*
Routine Description:
The CopyFrom function copies sample data from the DMA buffer. 
Callers of CopyFrom can run at any IRQL

Arguments:
Destination - Points to the destination buffer. 
Source - Points to the source buffer. 
ByteCount - Points to the source buffer. 

Return Value:
void
*/
{
ULONG i=0;
ULONG FrameCount = ByteCount/2; //we guess 16-Bit sample rate
//DbgPrint(DBGMESSAGE "CopyFrom - ReadPos=%d",myBufferReadPos); 
//DbgPrint(DBGMESSAGE "CopyFrom - WritePos=%d",myBufferWritePos);
if (!m_pMiniport->myBufferLocked) {
//DbgPrint(DBGMESSAGE "CopyFrom - ByteCount=%d", ByteCount);
InterlockedExchange(&m_pMiniport->myBufferLocked, TRUE);

ULONG umyBufferSize=(ULONG)m_pMiniport->myBufferSize;
ULONG availableDataCount = (umyBufferSize + m_pMiniport->myBufferWritePos) 
                                                - m_pMiniport->myBufferReadPos;
if (availableDataCount >= umyBufferSize)
availableDataCount -= umyBufferSize;
if (availableDataCount < FrameCount) {
//if the caller wants to read more data than the buffer size is,
//we fill the rest with silence
//we write the silence at the beginning,
//because in the most cases we need to do this the caller begins to read - so we care
//for a continually stream of sound data
ULONG silenceCount = FrameCount - availableDataCount;
//DbgPrint(DBGMESSAGE "CopyFrom - need more data! NeedCount=%d", silenceCount);
for (i=0; i<=silenceCount ; i++) {
((PWORD)Destination)[i]=0;
}
}

//i=0;
while ((i < FrameCount) &&
((m_pMiniport->myBufferWritePos != m_pMiniport->myBufferReadPos+1) && !((m_pMiniport->myBufferWritePos==0) && 
(m_pMiniport - >myBufferReadPos==m_pMiniport->myBufferSize))) ) {
((PWORD)Destination)[i]=((PWORD)m_pMiniport->myBuffer)[m_pMiniport->myBufferReadPos];
i++;
m_pMiniport->myBufferReadPos++;
if (m_pMiniport->myBufferReadPos >= m_pMiniport->myBufferSize) //Loop the buffer
m_pMiniport->myBufferReadPos=0;
}
InterlockedExchange(&m_pMiniport->myBufferReading, TRUE); //now the caller reads from the buffer -
// so we can notify the CopyTo function

//DbgPrint(DBGMESSAGE "CopyFrom TRUE ByteCount=%d", ByteCount);
InterlockedExchange(&m_pMiniport->myBufferLocked, FALSE);
} else {
//in this case we can't obtain the data from buffer because it is locked
//the best we can do (to satisfy the caller) is to fill the whole buffer with silence
for (i=0; i < FrameCount ; i++) {
((PWORD)Destination)[i]=0;
}
DBGPRINT("CopyFrom FALSE");
}
} // CopyFrom

//====================================================
STDMETHODIMP_(void) CMiniportWaveCyclicStream::CopyTo( 
IN PVOID Destination,
IN PVOID Source,
IN ULONG ByteCount
)
/*
Routine Description:
The CopyTo function copies sample data to the DMA buffer. 
Callers of CopyTo can run at any IRQL. 

Arguments:
Destination - Points to the destination buffer. 
Source - Points to the source buffer
ByteCount - Number of bytes to be copied

Return Value:
void
*/
{
ULONG i=0;
ULONG FrameCount = ByteCount/2; //we guess 16-Bit sample rate
if (m_pMiniport->myBuffer==NULL) {
ULONG bufSize=64*1024; //size in bytes
DBGPRINT("Try to allocate buffer");
m_pMiniport->myBuffer = (PVOID) ExAllocatePoolWithTag(NonPagedPool, bufSize, RTSDAUDIO_POOLTAG);
if (!m_pMiniport->myBuffer) {
DBGPRINT("FAILED to allocate buffer");
} else {
DBGPRINT("Successfully allocated buffer");
m_pMiniport->myBufferSize = bufSize/2; //myBufferSize in frames
InterlockedExchange(&m_pMiniport->myBufferLocked, FALSE);
}
}
if (!m_pMiniport->myBufferLocked) {
//DbgPrint(DBGMESSAGE "Fill Buffer ByteCount=%d", ByteCount);
InterlockedExchange(&m_pMiniport->myBufferLocked, TRUE);
i=0;
while (i < FrameCount) {//while data is available
//test wether we arrived at the read-pos
if ((m_pMiniport->myBufferWritePos+1==m_pMiniport->myBufferReadPos) || 
(m_pMiniport->myBufferReadPos==0 && 
m_pMiniport->myBufferWritePos==m_pMiniport->myBufferSize)){
//DbgPrint(DBGMESSAGE "CopyTo - there is no space for new data! NeedCount=%d", FrameCount-i);
if (m_pMiniport->myBufferReadPos==m_pMiniport->myBufferSize)
m_pMiniport->myBufferReadPos=0;
else
m_pMiniport->myBufferReadPos++;
//break; //we have to break - because there is no space for the rest data
}
((PWORD)m_pMiniport->myBuffer)[m_pMiniport->myBufferWritePos]=((PWORD)Source)[i];
i++;
m_pMiniport->myBufferWritePos++;
if (m_pMiniport->myBufferWritePos >= m_pMiniport->myBufferSize) //Loop the buffer
m_pMiniport->myBufferWritePos=0;
}
//DbgPrint(DBGMESSAGE "CopyTo - ReadPos=%d",myBufferReadPos);
// DbgPrint(DBGMESSAGE "CopyTo - WritePos=%d",myBufferWritePos);
InterlockedExchange(&m_pMiniport->myBufferLocked, FALSE);
//DbgPrint(DBGMESSAGE "(2) CopyTo - ReadPos=%d",myBufferReadPos);
// DbgPrint(DBGMESSAGE "(2) CopyTo - WritePos=%d",myBufferWritePos);
//DbgPrint(DBGMESSAGE "(2) CopyTo - Locked=%d",myBufferLocked);
}
} // CopyTo
//========================================================================

2 Replies

Please log in or register to post a reply.

A8433b04cb41dd57113740b779f61acb
1
Reedbeta 168 Sep 25, 2013 at 17:44

Clicking and crackling sounds could indicate the buffer is too small and your thread doesn’t get serviced often enough to keep it full. Of course, increasing the buffer size will increase latency, so you have to find a happy medium.

Also, please indent your code properly so it’s readable.

Ab9078ea733a220836e34c8c152c8597
0
syamkumar 101 Oct 17, 2013 at 07:05

Ok, I solved the problem by changing the buffer size. Now Virtual Loop-back Cable (VALC) is working but without multichannel support. I would like to give up to 8 Channel(7.1) audio support to the VALC, for this what changes must be made in the source code of MSVAD PCMEX sample. I changed maximum channels to 8 and minimum channels to 2, but VALC outputs same information ( 2 input channels) to all the 8 output channels (ie, one to one map does not take place). Code: http://codepad.org/HZkI46p9