⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 audioparsebuffer.cpp

📁 完整的基于Conxant平台的USB电视棒的WIN驱动程序。
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*+++ *******************************************************************\ 
* 
*  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 + -