iOS AVAudioSession 详解【音乐播放器的配置】

前言

在 iOS 音频开发中,AVAudioSession 是至关重要的工具,它控制着应用的音频行为,包括播放、录音、后台支持和音频中断处理等。对于音乐播放器等音频需求强烈的应用,设计一个合理的 AVAudioSession 管理体系不仅能保证音频播放的流畅体验,也能确保应用在多种使用场景下的稳定性。本文将基于苹果官方文档,详细介绍如何使用 AVAudioSession,并探讨在音乐播放器设计中如何合理管理 AVAudioSession。

请添加图片描述

一、AVAudioSession 的基础概念

AVAudioSession 提供了一个全局的音频会话来管理应用的音频需求。音频会话分为多个类别(category)和模式(mode),并支持多种选项(options)以适应不同场景。每个类别有其特定的行为和适用场景,例如是否支持后台播放,是否允许耳机和蓝牙播放等。音频会话配置完成后,通过激活音频会话来使配置生效。

主要概念:
1. 类别 (Category):定义了应用的音频行为,决定了应用如何与系统中的其他音频(如电话或音乐)交互
官方文档:avaudiosession/category

常用类别:
• .playback
用于媒体播放,确保在静音模式下音频仍然可以播放。
• .record
专注于音频输入,如语音录制。
• .playAndRecord
允许同时播放和录音,适用于视频通话等场景。
• .ambient
适合背景音频,音频会在其他音频播放或静音模式下暂停。
• .soloAmbient
类似于 .ambient,但会在其他音频播放时自动静音。
• .multiRoute
支持同时向多个输出设备播放音频,如耳机和扬声器。

2. 模式 (Mode):定义了音频会话的具体操作模式,影响音频处理的特定方式。通过选择适当的模式,开发者可以优化应用的音频行为,以适应不同的使用场景。
官方文档:avaudiosession/mode

常用模式:
• .default
默认模式,适用于大多数音频任务。
• .voiceChat
适合语音聊天,优化语音输入和输出质量。
• .videoRecording
针对视频录制,优化视频和音频的同步。
• .measurement
适合音频测量应用,确保最低延迟和最佳质量。
• .gameChat
优化游戏内语音聊天,确保低延迟和高质量。

3. 选项 (Options):用于进一步细化和调整音频会话类别的行为,通过组合不同的选项,可以实现特定的音频需求。
官方文档:avaudiosession/categoryoptions

常用选项:
• mixWithOthers
允许与其他音频会话混合播放音频,适用于需要与其他音频同时播放的场景。
• duckOthers
在播放音频时,降低其他正在播放的音频的音量。
• allowBluetooth
允许使用蓝牙音频设备进行音频输入和输出。
• defaultToSpeaker
默认将音频路由到扬声器,而不是耳机。

二、AVAudioSession 不同场景的配置表

场景类别 (Category)模式 (Mode)选项 (Options)说明
音乐播放器.playback.default默认: 空
特殊: .mixWithOthers,允许与其他音频混合播放
在播放音乐时,默认情况下不需要特殊配置。特殊情况需要支持和与其他音频同时播放。
语音通话.playAndRecord.voiceChat默认: 空
特殊: .allowBluetooth,支持蓝牙通话
.defaultToSpeaker,通话时默认使用扬声器
通话场景一般无需特殊配置,但如果使用蓝牙设备或希望通话时自动切换到扬声器,则需要这些选项。
视频播放.playback.video默认: 空
特殊: .allowAirPlay,支持 AirPlay 输出
播放视频时一般不需特殊配置。若需要通过 AirPlay 播放视频,可以使用此选项。
语音识别.playAndRecord.measurement默认: 空
特殊: .defaultToSpeaker,默认使用扬声器
语音识别通常不需额外选项,但若需要确保输出清晰,可设置为使用扬声器。
游戏音效.ambient.default默认: 空
特殊: .mixWithOthers,允许与其他音频混合
.duckOthers,降低其他音频音量
游戏场景通常允许与其他音频混合。若需要强调游戏音效,可选择降低其他音频音量。
音频录制.playAndRecord.default默认: 空
特殊: .defaultToSpeaker,录制时输出使用扬声器
录制场景一般不需特殊配置,但若希望使用扬声器输出录制音频可设置此选项。
播放有声书.playback.spokenAudio默认: 空
特殊: .allowBluetooth,允许蓝牙音频输出
播放有声书时一般不需要特殊配置,若希望支持蓝牙播放则需此选项。
后台播放.playback.default默认: 空
特殊: .mixWithOthers,允许与其他音频混合
在应用后台播放音乐时,一般需要设置此选项以确保音乐继续播放。
语音导航.playAndRecord.voicePrompt默认: 空
特殊: .defaultToSpeaker,默认使用扬声器
.allowBluetooth,支持蓝牙音频输出
导航应用通常使用扬声器播放语音提示,若希望支持蓝牙设备则需额外配置。
录音与播放.playAndRecord.default默认: 空
特殊: .mixWithOthers,允许与其他音频混合
.allowBluetooth,支持蓝牙
在同时录音和播放音频时,需根据需求配置选项,以确保音频效果良好。
网络广播.playback.default默认: 空
特殊: .allowAirPlay,支持 AirPlay 输出
.mixWithOthers,允许与其他音频混合
在进行网络广播时,允许与其他音频混合播放,并支持 AirPlay 输出以保证流畅性。
声音提示.ambient.default默认: 空
特殊: .mixWithOthers,允许与其他音频混合
播放短声音提示时,通常不需要特殊配置,若希望同时播放与其他音频,则需此选项。

说明

  • 默认情况: 在没有特殊需求的情况下,Options 一般为空。
  • 特殊情况 根据应用场景的具体需求,选择适合的 Options 选项可以提升用户体验。例如,如果应用需要支持蓝牙音频或在后台持续播放,需明确配置相关选项。

正确配置 AVAudioSession 的类别、模式和选项对于提升音频播放和录制体验至关重要。根据应用场景灵活调整这些设置可以确保音频质量和用户体验。

三、音乐播放器中的 AVAudioSession 配置

在音乐播放器的设计中,我们需要支持后台播放、音频中断处理等。接下来我们将逐步设计 AVAudioSession 的配置和管理方法。

  1. 配置 AVAudioSession 的类别和选项
    音乐播放器的核心需求是播放音频,并支持在应用进入后台时继续播放。因此,我们可以设置音频会话的类别为 .playback。
    一般在播放管理类初始化时,配置一次就可以了
   //配置流通道
    func configureAudioSession() {
          do {
              print("AudioSession category is AVAudioSessionCategoryPlayback")
              try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [])
          } catch let error as NSError {
              print("Couldn't setup audio session category to Playback \(error.localizedDescription)")
          }
    }
  1. 激活和管理音频会话
    你可以在设置类别后的任何时间激活音频会话,但通常最好将此调用推迟到应用程序开始音频播放。延迟调用可以确保您不会过早地中断正在进行的任何其他背景音频。

激活:建议在开始播放时调用

func activateAudioSession() {
    do {
        try AVAudioSession.sharedInstance().setActive(true)
    } catch {
        print("Failed to activate audio session: \(error)")
    }
}

停用
停用当前音频会话,并通知其他应用继续播放;
在确定当前应用没有音频播放的情况下调用。

func deactivateAudioSession() {
    do {
        try AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)
    } catch {
        print("Failed to deactivate audio session: \(error)")
    }
}
  1. 音频中断处理
    音频中断(如来电)是音频应用中常见的场景。在音频中断时,AVAudioSession 会发送中断通知,我们需要监听并处理这些通知,暂停当前播放,并在中断结束后恢复播放。
