📄 macsnd.c
字号:
/*mediastreamer2 library - modular sound and video processing and streamingCopyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)This program is free software; you can redistribute it and/ormodify it under the terms of the GNU General Public Licenseas published by the Free Software Foundation; either version 2of the License, or (at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*//* this file is specifically distributed under a BSD license *//*** Copyright (C) 2007 Hiroki Mori (himori@users.sourceforge.net)* All rights reserved.* * Redistribution and use in source and binary forms, with or without* modification, are permitted provided that the following conditions are met:* * Redistributions of source code must retain the above copyright* notice, this list of conditions and the following disclaimer.* * Redistributions in binary form must reproduce the above copyright* notice, this list of conditions and the following disclaimer in the* documentation and/or other materials provided with the distribution.* * Neither the name of the <organization> nor the* names of its contributors may be used to endorse or promote products* derived from this software without specific prior written permission.** THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.**/#include <CoreServices/CoreServices.h>#include <AudioUnit/AudioUnit.h>#include <AudioToolbox/AudioToolbox.h>#include "mediastreamer2/mssndcard.h"#include "mediastreamer2/msfilter.h"MSFilter *ms_ca_read_new(MSSndCard *card);MSFilter *ms_ca_write_new(MSSndCard *card);typedef struct CAData{ char *pcmdev; char *mixdev; AudioUnit caOutAudioUnit; AudioUnit caInAudioUnit; AudioStreamBasicDescription caOutASBD; AudioStreamBasicDescription caInASBD; AURenderCallbackStruct caOutRenderCallback; AURenderCallbackStruct caInRenderCallback; AudioConverterRef caOutConverter; AudioConverterRef caInConverter; int pcmfd; int rate; int bits; ms_mutex_t mutex; queue_t rq; MSBufferizer * bufferizer; bool_t read_started; bool_t write_started; bool_t stereo; void *caSourceBuffer; AudioBufferList *fAudioBuffer, *fMSBuffer;} CAData;// Convenience function to dispose of our audio buffersvoid DestroyAudioBufferList(AudioBufferList* list){ UInt32 i; if(list) { for(i = 0; i < list->mNumberBuffers; i++) { if(list->mBuffers[i].mData) free(list->mBuffers[i].mData); } free(list); }}// Convenience function to allocate our audio buffersAudioBufferList *AllocateAudioBufferList(UInt32 numChannels, UInt32 size){ AudioBufferList* list; UInt32 i; list = (AudioBufferList*)calloc(1, sizeof(AudioBufferList) + numChannels * sizeof(AudioBuffer)); if(list == NULL) return NULL; list->mNumberBuffers = numChannels; for(i = 0; i < numChannels; ++i) { list->mBuffers[i].mNumberChannels = 1; list->mBuffers[i].mDataByteSize = size; list->mBuffers[i].mData = malloc(size); if(list->mBuffers[i].mData == NULL) { DestroyAudioBufferList(list); return NULL; } } return list;}OSStatus writeACInputProc ( AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void* inUserData){ OSStatus err = noErr; CAData *d=(CAData*)inUserData; UInt32 packetSize = (d->bits / 8) * (d->stereo ? 2 : 1);// ms_error("writeACInputProc %d", *ioNumberDataPackets); if(*ioNumberDataPackets) { if(d->caSourceBuffer != NULL) { free(d->caSourceBuffer); d->caSourceBuffer = NULL; } d->caSourceBuffer = (void *) calloc (1, *ioNumberDataPackets * packetSize); ioData->mBuffers[0].mData = d->caSourceBuffer; // tell the Audio Converter where it's source data is ms_mutex_lock(&d->mutex); int readsize = ms_bufferizer_read(d->bufferizer,d->caSourceBuffer,*ioNumberDataPackets * packetSize); ms_mutex_unlock(&d->mutex); if(readsize != *ioNumberDataPackets * packetSize) { ms_error("ms_bufferizer_read error request = %d result = %d", *ioNumberDataPackets * packetSize, readsize); memset(d->caSourceBuffer, 0, *ioNumberDataPackets * packetSize); ioData->mBuffers[0].mDataByteSize = *ioNumberDataPackets * packetSize; // tell the Audio Converter how much source data there is } else { ioData->mBuffers[0].mDataByteSize = readsize; // tell the Audio Converter how much source data there is } } return err;}OSStatus readACInputProc (AudioConverterRef inAudioConverter, UInt32* ioNumberDataPackets, AudioBufferList* ioData, AudioStreamPacketDescription** ioASPD, void* inUserData){ CAData *d=(CAData*)inUserData; AudioBufferList* l_inputABL = d->fAudioBuffer; UInt32 totalInputBufferSizeBytes = ((*ioNumberDataPackets) * sizeof (float)); int counter = d->caInASBD.mChannelsPerFrame; ioData->mNumberBuffers = d->caInASBD.mChannelsPerFrame; while (--counter >= 0) { AudioBuffer* l_ioD_AB = &(ioData->mBuffers[counter]); l_ioD_AB->mNumberChannels = 1; l_ioD_AB->mData = (float*)(l_inputABL->mBuffers[counter].mData); l_ioD_AB->mDataByteSize = totalInputBufferSizeBytes; } return (noErr);}OSStatus readRenderProc(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData){ CAData *d=(CAData*)inRefCon; OSStatus err = noErr; // Render into audio buffer err = AudioUnitRender(d->caInAudioUnit, inActionFlags, inTimeStamp, inBusNumber, inNumFrames, d->fAudioBuffer); if(err != noErr) ms_error("AudioUnitRender %d size = %d", err, d->fAudioBuffer->mBuffers[0].mDataByteSize); UInt32 AvailableOutputBytes = inNumFrames * sizeof (float); UInt32 propertySize = sizeof (AvailableOutputBytes); err = AudioConverterGetProperty (d->caInConverter, kAudioConverterPropertyCalculateOutputBufferSize, &propertySize, &AvailableOutputBytes); if(err != noErr) ms_error("AudioConverterGetProperty %d", err); UInt32 ActualOutputFrames = AvailableOutputBytes / sizeof (short); err = AudioConverterFillComplexBuffer (d->caInConverter, (AudioConverterComplexInputDataProc)(readACInputProc), inRefCon, &ActualOutputFrames, d->fMSBuffer, NULL); if(err != noErr) ms_error("readRenderProc:AudioConverterFillComplexBuffer %08x mNumberBuffers = %d", err, ioData->mNumberBuffers); mblk_t *rm=NULL; rm=allocb(d->fMSBuffer->mBuffers[0].mDataByteSize,0); memcpy(rm->b_wptr, d->fMSBuffer->mBuffers[0].mData, d->fMSBuffer->mBuffers[0].mDataByteSize);// memset(rm->b_wptr, 0, d->fMSBuffer->mBuffers[0].mDataByteSize); rm->b_wptr+=d->fMSBuffer->mBuffers[0].mDataByteSize; ms_mutex_lock(&d->mutex); putq(&d->rq,rm); ms_mutex_unlock(&d->mutex); rm=NULL; return err;}OSStatus writeRenderProc(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData){ OSStatus err= noErr; void *inInputDataProcUserData=NULL; CAData *d=(CAData*)inRefCon; if(d->write_started != FALSE) { AudioStreamPacketDescription* outPacketDescription = NULL; err = AudioConverterFillComplexBuffer(d->caOutConverter, writeACInputProc, inRefCon, &inNumFrames, ioData, outPacketDescription); if(err != noErr) ms_error("writeRenderProc:AudioConverterFillComplexBuffer err %08x %d", err, ioData->mNumberBuffers); } return err;}static void ca_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent){ CAData *d=(CAData*)card->data;}static int ca_get_level(MSSndCard *card, MSSndCardMixerElem e){ CAData *d=(CAData*)card->data; return 0;}static void ca_set_source(MSSndCard *card, MSSndCardCapture source){ CAData *d=(CAData*)card->data;}static void ca_init(MSSndCard *card){ ms_debug("ca_init"); OSStatus err; UInt32 param; AudioDeviceID fInputDeviceID; CAData *d=ms_new(CAData,1); ComponentDescription desc; // Get Default Output audio unit desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_DefaultOutput; desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; Component comp = FindNextComponent(NULL, &desc); if (comp == NULL) return; err = OpenAComponent(comp, &d->caOutAudioUnit); if(err != noErr) return; // Get Default Input audio unit desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_HALOutput; desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; comp = FindNextComponent(NULL, &desc); if (comp == NULL) return; err = OpenAComponent(comp, &d->caInAudioUnit); if(err != noErr) return; AudioUnitInitialize(d->caOutAudioUnit); AudioUnitInitialize(d->caInAudioUnit); UInt32 asbdsize = sizeof(AudioStreamBasicDescription); memset((char *)&d->caOutASBD, 0, asbdsize); memset((char *)&d->caInASBD, 0, asbdsize); // Setup Output audio unit OSStatus result = AudioUnitGetProperty (d->caOutAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &d->caOutASBD, &asbdsize); result = AudioUnitSetProperty (d->caOutAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &d->caOutASBD, asbdsize); // Setup Input audio unit // Enable input on the AUHAL param = 1; result = AudioUnitSetProperty(d->caInAudioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, ¶m, sizeof(UInt32));// Select the default input device param = sizeof(AudioDeviceID); result = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, ¶m, &fInputDeviceID); // Set the current device to the default input unit. result = AudioUnitSetProperty(d->caInAudioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &fInputDeviceID, sizeof(AudioDeviceID)); AudioStreamBasicDescription tmpASBD; result = AudioUnitGetProperty (d->caInAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &tmpASBD, &asbdsize);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -