开箱即用的OpenAL捕获功能不起作用,但存在一个已知的解决方法: open an output context before starting capture.此解决方案适用于iOS 5.0.
但是在iOS 5.1.1上,解决方法仅对我尝试记录的第一个示例有帮助. (我在开始捕获之前将AudioSession切换到PlayAndRecord并打开默认输出设备.录制完样本后,我关闭设备并将会话切换回原来的状态.)
对于第二个示例,重新打开输出上下文没有帮助,也没有捕获声音.
有没有一种已知的方法来处理这个问题?
// Here's what I do before starting the recordingoldAudioSessioncategory = [audioSession category];[audioSession setcategory:AVAudioSessioncategoryPlayAndRecord error:nil];[audioSession setActive:YES error:nil];// We need to have an active context. If there is none,create one.if (!alcGetCurrentContext()) { outputDevice = alcopenDevice(NulL); outputContext = alcCreateContext(outputDevice,NulL); alcMakeContextCurrent(outputContext);}// Capture itselfinputDevice = alcCaptureOpenDevice(NulL,frequency,FORMAT,bufferSize);....alcCaptureCloseDevice(inputDevice);// Restoring the audio state to whatever it had been before captureif (outputContext) { alcDestroyContext(outputContext); alccloseDevice(outputDevice);}[[AVAudioSession sharedInstance] setcategory:oldAudioSessioncategory error:nil];解决方法@H_403_21@ 这是我用来模拟捕获扩展的代码.
一些评论:
>在整个项目中,OpenKD用于例如线程原语.你可能需要更换这些电话.
>我必须在开始捕获时对抗延迟.结果,我不断地继续读取声音输入并在不需要时扔掉它. (例如,提出了这样的解决方案,例如,here.)这反过来需要捕获有效的通知,以便释放对麦克风的控制.您可能想也可能不想使用这种污泥.
>我必须定义一个单独的函数alcGetAvailableSamples,而不是alcGetIntegerv(设备,ALC_CAPTURE_SAMPLES,1和& res).
简而言之,此代码不太可能在您的项目中按原样使用,但希望您可以
调整它以满足您的需求.
#include <stdbool.h>#include <stddef.h>#include <stdint.h>#include <KD/kd.h>#include <AL/al.h>#include <AL/alc.h>#include <AudioToolBox/AudioToolBox.h>#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>#include "KD/kdext.h"struct inputDeviceData { int ID; KDThreadMutex *mutex; AudioUnit audioUnit; int nChannels; int frequency; ALCenum format; int sampleSize; uint8_t *buf; size_t bufSize; // in bytes size_t bufFilledBytes; // in bytes bool started;};static struct inputDeviceData *cachedindata = NulL;static Osstatus renderCallback (voID *inRefCon,AudioUnitRenderActionFlags *ioActionFlags,const AudioTimeStamp *inTimeStamp,UInt32 inBusNumber,UInt32 inNumberFrames,audiobufferlist *ioData);static AudioUnit getAudioUnit();static voID setupNotifications();static voID destroyCachedindata();static struct inputDeviceData *setupCachedindata(AudioUnit audioUnit,ALCuint frequency,ALCenum format,ALCsizei bufferSizeInSamples);static struct inputDeviceData *getinputDeviceData(AudioUnit audioUnit,ALCsizei bufferSizeInSamples);/** I only have to use NSNotificationCenter instead of CFNotificationCenter * because there is no published name for WillResignActive/WillBecomeActive * notifications in CoreFoundation. */@interface ALCNotificationObserver : NSObject- (voID)onResignActive;@end@implementation ALCNotificationObserver- (voID)onResignActive { destroyCachedindata();}@endstatic voID setupNotifications() { static ALCNotificationObserver *observer = NulL; if (!observer) { observer = [[ALCNotificationObserver alloc] init]; [[NSNotificationCenter defaultCenter] addobserver:observer selector:@selector(onResignActive) name:UIApplicationWillResignActiveNotification object:nil]; }}static Osstatus renderCallback (voID *inRefCon,audiobufferlist *ioData) { struct inputDeviceData *inData = (struct inputDeviceData*)inRefCon; kdThreadMutexLock(inData->mutex); size_t bytesToRender = inNumberFrames * inData->sampleSize; if (bytesToRender + inData->bufFilledBytes <= inData->bufSize) { Osstatus status; struct audiobufferlist audiobufferlist; // 1 buffer is declared insIDe the structure itself. audiobufferlist.mNumberBuffers = 1; audiobufferlist.mBuffers[0].mNumberChannels = inData->nChannels; audiobufferlist.mBuffers[0].mDataByteSize = bytesToRender; audiobufferlist.mBuffers[0].mData = inData->buf + inData->bufFilledBytes; status = AudioUnitRender(inData->audioUnit,ioActionFlags,inTimeStamp,inBusNumber,inNumberFrames,&audiobufferlist); if (inData->started) { inData->bufFilledBytes += bytesToRender; } } else { kdLogFormatMessage("%s: buffer overflow",__FUNCTION__); } kdThreadMutexUnlock(inData->mutex); return 0;}static AudioUnit getAudioUnit() { static AudioUnit audioUnit = NulL; if (!audioUnit) { AudioComponentDescription IoUnitDescription; IoUnitDescription.componentType = kAudioUnitType_Output; IoUnitDescription.componentSubType = kAudioUnitSubType_VoiceProcessingIO; IoUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple; IoUnitDescription.componentFlags = 0; IoUnitDescription.componentFlagsMask = 0; AudioComponent foundioUnitReference = AudioComponentFindNext(NulL,&IoUnitDescription); AudioComponentInstanceNew(foundioUnitReference,&audioUnit); if (audioUnit == NulL) { kdLogMessage("Could not obtain AudioUnit"); } } return audioUnit;}static voID destroyCachedindata() { Osstatus status; if (cachedindata) { status = AudioOutputUnitStop(cachedindata->audioUnit); status = AudioUnitUninitialize(cachedindata->audioUnit); free(cachedindata->buf); kdThreadMutexFree(cachedindata->mutex); free(cachedindata); cachedindata = NulL; }}static struct inputDeviceData *setupCachedindata(AudioUnit audioUnit,ALCsizei bufferSizeInSamples) { static int IDCount = 0; Osstatus status; int bytesPerFrame = (format == AL_FORMAT_MONO8) ? 1 : (format == AL_FORMAT_MONO16) ? 2 : (format == AL_FORMAT_STEREO8) ? 2 : (format == AL_FORMAT_STEREO16) ? 4 : -1; int channelsPerFrame = (format == AL_FORMAT_MONO8) ? 1 : (format == AL_FORMAT_MONO16) ? 1 : (format == AL_FORMAT_STEREO8) ? 2 : (format == AL_FORMAT_STEREO16) ? 2 : -1; int bitsPerChannel = (format == AL_FORMAT_MONO8) ? 8 : (format == AL_FORMAT_MONO16) ? 16 : (format == AL_FORMAT_STEREO8) ? 8 : (format == AL_FORMAT_STEREO16) ? 16 : -1; cachedindata = malloc(sizeof(struct inputDeviceData)); cachedindata->ID = ++IDCount; cachedindata->format = format; cachedindata->frequency = frequency; cachedindata->mutex = kdThreadMutexCreate(NulL); cachedindata->audioUnit = audioUnit; cachedindata->nChannels = channelsPerFrame; cachedindata->sampleSize = bytesPerFrame; cachedindata->bufSize = bufferSizeInSamples * bytesPerFrame; cachedindata->buf = malloc(cachedindata->bufSize); cachedindata->bufFilledBytes = 0; cachedindata->started = FALSE; UInt32 enableOutput = 1; // to enable output status = AudioUnitSetProperty(audioUnit,kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_input,1,&enableOutput,sizeof(enableOutput)); struct AudioStreamBasicDescription basicDescription; basicDescription.mSampleRate = (float64)frequency; basicDescription.mFormatID = kAudioFormatlinearPCM; basicDescription.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; basicDescription.mBytesPerPacket = bytesPerFrame; basicDescription.mFramesPerPacket = 1; basicDescription.mBytesPerFrame = bytesPerFrame; basicDescription.mChannelsPerFrame = channelsPerFrame; basicDescription.mBitsPerChannel = bitsPerChannel; basicDescription.mReserved = 0; status = AudioUnitSetProperty(audioUnit,kAudioUnitProperty_StreamFormat,// property key kAudioUnitScope_Output,// scope 1,// 1 is output &basicDescription,sizeof(basicDescription)); // value AURenderCallbackStruct renderCallbackStruct; renderCallbackStruct.inputProc = renderCallback; renderCallbackStruct.inputProcRefCon = cachedindata; status = AudioUnitSetProperty(audioUnit,kAudioOutputUnitProperty_SetinputCallback,// 1 is output &renderCallbackStruct,sizeof(renderCallbackStruct)); // value status = AudioOutputUnitStart(cachedindata->audioUnit); return cachedindata;}static struct inputDeviceData *getinputDeviceData(AudioUnit audioUnit,ALCsizei bufferSizeInSamples) { if (cachedindata && (cachedindata->frequency != frequency || cachedindata->format != format || cachedindata->bufSize / cachedindata->sampleSize != bufferSizeInSamples)) { kdAssert(!cachedindata->started); destroyCachedindata(); } if (!cachedindata) { setupCachedindata(audioUnit,format,bufferSizeInSamples); setupNotifications(); } return cachedindata;}ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename,ALCsizei buffersizeInSamples) { kdAssert(devicename == NulL); AudioUnit audioUnit = getAudioUnit(); struct inputDeviceData *res = getinputDeviceData(audioUnit,buffersizeInSamples); return (ALCdevice*)res->ID;}ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) { alcCaptureStop(device); return true;}ALC_API voID ALC_APIENTRY alcCaptureStart(ALCdevice *device) { if (!cachedindata || (int)device != cachedindata->ID) { // may happen after the app loses and regains active status. kdLogFormatMessage("Attempt to start a stale AL capture device"); return; } cachedindata->started = TRUE;}ALC_API voID ALC_APIENTRY alcCaptureStop(ALCdevice *device) { if (!cachedindata || (int)device != cachedindata->ID) { // may happen after the app loses and regains active status. kdLogFormatMessage("Attempt to stop a stale AL capture device"); return; } cachedindata->started = FALSE;}ALC_API ALCint ALC_APIENTRY alcGetAvailableSamples(ALCdevice *device) { if (!cachedindata || (int)device != cachedindata->ID) { // may happen after the app loses and regains active status. kdLogFormatMessage("Attempt to get sample count from a stale AL capture device"); return 0; } ALCint res; kdThreadMutexLock(cachedindata->mutex); res = cachedindata->bufFilledBytes / cachedindata->sampleSize; kdThreadMutexUnlock(cachedindata->mutex); return res;}ALC_API voID ALC_APIENTRY alcCaptureSamples(ALCdevice *device,ALCvoID *buffer,ALCsizei samples) { if (!cachedindata || (int)device != cachedindata->ID) { // may happen after the app loses and regains active status. kdLogFormatMessage("Attempt to get samples from a stale AL capture device"); return; } size_t bytesToCapture = samples * cachedindata->sampleSize; kdAssert(cachedindata->started); kdAssert(bytesToCapture <= cachedindata->bufFilledBytes); kdThreadMutexLock(cachedindata->mutex); memcpy(buffer,cachedindata->buf,bytesToCapture); memmove(cachedindata->buf,cachedindata->buf + bytesToCapture,cachedindata->bufFilledBytes - bytesToCapture); cachedindata->bufFilledBytes -= bytesToCapture; kdThreadMutexUnlock(cachedindata->mutex);}@H_301_0@ 总结
以上是内存溢出为你收集整理的在iOS上使用OpenAL进行声音捕获全部内容,希望文章能够帮你解决在iOS上使用OpenAL进行声音捕获所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)