我在我正在创建的必须同时播放和录制的应用程序中使用 SpeakHere 音频类。
我在通用应用程序构建(针对 iPad 和 iPhone)中使用带有 3.2 设备目标的最新 SDK。
该应用程序使用 MPMoviePlayerController 播放流媒体电影并同时录制音频。
这在 iPhone 上 100% 完美运行。
但是,它在我的客户 iPad 上 100% 失败。 日志显示 AudioSession 拒绝激活的 !act 错误!我从他那里收到的每个日志文件都包含许多被返回给回调函数的中断和路由更改(即类别)。**在 iPhone 上,我根本看不到这样的东西。日志仅显示已创建记录并记录到指定文件。没有中断,没有路线变化,没有废话。
以下是相关日志:
Jul 10 07:15:21 iPad mediaserverd[15502] <Error>: [07:15:21.464 <0x1207000>] AudioSessionSetClientPlayState: Error adding running client - session not active
Sat Jul 10 07:15:21 iPad mediaserverd[15502] <Error>: [07:15:21.464 <AudioQueueServer>] AudioQueue: Error '!act' from AudioSessionSetClientPlayState(15642)
我已经删除了两个回调函数,仅记录中断的发生和路由更改(有原因)。所以我不会费心发布代码,因为它实际上什么也没做。不过,在一次尝试开始在 iPad 上录制期间,我多次看到这些日志。
我几乎已经阅读了在 Apple Dev 论坛和 StackOverflow 中可以找到的所有帖子,但似乎无法在 Apple Docs 中找到有相同问题的人或任何解释 iPad 行为差异的相关注释。--注意:iPad 确实显示了一些其他已修复的缺陷行为,例如永不结束的不匹配的 Begin Interruption 呼叫(因此我从未停用会话)。
我从未收到任何日志,表明来自 AudioQueue 或 AudioSession 代码的任何失败的初始化或激活调用。当我尝试开始录制时,它只是失败了。--我什至试图强制 AudioSessionSetActive(true); 在每次尝试使用音响系统之前打电话,我仍然收到这些错误。
这是初始化调用的相关代码:
//Initialize the Sound System
OSStatus error = AudioSessionInitialize(NULL, NULL, interruptionListener, self);
if (error){ printf("ERROR INITIALIZING AUDIO SESSION! %d\n", (int)error); }
else {
//must set the session active first according to devs talking about some defect....
error = AudioSessionSetActive(true);
if (error) NSLog(@"AudioSessionSetActive (true) failed");
UInt32 category = kAudioSessionCategory_PlayAndRecord;
error = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category);
if (error) printf("couldn't set audio category!\n");
error = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, propListener, self);
if (error) printf("ERROR ADDING AUDIO SESSION PROP LISTENER! %d\n", (int)error);
//Force mixing!
UInt32 allowMixing = true;
error = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof (allowMixing), &allowMixing );
if (error) printf("ERROR ENABLING MIXING PROPS! %d\n", (int)error);
UInt32 inputAvailable = 0;
UInt32 size = sizeof(inputAvailable);
// we do not want to allow recording if input is not available
error = AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable, &size, &inputAvailable);
if (error) printf("ERROR GETTING INPUT AVAILABILITY! %d\n", (int)error);
isInputAvailable = (inputAvailable) ? YES : NO;
//iPad doesn't require the routing changes, branched to help isolate iPad behavioral issues
if(! [Utils GetMainVC].usingiPad){
//redirect to speaker? //this only resets on a category change!
UInt32 doChangeDefaultRoute = 1;
error = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker, sizeof (doChangeDefaultRoute), &doChangeDefaultRoute);
if (error) printf("ERROR CHANGING DEFAULT ROUTE PROPS! %d\n", (int)error);
//this resets with interruption and/or route changes
UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
error = AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute,sizeof (audioRouteOverride),&audioRouteOverride);
if (error) printf("ERROR SPEAKER ROUTE PROPS! %d\n", (int)error);
}
// we also need to listen to see if input availability changes
error = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioInputAvailable, propListener, self);
if (error) printf("ERROR ADDING AUDIO SESSION PROP LISTENER! %d\n", (int)error);
error = AudioSessionSetActive(true);
if (error) NSLog(@"AudioSessionSetActive (true) failed");
}
// Allocate our singleton instance for the recorder & player object
myRecorder = new AQRecorder();
myPlayer = new AQPlayer();
稍后在视频的 loadstate 回调中,我只是尝试开始录制到预定的文件路径:
myRecorder->StartRecord((CFStringRef)myPathStr);
录音完全失败。
感谢您的时间和帮助。