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

📄 coreaudio_drv.c

📁 audio-video-codecs.rar语音编解码器
💻 C
字号:
/*
//
//                  INTEL CORPORATION PROPRIETARY INFORMATION
//     This software is supplied under the terms of a license agreement or
//     nondisclosure agreement with Intel Corporation and may not be copied
//     or disclosed except in accordance with the terms of that agreement.
//          Copyright(c) 2003-2006 Intel Corporation. All Rights Reserved.
//
*/

#include "umc_defs.h"

#ifdef UMC_ENABLE_COREAUDIO_RENDER

#include "coreaudio_drv.h"
#include <vm_time.h>

#define COREAUDIO_DELAY 10

void *coreaudioInit(const Ipp32u freq,
                    const Ipp32u channels,
                    const Ipp32u bps)
{
    Component aComp;
    ComponentDescription aDesc;
    AudioStreamBasicDescription sDesc;
    AURenderCallbackStruct aCallback;

    UInt32 sSize = 0;
    OSStatus result = noErr;
    CoreAudioDrv *drv =(CoreAudioDrv *)ippsMalloc_8u(sizeof(CoreAudioDrv));

    drv->mFrequency = freq;
    drv->mChannels = channels;
    drv->mBitPerSample = bps;

    /* Default audio unit initialization */
    aDesc.componentType = kAudioUnitType_Output;
    aDesc.componentSubType = kAudioUnitSubType_DefaultOutput;
    aDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
    aDesc.componentFlags = 0;
    aDesc.componentFlagsMask = 0;

    aComp = FindNextComponent(NULL, &aDesc);
    if (aComp == NULL) {
        vm_debug_trace(VM_DEBUG_NONE, VM_STRING("CoreAudio:" "Init:FindNextComponent" " FAILED"));
        return NULL;
    }

    /* Open the default audio unit */
    result = OpenAComponent(aComp, &(drv->aUnit));
    CHECK_RESULT(noErr, "Init:OpenAComponent", NULL)

    result = AudioUnitInitialize(drv->aUnit);
    CHECK_RESULT(noErr, "Init:AudioUnitInitialize", NULL)

    result = vm_mutex_init(&(drv->mLockSender));
    CHECK_RESULT(VM_OK, "Init:MutexInit", NULL)

    result = vm_mutex_init(&(drv->mLockBuffer));
    CHECK_RESULT(VM_OK, "Init:MutexInit", NULL)

    /* Requested audio format AudioStreamBasicDescription initialization */
    sDesc.mSampleRate = drv->mFrequency;
    sDesc.mChannelsPerFrame = drv->mChannels;
    sDesc.mBitsPerChannel = drv->mBitPerSample;

    sDesc.mFormatID = kAudioFormatLinearPCM;
    sDesc.mFramesPerPacket = 1;
    sDesc.mBytesPerFrame =(sDesc.mBitsPerChannel / 8) * sDesc.mChannelsPerFrame;
    sDesc.mBytesPerPacket = sDesc.mBytesPerFrame * sDesc.mFramesPerPacket;
    drv->mPacketSize = sDesc.mBytesPerPacket;

    sDesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
    sDesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;

    /* Audio unit input format setup */
    result = AudioUnitSetProperty(drv->aUnit,
                                  kAudioUnitProperty_StreamFormat,
                                  kAudioUnitScope_Input,
                                  0,
                                  &sDesc,
                                  sizeof(sDesc));
    CHECK_RESULT(noErr, "Init:AudioUnitSetProperty:StreamFormat", NULL)

    /* Audio unit frames buffer size check*/
    drv->mChunkSize = COREAUDIO_BUFFERS_SIZE;
    result = AudioUnitSetProperty(drv->aUnit,
                                  kAudioDevicePropertyBufferSize,
                                  kAudioUnitScope_Input,
                                  0,
                                  &(drv->mChunkSize),
                                  sizeof(drv->mChunkSize));
    CHECK_RESULT(noErr, "Init:AudioUnitSetProperty:BufferSize", NULL)

    sSize = sizeof(drv->mChunkSize);
    result = AudioUnitGetProperty(drv->aUnit,
                                  kAudioDevicePropertyBufferSize,
                                  kAudioUnitScope_Input,
                                  0,
                                  &(drv->mChunkSize),
                                  &sSize);
    CHECK_RESULT(noErr, "Init:AudioUnitGetProperty:BufferSize", NULL)

    /* Buffers allocation and setup*/
    drv->mChunksNumber = COREAUDIO_BUFFERS_NUM;
    drv->mBufferSize =(drv->mChunksNumber + 1) * drv->mChunkSize;
    drv->mDataBuffer =(Ipp8u *)ippsMalloc_8u(drv->mBufferSize);
    drv->mReadPosition = 0;
    drv->mWritePosition = 0;

    /* Audio callback linking */
    aCallback.inputProcRefCon = drv;
    aCallback.inputProc = coreaudioCallback;
    result = AudioUnitSetProperty(drv->aUnit,
                                  kAudioUnitProperty_SetRenderCallback,
                                  kAudioUnitScope_Input,
                                  0,
                                  &aCallback,
                                  sizeof(aCallback));
    CHECK_RESULT(noErr, "Init:AudioUnitSetProperty:SetRenderCallback", NULL)

    /* Audio unit start processing */
    result = AudioOutputUnitStart(drv->aUnit);
    CHECK_RESULT(noErr, "Init:AudioOutputUnitStart", NULL)

    drv->mVolume = 1.0;
    drv->mRenderFlag = COREAUDIO_RENDER_OPEN;

    return drv;
}