NotificationCenter.default.addObserver(self, selector: #selector(handleInterruption), name: AVAudioSession.interruptionNotification, object: nil)

@objc func handleInterruption(notification: Notification) {
    guard let userInfo = notification.userInfo,
          let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
          let interruptionType = AVAudioSession.InterruptionType(rawValue: typeValue) else {
        return
    }

    switch interruptionType {
    case .began:
        // 中断开始,暂停播放
        pauseMusic()
    case .ended:
        if let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt {
            let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
            if options.contains(.shouldResume) {
                resumeMusic()
            }
        }
    default:
        break
    }
}
  1. 判断是否有其它应用在播放
    secondaryAudioShouldBeSilencedHint:一个布尔值,表示另一个具有不可混合音频会话的应用程序是否正在播放音频
if AVAudioSession.sharedInstance().secondaryAudioShouldBeSilencedHint {
    print("有更高优先级的音频正在播放,静音当前音频")
} else {
    // 正常播放音频
    print("无其他高优先级音频,可以正常播放音频")
}

isOtherAudioPlaying:表示另一个应用程序是否正在播放音频的布尔值

if AVAudioSession.sharedInstance().isOtherAudioPlaying {
    print("检测到其他音频在播放")
    // 可选择使用 .mixWithOthers 选项进行混合播放
} else {
    print("没有其他音频在播放,可以独占播放")
    // 开始正常播放
}

总结

在音乐播放器中,AVAudioSession 是确保音频会话稳定和高效管理的关键。通过合理设置音频会话的类别和模式,结合锁屏信息展示和远程控制,我们可以提供流畅、贴心的用户体验。同时,注意音频中断处理和远程控制的配置,将让应用的音频体验更加完善和专业。

参考官方文档
documentation/avfaudio/avaudiosession


感谢您的阅读和参与,HH思无邪愿与您一起在技术的道路上不断探索。如果您喜欢这篇文章,不妨留下您宝贵的赞!如果您对文章有任何疑问或建议,欢迎在评论区留言,我会第一时间处理,您的支持是我前行的动力,愿我们都能成为更好的自己!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/901430.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[JAVAEE] 多线程的案例(三) - 线程池

目录 一. 什么是线程池 二. 线程池的作用 三. java提供的线程池类 四. ThreadPoolExecutor的构造方法及参数理解 1. int corePoolSize: 核心线程数. 2. int maximumPoolSize: 最大线程数 核心线程数 非核心线程数 3. int keepAliveTime:非核心线程允许空闲的最大时间. …

网络通信与并发编程(六)线程、进程池与线程池

线程、进程池与线程池 文章目录 线程、进程池与线程池一、线程二、线程的相关操作2.1创建线程的两种方式2.2线程的其他操作2.3死锁现象和递归锁2.4条件2.5定时器2.6 队列与堆栈 三、进程池与线程池 一、线程 线程是指cpu上实际执行计算的单位,而进程是将计算所需资…

Leetcode刷题笔记12

HJ1 字符串最后一个单词的长度 字符串最后一个单词的长度_牛客题霸_牛客网 这里可以使用rfind(),rfind()函数从字符串的末尾向前查找第一个空格的位置。这个空格将是最后一个单词和前面的单词的分隔符。首先使用getline读取字符串,然后用rfind找到最后一…

class 36 二叉树高频题目 - 上 (不含有树形dp)

1. BFS 的两种方式 如下图, 是一个二叉树. 我们需要按照层的方式来遍历这棵树. 1.1 使用 JDK 自带的类实现(链表实现, 经典 BFS) 首先我们实现一个队列, 这个队列从头进, 从尾出.然后将根节点放入其中, 然后将放入的节点弹出,然后继续验证弹出的节点有没有左孩子, 若是有, 将…

便捷之选:微信小程序驱动的停车场管理系统

作者介绍:✌️大厂全栈码农|毕设实战开发,专注于大学生项目实战开发、讲解和毕业答疑辅导。 🍅获取源码联系方式请查看文末🍅 推荐订阅精彩专栏 👇🏻 避免错过下次更新 Springboot项目精选实战案例 更多项目…

跨境支付,哪些国产数据库能接得住?

最近有一个非常重大的事件,那就是10月22日-24日的金砖国家会议。金砖国家领导人第十六次会晤是金砖国家进一步凝聚共识、以实际行动推动“全球南方”共同发展进步的重要机遇。 酝酿已久的金砖跨境支付体系,也在这次峰会中正式推出。金砖国家的支付系统一…

国内大语言模型哪家更好用?

大家好,我是袁庭新。 过去一年,AI大语言模型在爆发式增长,呈现百家争鸣之态。国内外相关厂商积极布局,并相继推出自家研发的智能化产品。 我在工作中已习惯借助AI来辅助完成些编码、创作、文生图等任务,甚至对它们产…

【计网】从零开始认识IP协议 --- 认识网络层,认识IP报头结构

从零开始认识IP协议 1 网络层协议1.1 初步认识IP协议1.2 初步理解IP地址 2 IP协议报头3 初步理解网段划分 1 网络层协议 1.1 初步认识IP协议 我们已经熟悉了传输层中的UDP和TCP协议,接下来我们来接触网络层的协议: 网络层在计算机网络中的意义主要体现…

线段树

文章目录 1 线段树概念2 线段树操作2.1 建树2.2 区间修改2.3 区间查询2.4 练习题目 3 线段树进阶3.1 乘法线段树 * 补充:快读快写4 End 1 线段树概念 线段树 ( S e g m e n t T r e e ) (Segment\ Tree) (Segment Tree) 是 O I OI OI 中的常用算法。线段树是一种…

PHP-FPM 性能配置优化

4 核 8 G 服务器大约可以开启 500 个 PHP-FPM,极限吞吐量在 580 qps (Query Per Second 每秒查询数)左右。 Nginx php-fpm 是怎么工作的? php-fpm 全称是 PHP FastCGI Process Manager 的简称,从名字可得知&#xff…

基于SSM的冰淇淋在线购买网站【附源码】

基于SSM的冰淇淋在线购买网站 效果如下: 系统首页界面 用户登录界面 冰淇淋页面 每日秒杀页面 个人中心界面 管理员登录界面 管理员功能界面 口味管理界面 冰淇淋管理界面 每日秒杀管理界面 视频教学管理界面 研究背景 近些年,随着中国经济发展&#…

订购 Claude AI 的第二天 它独自完成 文字转语音 flask应用

图二里,删除几个无关的 chats 全程我做的工作:向 AI 提要求,copy / paste 代码,在venv验证运行,向 AI 反馈,总共用了3个 chats.(图中的只有一个 Chat, 删掉的另外两个: Python 库安…

海外云手机实现高效的海外社交媒体营销

随着全球化的深入发展,越来越多的中国企业走向国际市场,尤其是B2B外贸企业,海外社交媒体营销已成为其扩大市场的重要手段。在复杂多变的海外市场环境中,如何有效提高营销效率并降低运营风险,成为了众多企业的首要任务。…

计算机网络(十二) —— 高级IO

#1024程序员节 | 征文# 目录 一,预备 1.1 重新理解IO 1.2 五种IO模型 1.3 非阻塞IO 二,select 2.1 关于select 2.2 select接口参数解释 2.3 timeval结构体和fd_set类型 2.4 socket就绪条件 2.5 select基本工作流程 2.6 简单select的服务器代…

【mysql进阶】4-8 临时表空间

临时表空间 - Temporary Tablespaces 1 什么是临时表? ✅ 解答问题 临时表存储的是临时数据,不能永久的存储数据,⼀般在复杂的查询或计算过程中⽤来存储过渡的中间结果,MySQL在执⾏查询与计算的过程中会⾃动⽣成临时表&#xff0c…

C++ 抛异常

目录 一.抛异常与运行崩溃的区别 1.运行崩溃 2.抛异常 二.抛异常机制存在的意义 1.清晰的处理错误 2.结构化的错误管理 3.跨函数传递错误信息 4.异常对象多态性 三.抛异常的使用方法 1.抛出异常 (throw) 2.捕获异常 (catch) 3.标准异常类 四.抛异常的处理机制 1.抛…

2024“源鲁杯“高校网络安全技能大赛-Misc-WP

Round 1 hide_png 题目给了一张图片,flag就在图片上,不过不太明显,写个python脚本处理一下 from PIL import Image ​ # 打开图像并转换为RGB模式 img Image.open("./attachments.png").convert("RGB") ​ # 获取图像…

rabbitmq 使用注意事项

1,注意开启的端口号,一共四个端口号,1883是mqtt连接的端口号,如果没开,是连接不上的需要手动起mqtt插件。 //开始mqtt插件服务 rabbitmq-plugins enable rabbitmq_mqtt 2,15672端口是http网页登录的管理后…

Next Stack技术联盟成立:打造新一代基础软件技术栈

北京,2024 年 10 月 —— 在全球数字化浪潮的推动下,中国基础软件产业迎来了前所未有的创新机遇与挑战。为应对这一时代任务并推动中国基础软件的全球化进程,观测云携手多家领先技术企业正式宣布成立 Next Stack 技术联盟。这一联盟旨在汇聚国…

接口测试(五)jmeter——get请求

一、get请求——短信验证码(示例仅供参考) 1. get请求:传参数据直接拼接在地址后面,jmeter不需要设置请求头content-type 注:短信验证码接口,返回结果中不会返回短信验证码,是存在数据库表中&a…