2012-11-20 70 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; 
}