/**
 * Add audio data to ringbuffer
 */
static Ipp32s audio_data_add(CoreAudioDrv *drv,
                             Ipp8u* data,
                             Ipp32s size)
{
    Ipp32s offset, free;

    if (NULL == drv) return size;
    offset = drv->mBufferSize - drv->mWritePosition;
    /* Number of free bytes in the buffer */
    free = drv->mReadPosition - drv->mWritePosition - drv->mChunkSize;
    if (free < 0) free += drv->mBufferSize;

    if (size > free) size = free;
    if (offset > size) offset = size;

    /* Till end of buffer */
    //memcpy(&drv->mDataBuffer[drv->mWritePosition], data, offset);
    ippsCopy_8u(data, &drv->mDataBuffer[drv->mWritePosition], offset);

    /* We have to wrap around */
    if (size > offset)
    {
        /* remaining part from beginning of buffer */
        //memcpy(drv->mDataBuffer, &data[offset], size - offset);
        ippsCopy_8u(&data[offset], drv->mDataBuffer, size - offset);
    }

    drv->mWritePosition =(drv->mWritePosition + size) % drv->mBufferSize;
    return size;
}

/**
 * Remove data from ringbuffer
 */
static Ipp32s audio_data_remove(CoreAudioDrv *drv,
                                Ipp8u* data,
                                Ipp32s size)
{
    Ipp32s offset, buffered;

    if (NULL == drv) return size;
    offset = drv->mBufferSize - drv->mReadPosition;
    /* Number of buffered bytes */
    buffered = drv->mWritePosition - drv->mReadPosition;
    if (buffered < 0) buffered += drv->mBufferSize;

    if (size > buffered) size = buffered;
    if (offset > size) offset = size;

    /* Till end of buffer */
    //memcpy(data, &drv->mDataBuffer[drv->mReadPosition], offset);
    if (drv->mVolume > 0)
        ippsCopy_8u(&drv->mDataBuffer[drv->mReadPosition], data, offset);
    else
        ippsZero_8u(data, offset);

    /* We have to wrap around */
    if(size > offset)
    {
        /* remaining part from beginning of buffer */
        //memcpy(&data[offset], drv->mDataBuffer, size - offset);
        if (drv->mVolume > 0)
            ippsCopy_8u(drv->mDataBuffer, &data[offset], size - offset);
        else
            ippsZero_8u(&data[offset], size - offset);
    }

    drv->mReadPosition = (drv->mReadPosition + size) % drv->mBufferSize;
    return size;
}

Ipp32s coreaudioPlay(void *driver,
                     Ipp8u* buf,
                     Ipp32s size)
{
    CoreAudioDrv *drv =(CoreAudioDrv *)driver;

    if (NULL == drv) return 0;
    /*
     * This is a hack. Actualy we don't need to use mLockSender and mRenderFlag.
     * But UMC run SendFrame() after Close(). Why?
     */
    vm_mutex_lock(&(drv->mLockSender));
    if (drv->mRenderFlag == COREAUDIO_RENDER_OPEN)
    {
        while(size > 0)
        {
            vm_mutex_lock(&(drv->mLockBuffer));
            Ipp32s added = audio_data_add(drv, buf, size);
            vm_mutex_unlock(&(drv->mLockBuffer));
            buf += added;
            size -= added;
            /* Increasing of productivity: */
            if (size > 0) vm_time_sleep (COREAUDIO_DELAY);
        }
    }
    vm_mutex_unlock(&(drv->mLockSender));
    return 0;
}

