gpt4 book ai didi

ios - 通过上部(电话)扬声器播放音频

转载 作者:技术小花猫 更新时间:2023-10-29 11:10:19 26 4
gpt4 key购买 nike

我正在尝试让我的应用程序中的音频通过 iPhone 上的上部扬声器播放,即您在通话期间按在耳朵上的那个扬声器。我知道这是可能的,因为我玩过 App Store 上的一款模拟电话的游戏(“The Heist” by “tap tap tap”),并且确实做到了这一点。

我在网上做了很多研究,但我很难找到任何人甚至讨论过这种可能性。绝大多数帖子似乎是关于免提扬声器与插入式耳机(如 thisthisthis),而不是上面的“电话”扬声器与免提扬声器。 (这个问题的一部分可能没有一个好名字:“电话扬声器”通常意味着设备底部的免提扬声器等,因此很难进行真正有针对性的搜索)。我查看了 Apple 的 Audio Session Category Route Overrides ,但那些似乎再次(如果我错了请纠正我)只处理底部的免提扬声器,而不是电话顶部的扬声器。

我找到了一篇似乎与此相关的帖子:link .它甚至提供了一堆代码,所以我以为我可以在家自由,但现在我似乎无法让代码工作。为简单起见,我只是复制了 DisableSpeakerPhone方法(如果我理解正确,它应该是将音频重新路由到上扬声器的方法)到我的 viewDidLoad看看它是否会工作,但第一个“断言”行失败,音频继续在底部播放。 (我还按照评论中的建议导入了 AudioToolbox 框架,所以这不是问题。)

这是我正在使用的主要代码块(这是我复制到我的 viewDidLoad 中进行测试的内容),尽管我链接到的文章中还有一些方法:

void DisableSpeakerPhone () {
UInt32 dataSize = sizeof(CFStringRef);
CFStringRef currentRoute = NULL;
OSStatus result = noErr;

AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &dataSize, &currentRoute);

// 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 音乐播放器播放音频(在 viewDidLoad 中的 AVAudioSession 行之后立即初始化,这是值得的):
_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 播放媒体”方法之类的?或者有没有办法检查当前处于事件状态的 Audio Session 类别,以确认没有任何东西可以将其切换回来或其他什么?有没有办法强调地告诉代码使用接收器,而不是依赖默认值来这样做?我觉得我在一码线上,我只需要越过最后一点......

编辑:我只是想到了一个理论,其中关于 iPod 音乐播放器不想在接收器外播放。我的推理:可以通过官方 iPod 应用程序设置一首歌曲开始播放,然后通过我正在开发的应用程序无缝调整(暂停、跳过等)。从一个应用程序到下一个应用程序的连续播放让我想到可能iPod音乐播放器有自己的音频路由设置,或者它不会停下来检查新应用程序中的设置?有没有知道他们在说什么的人认为它可能是这样的?

最佳答案

您必须先初始化 Audio Session 。

使用 C API

  AudioSessionInitialize (NULL, NULL, NULL, NULL);

在 iOS6 中,您可以改用 AVAudioSession 方法(您需要导入 AVFoundation 框架才能使用 AVAudioSession):

使用 AVAudioSession 初始化
 self.audioSession = [AVAudioSession sharedInstance];

使用 AVAudioSession 设置 audioSession 类别
 [self.audioSession setCategory:AVAudioSessionCategoryPlayAndRecord
error:nil];

为了进一步研究,如果您想要更好的搜索词,以下是扬声器常量的全名:
const CFStringRef kAudioSessionOutputRoute_BuiltInReceiver;
const CFStringRef kAudioSessionOutputRoute_BuiltInSpeaker;

查看苹果的文档 here

但真正的谜团是为什么您在路由到接收器时遇到任何问题。这是 playAndRecord 类别的默认行为。 Apple 的文档 kAudioSessionOverrideAudioRoute_None :

“指定,对于 kAudioSessionCategory_PlayAndRecord 类别,输出音频应进入接收器。 这是该类别的默认输出音频路由。

更新

在您更新的问题中,您透露您正在使用 MPMusicPlayerController类(class)。此类调用全局音乐播放器(与音乐应用程序中使用的播放器相同)。此音乐播放器与您的应用程序分开,因此不会与您的应用程序的 audioSession 共享相同的 Audio Session 。 MPMusicPlayerController 将忽略您在应用的 audioSession 上设置的任何属性。

如果您想控制应用的音频行为,则需要使用应用内部的音频框架。这将是 AVAudioRecorder/ AVAudioPlayer或核心音频(音频队列、音频单元或 OpenAL)。无论您使用哪种方法,都可以通过 AVAudioSession 控制 Audio Session 。属性或通过 Core Audio API。 Core Audio 为您提供更细粒度的控制,但随着 iOS 的每个新版本,更多的它被移植到 AVFoundation,所以从它开始。

还要记住, Audio Session 为您提供了一种方法来描述与整个 iOS 环境相关的应用音频的预期行为,但它不会让您完全控制。 Apple 会注意确保用户对其设备音频行为的期望在应用程序之间以及当一个应用程序需要中断另一个应用程序的音频流时保持一致。

更新 2

在您的编辑中,您提到了 Audio Session 检查其他应用程序的 Audio Session 设置的可能性。那不会发生1。这个想法是每个应用程序使用它的自包含 Audio Session 来设置它自己的音频行为的首选项。当多个应用程序竞争不可共享的资源(例如内部麦克风或其中一个扬声器)时,操作系统会在冲突的音频要求之间进行仲裁,并且通常会决定支持最有可能满足用户期望的行为设备作为一个整体。

MPMusicPlayerController 类有点不寻常,因为它使您能够让一个应用程序在一定程度上控制另一个应用程序。在这种情况下,您的应用不会播放音频,而是向音乐播放器发送请求以代表您播放音频。您的控制受到 MPMusicPlayerController API 范围的限制。为了获得更多控制,您的应用程序必须提供它自己的音频播放实现。

在您的评论中,您想知道:

Could there be a way to pull an MPMediaItem from the MPMusicPlayerController and then play them through the app-specific audio session, or anything like that?



这是一个新问题的(大)主题。这是一个很好的入门读物(来自 Chris Adamson 的博客) From iPod Library to PCM Samples in Far Fewer Steps Than Were Previously Necessary - 这是 From iphone media library to pcm samples in dozens of confounding and potentially lossy steps 的续集- 这应该让您了解您将面临的复杂性。自 iOS6 以来,这可能变得更容易了,但我不太确定!

1 有一个 otherAudioPlaying ios6 中的只读 BOOL 属性,仅此而已

关于ios - 通过上部(电话)扬声器播放音频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18026578/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com