我有一个使用AudioUnit
子类型kAudioUnitSubType_VoiceProcessingIO
的应用。输入来自网络流。这很好,但现在我想从文件播放一个简单的声音(收到推送通知后发出警报声)。当AudioUnit
处于运行状态时,这不起作用,只有当它尚未启动或已经处置时。我甚至可以在声音文件静止播放时停止AudioUnit
以听取最终样本,因此播放似乎有效,但它是静音的。
我在真实设备上尝试AudioServicesPlaySystemSound
和AVAudioPlayer
但未成功(可能在模拟器中有效)。
这个简单的任务是否有简单的解决方案,还是我需要手动混合基于文件的音频内容?
提前致谢!
答案 0 :(得分:2)
您可以使用音频单元构建AUGraph并通过kAudioUnitSubType_AudioFilePlayer单元播放音频文件。
答案 1 :(得分: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;
}
答案 2 :(得分:0)
这可能是系统限制。如果在使用PlayAndRecord类别时调用AudioServicesPlaySystemSound时iOS设备没有执行任何操作,请尝试先停止AudioUnit,然后再调用此函数。
答案 3 :(得分:0)
我遇到了类似的问题。在 VOIP 应用程序中,我必须在通话过程中播放音调。使用 AVPlayer 播放音调文件将通过接收器以 50% 的音量播放。
对我有用的是在音调文件的持续时间内将 AVAudioSession 类别从 AVAudioSessionCategoryPlayAndRecord
切换到 AVAudioSessionCategoryPlayback
并返回。
这里有几个问题:
我认为发生的事情是扬声器被专门分配给 AudioUnit,任何使用 AVAudioPlayer 或 AVPlayer 的并行播放都通过接收器播放。如果您的音频文件的电平较低,则几乎不会引起注意。此外,当 AudioUnit 处于活动状态且 AVAudioSession 处于 PlayAndRecord 类别时,其他声音文件将被“躲避”。
您可以在连接设备时使用 Mac 的控制台确认这一点,搜索 mediaserverd 和 grep 以获取“duck”。
我得到了这样的东西:
default 18:36:01.844883-0800 mediaserverd -CMSessionMgr- cmsDuckVolumeBy: ducking 'sid:0x36952, $$$$$$(2854), 'prim'' duckToLevelDB = -40.0000 duckVolume = 0.100 duckFadeDuration = 0.500
default 18:36:02.371953-0800 mediaserverd -CMSystSounds- cmsmSystemSoundShouldPlay_block_invoke: SSID = 4096 with systemSoundCategory = UserAlert returning OutVolume = 1.000000, Audio = 1, Vibration = 2, Synchronized = 16, Interrupt = 0, NeedsDidFinishCall = 0, NeedsUnduckCall = 128, BudgetNotAvailable = 0
default 18:36:02.372685-0800 mediaserverd SSSActionLists.cpp:130:LogFlags: mSSID 4105, mShouldPlayAudio 1, mShouldVibe 1, mAudioVolume 1.000000, mVibeIntensity 1.000000, mNeedsFinishCall 0, mNeedsUnduckCall 1, mSynchronizedSystemSound 1, mInterruptCurrentSystemSounds 0
default 18:36:02.729872-0800 mediaserverd ActiveSoundList.cpp:386:SendUnduckMessageToCM: Notifying CM that sound should unduck now for ssidForCMSession: 4096, token 3569
default 18:36:02.729928-0800 mediaserverd -CMSystSounds- cmsmSystemSoundUnduckMedia: called for ssid 4096
default 18:36:02.729973-0800 mediaserverd -CMSessionMgr- cmsUnduckVolume: 'sid:0x36952, $$$$$$(2854), 'prim'' unduckFadeDuration: 0.500000