我正在尝试让我的应用程序中的音频通过 iPhone 上的上扬声器播放,这是您在通话期间按在耳朵上的那个。我知道这是可能的,因为我玩过 App Store 上的一款游戏(“tap tap tap”中的“The Heist”),它模拟了电话通话并做到了这一点。
我在网上做了很多研究,但我很难找到任何甚至讨论过这种可能性的人。绝大多数帖子似乎是关于免提扬声器与插入式耳机(如this和this和this),而不是上部“电话”扬声器与免提扬声器。(部分问题可能是它没有一个好名字:“电话扬声器”通常是指设备底部的免提扬声器等,因此很难进行有针对性的搜索)。我研究过苹果的Audio Session Category Route Overrides
,但那些似乎(如果我错了,请纠正我)只处理底部的免提扬声器,而不是手机顶部的扬声器。
我发现了一篇似乎与此有关的帖子:链接。它甚至提供了一堆代码,所以我以为我在家自由,但现在我似乎无法让代码工作。为简单起见,我只是将DisableSpeakerPhone
方法(如果我理解正确,应该是将音频重新路由到上扬声器的方法)复制到我的方法viewDidLoad
中,看看它是否可行,但第一条“断言”行失败,音频继续发挥底部。(我还按照评论中的建议导入了 AudioToolbox 框架,所以这不是问题。)
这是我正在使用的主要代码块(这是我复制到我viewDidLoad
的测试中的内容),尽管我链接到的文章中还有一些方法:
void DisableSpeakerPhone () {
UInt32 dataSize = sizeof(CFStringRef);
CFStringRef currentRoute = NULL;
OSStatus result = noErr;
AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &dataSize, ¤tRoute);
// Set the category to use the speakers and microphone.
UInt32 sessionCategory = kAudioSessionCategory_PlayAndRecord;
result = AudioSessionSetProperty (
kAudioSessionProperty_AudioCategory,
sizeof (sessionCategory),
&sessionCategory
);
assert(result == kAudioSessionNoError);
Float64 sampleRate = 44100.0;
dataSize = sizeof(sampleRate);
result = AudioSessionSetProperty (
kAudioSessionProperty_PreferredHardwareSampleRate,
dataSize,
&sampleRate
);
assert(result == kAudioSessionNoError);
// Default to speakerphone if a headset isn't plugged in.
// Overriding the output audio route
UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_None;
dataSize = sizeof(audioRouteOverride);
AudioSessionSetProperty(
kAudioSessionProperty_OverrideAudioRoute,
dataSize,
&audioRouteOverride);
assert(result == kAudioSessionNoError);
AudioSessionSetActive(YES);
}
所以我的问题是:任何人都可以A)帮助我弄清楚为什么该代码不起作用,或者B)提供更好的建议,以便能够按下按钮并将音频路由到上部扬声器?
PS 我越来越熟悉 iOS 编程,但这是我第一次涉足 AudioSessions 等领域,因此非常感谢详细信息和代码示例!谢谢您的帮助!
更新:
根据“他是”(下)的建议,我删除了上面引用的代码并将其替换为:
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayAndRecord error:nil];
[[AVAudioSession sharedInstance] setActive: YES error:nil];
开始时viewDidLoad
。但是,它仍然无法正常工作(我的意思是音频仍然来自手机底部的扬声器,而不是顶部的接收器)。显然,默认行为应该是AVAudioSessionCategoryPlayAndRecord
自己从接收器发送音频,所以还是有问题。
更具体地说,我正在使用此代码执行的操作是通过 iPod 音乐播放器播放音频(在上面的 AVAudioSession 行之后立即初始化viewDidLoad
,这是值得的):
_musicPlayer = [MPMusicPlayerController iPodMusicPlayer];
并且该 iPod 音乐播放器的媒体是通过以下方式选择的MPMediaPickerController
:
- (void) mediaPicker: (MPMediaPickerController *) mediaPicker didPickMediaItems: (MPMediaItemCollection *) mediaItemCollection {
if (mediaItemCollection) {
[_musicPlayer setQueueWithItemCollection: mediaItemCollection];
[_musicPlayer play];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
这一切对我来说似乎相当简单,我没有任何错误或警告,而且我知道媒体选择器和音乐播放器工作正常,因为正确的歌曲开始播放,只是来自错误的扬声器。是否有“使用此 AudioSession 播放媒体”方法之类的?或者有没有办法检查当前处于活动状态的音频会话类别,以确认没有任何东西可以将其切换回来或其他什么?有没有办法强调告诉代码使用接收器,而不是依赖默认值来这样做?我觉得我在一码线上,我只需要越过最后一点......
编辑:我只是想到了一个理论,其中关于 iPod 音乐播放器不想从接收器中播放。我的推理:可以设置一首歌曲通过官方 iPod 应用程序开始播放,然后通过我正在开发的应用程序无缝调整(暂停、跳过等)。从一个应用程序到下一个应用程序的连续播放让我觉得也许 iPod 音乐播放器有自己的音频路由设置,或者它不会停止检查新应用程序中的设置?有谁知道他们在说什么认为它可能是这样的吗?