📄 audioparsebuffer.cpp
字号:
/*+++ *******************************************************************\
*
* Copyright and Disclaimer:
*
* ---------------------------------------------------------------
* This software is provided "AS IS" without warranty of any kind,
* either expressed or implied, including but not limited to the
* implied warranties of noninfringement, merchantability and/or
* fitness for a particular purpose.
* ---------------------------------------------------------------
*
* Copyright (c) 2008 Conexant Systems, Inc.
* All rights reserved.
*
\******************************************************************* ---*/
#include "AudioParseBuffer.h"
#include "AncillaryPacket.h"
/////////////////////////////////////////////////////////////////////////////////////////
AudioParseBuffer::AudioParseBuffer():
_p_pin(NULL),
_channel1_samples_in_buffer(0),
_channel2_samples_in_buffer(0),
_p_current_buffer(NULL)
{
KeInitializeMutex(&_mutex, 0);
}
/////////////////////////////////////////////////////////////////////////////////////////
VOID AudioParseBuffer::setPin(BasePin* p_pin)
{
KeWaitForSingleObject(&_mutex, Executive, KernelMode, FALSE, NULL );
_p_pin = p_pin;
_channel1_samples_in_buffer = 0;
_channel2_samples_in_buffer = 0;
_p_current_buffer = NULL;
KeReleaseMutex(&_mutex, FALSE);
}
/////////////////////////////////////////////////////////////////////////////////////////
VOID AudioParseBuffer::releasePin()
{
KeWaitForSingleObject(&_mutex, Executive, KernelMode, FALSE, NULL );
_p_pin = NULL;
_channel1_samples_in_buffer = 0;
_channel2_samples_in_buffer = 0;
_p_current_buffer = NULL;
KeReleaseMutex(&_mutex, FALSE);
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// NOTE: The format of the audio data in the buffer is as follows:
//
// Mako supports up to 4 channels of audio output at a time. If a channel is
// present in the current audio buffer, then a bit will be set in the data_id2 byte.
// Each channel will have 8 bytes of data in the buffer, or 4 2-byte samples. The
// samples themselves are byte swapped, so we must byte swap each WORD, (not each DWORD).
// Of the channels that are present in the buffer, they will be in the order of
// Channel A, Channel B, Channel C, Channel D, with only channels that are present
// having data.
//
// We only use channels A and B, (referred to below as 1 and 2). If A and B are both present
// the data from A is at offset 0 and the data from B is at offset 8. If A alone is present,
// the data is at offset 0. If B alone is present, the data is at offset 0. Any other
// channels that may be present are ignored.
//
DWORD AudioParseBuffer::parseBuffer(AncillaryPacket* p_packet)
{
KeWaitForSingleObject(&_mutex, Executive, KernelMode, FALSE, NULL );
DWORD buffer_size;
AUDIO_PACKET* p_audio_packet = (AUDIO_PACKET*)p_packet->getBuffer(&buffer_size);
//Get the data byte count from the buffer. It is stored shifted two bytes to the
// right because we are in 8-bit format rather than 10-bit
//
// The maximum bytes that can be transfered is 32, of which we will use at most 16
DWORD data_count = (p_audio_packet->data_count & 0xF) << 2;
//If we don't have a pin, just return the number of bytes we would have used.
if(!_p_pin)
{
KeReleaseMutex(&_mutex, FALSE);
return data_count;
}
const DWORD HEADER_SIZE = 6;
if(data_count > (buffer_size - HEADER_SIZE))
{
KeReleaseMutex(&_mutex, FALSE);
//Buffer is not valid
return 0;
}
//Byte swap the data
DWORD bytes_to_swap = (data_count <= 16) ? data_count : 16;
PWORD p_word_data = (PWORD) &p_audio_packet->data_channel1[0];
if(p_word_data)
{
for(DWORD i = 0; i < (bytes_to_swap/2); i++)
{
if(p_word_data[i])
{
p_word_data[i] = RtlUshortByteSwap(p_word_data[i]);
}
}
}
//Get a buffer to copy the data into
if(!_p_current_buffer)
{
_p_current_buffer = _p_pin->getNextBuffer();
}
if(!_p_current_buffer)
{
KeReleaseMutex(&_mutex, FALSE);
//No available buffer, nothing to do
return data_count;
}
//Determine rather channel 1, channel 2, or both channels are present
// in the sample
PWORD p_data1 = NULL;
PWORD p_data2 = NULL;
//Note that data_id2 has bits set for each audio channel present in the
// packet. Bit 0 is set if channel 1 is present, bit 1 is set if channel
// 2 is present.
if((p_audio_packet->data_id2 & 0x3) == 3)
{
//Channel 1 and Channel 2 are present
p_data1 = (PWORD) &p_audio_packet->data_channel1[0];
p_data2 = (PWORD) &p_audio_packet->data_channel2[0];
}
else if(p_audio_packet->data_id2 & 0x1)
{
//Only channel 1 is present
p_data1 = (PWORD) &p_audio_packet->data_channel1[0];
}
else if(p_audio_packet->data_id2 & 0x2)
{
//Only channel 2 is present
p_data2 = (PWORD) &p_audio_packet->data_channel1[0];
}
else
{
KeReleaseMutex(&_mutex, FALSE);
//No data in channel 1 or channel 2
return data_count;
}
const DWORD AVAILABLE_SAMPLES = 4;
DWORD samples_used1 = 0;
DWORD samples_used2 = 0;
//if channel 1 is present, copy it into the buffer
if(p_data1)
{
samples_used1 = copySamplesIntoBuffer(p_data1, AVAILABLE_SAMPLES, 1);
}
//if channel 2 is present, copy it into the buffer
if(p_data2)
{
samples_used2 = copySamplesIntoBuffer(p_data2, AVAILABLE_SAMPLES, 2);
}
//Check for a completed buffer
buffer_size = _p_current_buffer->StreamHeader->FrameExtent;
const DWORD MAX_CHANNEL_SAMPLES_IN_BUFFER = buffer_size / 4;
if((_channel1_samples_in_buffer >= MAX_CHANNEL_SAMPLES_IN_BUFFER) &&
(_channel2_samples_in_buffer >= MAX_CHANNEL_SAMPLES_IN_BUFFER))
{
completeCurrentBuffer();
//Get the next buffer
if(!_p_current_buffer)
{
_p_current_buffer = _p_pin->getNextBuffer();
}
//If there are any remaining samples on either channel, copy them into the new buffer
if(_p_current_buffer)
{
if((samples_used1 < AVAILABLE_SAMPLES) && p_data1)
{
copySamplesIntoBuffer(
p_data1 + samples_used1,
AVAILABLE_SAMPLES - samples_used1,
1);
}
if((samples_used2 < AVAILABLE_SAMPLES) && p_data2)
{
copySamplesIntoBuffer(
p_data2 + samples_used2,
AVAILABLE_SAMPLES - samples_used2,
2);
}
}
}
KeReleaseMutex(&_mutex, FALSE);
return data_count;
}
/////////////////////////////////////////////////////////////////////////////////////////
//Copies the samples from one channel into the buffer
// Returns the number of samples actually copied into the buffer.
DWORD AudioParseBuffer::copySamplesIntoBuffer(
PWORD p_samples,
DWORD sample_count,
DWORD channel_number)
{
DWORD buffer_size = _p_current_buffer->StreamHeader->FrameExtent;
const DWORD MAX_COPY_INDEX = buffer_size / 2;
PDWORD p_sample_count = NULL;
DWORD copy_index = 0;
if(channel_number == 1)
{
copy_index = _channel1_samples_in_buffer * 2;
p_sample_count = &_channel1_samples_in_buffer;
}
else //channel 2
{
copy_index = 1 + _channel2_samples_in_buffer * 2;
p_sample_count = &_channel2_samples_in_buffer;
}
PWORD p_out_buffer = (PWORD)_p_current_buffer->StreamHeader->Data;
for(DWORD i = 0; i < sample_count; i++)
{
//if there is room in the data buffer, copy the current samples
if(copy_index < MAX_COPY_INDEX)
{
p_out_buffer[copy_index] = p_samples[i];
copy_index += 2;
(*p_sample_count)++;
}
else
{
return i;
}
}
return sample_count; //All samples were put in the buffer
}
/////////////////////////////////////////////////////////////////////////////////////////
VOID AudioParseBuffer::completeCurrentBuffer()
{
if(!_p_current_buffer)
{
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -