📄 coreaudio_drv.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 + -