Ipp32s coreaudioReset(void *driver)
{
    OSStatus result;
    CoreAudioDrv *drv =(CoreAudioDrv *)driver;

    if (NULL == drv) return 0;
    /* Resets an audio unit */
    AudioUnitReset(drv->aUnit,
                   kAudioUnitScope_Input,
                   0);
    CHECK_RESULT(noErr, "Reset:AudioUnitReset", -1)

    drv->mReadPosition = 0;
    drv->mWritePosition = 0;
    return 0;
}

Ipp32s coreaudioPause(void *driver)
{
    OSStatus result;
    CoreAudioDrv *drv =(CoreAudioDrv *)driver;

    if (NULL == drv) return 0;
    /* Audio unit stop processing */
    result = AudioOutputUnitStop(drv->aUnit);
    CHECK_RESULT(noErr, "Pause:AudioOutputUnitStop", -1)
    return 0;
}

Ipp32s coreaudioResume(void *driver)
{
    OSStatus result;
    CoreAudioDrv *drv =(CoreAudioDrv *)driver;

    if (NULL == drv) return 0;
    /* Audio unit start processing */
    result = AudioOutputUnitStart(drv->aUnit);
    CHECK_RESULT(noErr, "Resume:AudioOutputUnitStart", -1)
    return 0;
}

Ipp32f coreaudioSetVolume (void *driver, Ipp32f volume)
{
    CoreAudioDrv *drv =(CoreAudioDrv *)driver;

    if (NULL == drv) return 0;
    if (volume < 0)
        drv->mVolume = 0;
    else if (volume > 1)
        drv->mVolume = 1;
    else
        drv->mVolume = volume;

    /* Remark: core audio volume interval: [0,1]. */
    if (noErr != AudioUnitSetParameter(drv->aUnit,
                                       kHALOutputParam_Volume,
                                       kAudioUnitScope_Global,
                                       0,
                                       drv->mVolume,
                                       0))
        drv->mVolume = -1;
    return drv->mVolume;
}

Ipp32f coreaudioGetVolume (void *driver)
{
    CoreAudioDrv *drv =(CoreAudioDrv *)driver;

    if (NULL == drv) return 0;
    return drv->mVolume;
}

void coreaudioClose(void *driver)
{
    OSStatus result;
    CoreAudioDrv *drv =(CoreAudioDrv *)driver;

    if (NULL == drv) return;
    vm_mutex_lock(&(drv->mLockSender));
    vm_mutex_lock(&(drv->mLockBuffer));

    drv->mRenderFlag = COREAUDIO_RENDER_CLOSE;

    /* Audio unit stop processing */
    result = AudioOutputUnitStop(drv->aUnit);
    CHECK_RESULT(noErr, "Close:AudioOutputUnitStop",)

    result = AudioUnitUninitialize(drv->aUnit);
    CHECK_RESULT(noErr, "Close:AudioUnitUninitialize",)

    result = CloseComponent(drv->aUnit);
    CHECK_RESULT(noErr, "Close:CloseComponent",)

    vm_mutex_unlock(&(drv->mLockSender));
    vm_mutex_unlock(&(drv->mLockBuffer));

    vm_mutex_destroy(&(drv->mLockBuffer));
    vm_mutex_destroy(&(drv->mLockSender));

    ippsFree(drv->mDataBuffer);
    ippsFree(drv);
}

OSStatus coreaudioCallback(void *driver,
                           AudioUnitRenderActionFlags *aFlags,
                           const AudioTimeStamp *timeStamp,
                           UInt32 busNumber,
                           UInt32 numFrames,
                           AudioBufferList *aData)
{
    CoreAudioDrv *drv =(CoreAudioDrv *)driver;
    Ipp32s required, buffered;

    if (NULL == drv) return noErr;
    vm_mutex_lock(&(drv->mLockBuffer));

    required = numFrames * drv->mPacketSize;
    /* Number of buffered bytes */
    buffered = drv->mWritePosition - drv->mReadPosition;
    if (buffered < 0) buffered += drv->mBufferSize;

    if (buffered > required) buffered = required;

    if (buffered)
    {
        audio_data_remove(drv,
                          (Ipp8u *)aData->mBuffers[0].mData,
                          buffered);
    }

    aData->mBuffers[0].mDataByteSize = buffered;
    vm_mutex_unlock(&(drv->mLockBuffer));
    return noErr;
}

#endif // UMC_ENABLE_COREAUDIO_RENDER

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -