2012-11-20 71 views
2

我有一个应用程序,它使用AudioUnit与子类型kAudioUnitSubType_VoiceProcessingIO。输入来自网络流。这工作正常,但现在我想从文件播放简单的声音(收到推送通知后的警报声音)。只有当AudioUnit尚未启动或已经处理完毕时,该功能才起作用。我甚至可以停止AudioUnit而声音文件仍然播放,以听取最终的样本,所以播放似乎工作,但它是沉默的。与AudioUnit一起播放声音文件

我试过AudioServicesPlaySystemSoundAVAudioPlayer在真实设备上没有成功(可能在模拟器中工作)。

有没有简单的解决这个简单的任务,或者我需要手动混合基于文件的音频内容?

在此先感谢!

回答

2

您可以通过音频单元构建AUGraph并通过kAudioUnitSubType_AudioFilePlayer单元播放音频文件。

+0

感谢您的回复,奇怪的是没有更简单的解决方案。我最终在Apples [MixerHost示例](http://developer.apple.com/library/ios/#samplecode/MixerHost/Introduction/Intro.html)帮助下使用'ExtAudioFileOpenURL' +'ExtAudioFileRead'将文件读入AudioBuffers )。然后,我使用此准备好的缓冲区播放警报声音,而不是网络流。目前我不使用混音器单元。这将是一个完美的解决方案,但对于我的短暂警报声来说并不是必需的。 – MrJ

0

这可能是一个系统限制。如果您的iOS设备在使用PlayAndRecord类别时调用AudioServicesPlaySystemSound时没有执行任何操作,请尝试先停止您的AudioUnit,然后调用此函数。

2

尝试

OSStatus propertySetError = 0; 
UInt32 allowMixing = true; 

propertySetError = AudioSessionSetProperty (
         kAudioSessionProperty_OverrideCategoryMixWithOthers, // 1 
         sizeof (allowMixing),         // 2 
         &allowMixing           // 3 
        ); 

或者你可以使用kAudioUnitType_Mixer型AudioUnit。

AudioComponentDescription MixerUnitDescription; 
MixerUnitDescription.componentType   = kAudioUnitType_Mixer; 
MixerUnitDescription.componentSubType  = kAudioUnitSubType_MultiChannelMixer; 
MixerUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple; 
MixerUnitDescription.componentFlags   = 0; 
MixerUnitDescription.componentFlagsMask  = 0; 

将它们(mixer_unit,voice_processing_unit)添加到AUGraph中。为混音器单元设置输入总线计数2。

UInt32 busCount = 2; // bus count for mixer unit input 
status = AudioUnitSetProperty (mixer_unit, 
           kAudioUnitProperty_ElementCount, 
           kAudioUnitScope_Input, 
           0, 
           &busCount, 
           sizeof(busCount) 
           ); 

添加呈现回调mixer_unit的每个总线:

for (UInt16 busNumber = 0; busNumber < busCount; ++busNumber) { 
     AURenderCallbackStruct inputCallbackStruct; 
     inputCallbackStruct.inputProc  = &VoiceMixRenderCallback; 
     inputCallbackStruct.inputProcRefCon = self; 

     status = AUGraphSetNodeInputCallback (_mixSaveGraph, 
               mixerNode, 
               busNumber, 
               &inputCallbackStruct 
              ); 
     if (status) { printf("AudioUnitSetProperty set callback"); return NO; }    

    } 

的mixer_unit的输出总线连接到io_unit的输入总线:

status = AUGraphConnectNodeInput (_mixSaveGraph, 
             mixerNode,   // source node 
             0,     // source node output bus number 
             saveNode,   // destination node 
             0     // desintation node input bus number 
            ); 

启动图形,日子会把你得到读者来电带有不同的总线号(0和1),如下所示:

static OSStatus VoiceMixRenderCallback(void *      inRefCon, 
            AudioUnitRenderActionFlags *ioActionFlags, 
            const AudioTimeStamp *  inTimeStamp, 
            UInt32      inBusNumber, 
            UInt32      inNumberFrames, 
            AudioBufferList *    ioData) 
{ 
    OSStatus status; 
    AURecorder *recorder = (AURecorder*)inRefCon; 
    if (inBusNumber == BUS_ONE && (recorder.isMusicPlaying)) { 
     //Get data from music file. try ExtAudioFileRead 
    } else if (inBusNumber == BUS_TWO) { 
     status = AudioUnitRender(recorder.io_unit, ioActionFlags, inTimeStamp, INPUT_BUS, inNumberFrames, ioData); 
     //Get data from io unit's input bus. 
     if (status) 
     { 
      printf("AudioUnitRender for record error"); 
      *ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence; 
     } 
    } else { 
     *ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence; 
    } 

    return noErr; 
}