iOS 关于音频开发

音频方面的知识,相对其他编程还是较为复杂的,特别是要搞清楚框架里具体使用的参数和方法,不然写起代码来非常迷茫.

1:播放简短性质的音频,例如按键声音,等可以这样实现.

一:引入框架:

#import <AudioToolbox/AudioToolbox.h>

二:先声明一个声音源ID

SystemSoundID _bookSoundID;

三:提供需要播放的音频地址进行声音源的注册.

    NSURL *bookSoundUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"bookSound" ofType:@"wav"]];
    AudioServicesCreateSystemSoundID((__bridge CFURLRef)bookSoundUrl, &_bookSoundID);

四:在需要的时候播放:

AudioServicesPlaySystemSound(_bookSoundID);

五:不用的声音源记得释放掉

AudioServicesDisposeSystemSoundID(_bookSoundID);

2: 关于 AVAudioSession 的使用

首先知道 AVAudioSession  是一个单例模式,也就是说,不用开发者自行实例化. 这个类在各种音频环境中起着非常重要的作用

一:首先是设置 AVAudioSession 的 类别

                                                                                      获取输入硬 件          获取输出硬件       与IPOD混合      遵从振铃/静音按键
AVAudioSessionCategoryAmbient                            否                               是                          是                         是

AVAudioSessionCategorySoloAmbient                    否                              是                           否                         是

AVAudioSessionCategoryPlayback                          否                               是                           否                        否

AVAudioSessionCategoryRecord                              是                              否                           否                         否

AVAudioSessionCategoryPlayAndRecord              是                              是                           否                         否

根据实际的使用情况来设定具体的类别,设置代码如下:

AVAudioSession * audioSession = [AVAudioSession sharedInstance]; //得到AVAudioSession单例对象
[audioSession setDelegate:self];//设定代理
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error: &error];//设置类别,表示该应用同时支持播放和录音
[audioSession setActive:YES error: &error];//启动音频会话管理,此时会阻断后台音乐的播放.

二:在录制完声音或者播放完声音后,可以将音频会话关闭,来延续后台音乐的播放,代码如下:

[[AVAudioSession sharedInstance] setActive:NO error: nil];

三:通过音频会话可以强制的设置应用程序使用指定的输出方式,例如:内声道,扬声器,代码如下:

    UInt32 audioRouteOverride = hasHeadset ?kAudioSessionOverrideAudioRoute_None:kAudioSessionOverrideAudioRoute_Speaker;
    AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride), &audioRouteOverride);

kAudioSessionOverrideAudioRoute_None  内声道,耳机

kAudioSessionOverrideAudioRoute_Speaker 扬声器

四:那么怎么判断用户是否已经插入耳机?代码如下: (参考:http://iandworld.sinaapp.com/?p=184001)

- (BOOL)hasHeadset {
//模拟器不支持
#if TARGET_IPHONE_SIMULATOR
    #warning *** Simulator mode: audio session code works only on a device
    return NO;
#else
    CFStringRef route;
    UInt32 propertySize = sizeof(CFStringRef);
    AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &route);

    if((route == NULL) || (CFStringGetLength(route) == 0)){
        // Silent Mode
        NSLog(@"AudioRoute: SILENT, do nothing!");
    } else {
        NSString* routeStr = (__bridge NSString*)route;
        NSLog(@"AudioRoute: %@", routeStr);

        /* Known values of route:
         * "Headset"
         * "Headphone"
         * "Speaker"
         * "SpeakerAndMicrophone"
         * "HeadphonesAndMicrophone"
         * "HeadsetInOut"
         * "ReceiverAndMicrophone"
         * "Lineout"
         */

        NSRange headphoneRange = [routeStr rangeOfString : @"Headphone"];
        NSRange headsetRange = [routeStr rangeOfString : @"Headset"];
        if (headphoneRange.location != NSNotFound) {
            return YES;
        } else if(headsetRange.location != NSNotFound) {
            return YES;
        }
    }
    return NO;
#endif

}

返回YES,表示已经插入耳机,返回NO表示没有插入耳机

五:监听用户拔出插入耳机事件

1:注册监听事件,和回调函数

AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChange,
                                     audioRouteChangeListenerCallback,
                                     self);

2:实现回调函数进行相关处理:

void audioRouteChangeListenerCallback (
                                       void                      *inUserData,
                                       AudioSessionPropertyID    inPropertyID,
                                       UInt32                    inPropertyValueSize,
                                       const void                *inPropertyValue
                                       ) {

    if (inPropertyID != kAudioSessionProperty_AudioRouteChange) return;
    // Determines the reason for the route change, to ensure that it is not
    //		because of a category change.
    CFDictionaryRef	routeChangeDictionary = inPropertyValue;

    CFNumberRef routeChangeReasonRef =
    CFDictionaryGetValue (routeChangeDictionary,
                          CFSTR (kAudioSession_AudioRouteChangeKey_Reason));

    SInt32 routeChangeReason;

    CFNumberGetValue (routeChangeReasonRef, kCFNumberSInt32Type, &routeChangeReason);
    NSLog(@" ===================================== RouteChangeReason : %d", routeChangeReason);
    AudioHelper *_self = (AudioHelper *) inUserData;
    if (routeChangeReason == kAudioSessionRouteChangeReason_OldDeviceUnavailable) {
        [_self resetSettings];
        if (![_self hasHeadset]) {
            [[NSNotificationCenter defaultCenter] postNotificationName:@"ununpluggingHeadse"
                                                                object:nil];
        }
    } else if (routeChangeReason == kAudioSessionRouteChangeReason_NewDeviceAvailable) {
        [_self resetSettings];
        if (![_self hasMicphone]) {
            [[NSNotificationCenter defaultCenter] postNotificationName:@"pluggInMicrophone"
                                                                object:nil];
        }
    } else if (routeChangeReason == kAudioSessionRouteChangeReason_NoSuitableRouteForCategory) {
        [_self resetSettings];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"lostMicroPhone"
                                                            object:nil];
    }
    //else if (routeChangeReason == kAudioSessionRouteChangeReason_CategoryChange  ) {
    //    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
    //}

    [_self printCurrentCategory];
}

六:如何保持后台音乐的一直播放呢? (参考:http://blog.csdn.net/yhawaii/article/details/7788340)

1:在Info.plist中,添加"Required background modes"键,其值设置如下图所示:

2:系统音频服务支持音频播放,并关闭其他正在播放的音频

AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES error:nil];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];

3:设置app支持接受远程控制事件代码:

[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

设置app支持接受远程控制事件,其实就是在dock中可以显示应用程序图标,同时点击该图片时,打开app,如下图所示:

4:执行 AVAudioPlayer  

七 关于音量

1:由应用主动获取系统音量

UInt32 dataSize = sizeof(float);
AudioSessionGetProperty (kAudioSessionProperty_CurrentHardwareOutputVolume,
                                           &dataSize,
                                           &keyVolume);

获取之前要确保

AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES error:nil];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];

2:由应用主动设置系统音量 (参考:http://blog.csdn.net/studyrecord/article/details/6452354)

八:关于音频边下载边播放的实现.

请参考:AudioStreamer

https://github.com/mattgallagher/AudioStreamer

如果你只是想简简单单在线播放以下不做任何处理. 那使用AVPlayer 等等 去实现在线播放,也是可以的,但是如果要实现更多更能,还是别折腾这玩意,浪费生命. 

时间: 2024-09-08 15:22:48

iOS 关于音频开发的相关文章

《iOS 6高级开发手册(第4版)》——2.8节秘诀:声明文档支持

2.8 秘诀:声明文档支持 iOS 6高级开发手册(第4版) 应用程序文档并不仅限于它们创建或者从Internet下载的文件.如你在前一个秘诀中所发现的,应用程序可能处理某些文件类型.它们可能打开从其他应用程序传递过来的项目.你已经从发送方的角度见过了文档共享,它使用"open in"(打开在)控制器把文件导出到其他应用程序.现在应该从接收方的角度探讨它. 应用程序在它们的Info.plist属性列表中声明它们对某些文件类型的支持.Launch Services(启动服务)系统将读取该

《iOS 8应用开发入门经典(第6版)》——第1章,第1.1节欢迎进入iOS平台

1.1 欢迎进入iOS平台 iOS 8应用开发入门经典(第6版) 您阅读本书说明您可能有iOS设备,这意味着您知道如何使用其界面:清晰的图形.响应迅速.多点触摸和数以十万计的应用程序,这只是冰山一角.然而,作为开发人员,您需要习惯应对一个迫使您以不同方式思考的平台. 1.1.1 iOS设备 当前,iOS平台家族成员包括iPhone.iPad.iPod Touch和Apple TV,但Apple TV还未对第三方开发开放.在阅读本书时您将发现,很多屏幕截图都基于以iPhone(具体地说是iPhon

《iOS 9应用开发入门经典(第7版)》——第1章,第1.1节欢迎进入iOS平台

第1章 为开发准备好系统和iOS设备iOS 9应用开发入门经典(第7版)本章将介绍:您面临的iOS硬件局限性:到哪里获取iOS开发工具:如何加入iOS开发人员计划(Developer Program):创建并使用供应配置文件(provisioning profile):iOS开发技术概述.iOS设备向开发人员展示了一个全新的世界--多点触摸界面.可始终在线.视频以及众多内置的传感器,这些传感器可用于创建从游戏到提高生产率的应用程序等各种软件.信不信由您,作为新开发人员,您有一个优势:您是白纸一张

iOS的socket开发基础

iOS的socket开发基础 首先让我们通过一张图知道socket在哪里? Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口. TCP和UDP的区别 TCP:面向连接.传输可靠(保证数据正确性.保证数据顺序).用于传输大量数据(流模式).速度慢,建立连接需要开销较多(时间,系统资源). UDP:面向非连接.传输不可靠.用于传输少量数据(数据包模式).速度快. 关于TCP是一种流模式的协议,UDP是一种数据报模式的协议,这里要说明一下,TCP是面向连接的,也就是说,在连接

iOS硬件协议开发的相关问题

问题描述 iOS硬件协议开发的相关问题 最近公司有个项目做的事智能硬件,socket连接.如图,这是一部分的协议.目前我想问一下这种协议我该怎么开发?感觉处理起来好棘手,因为以前做项目都是基于http的返回的数据都是json格式.现在server端给我返回的是16进制的字符串,对照协议我也能知道哪个数据代表什么意思,就是不知道怎么用代码来处理这串16进制字符.求救,在线等... 解决方案 解决方案二: IOS---文件路径相关问题

《iOS 6核心开发手册(第4版)》——2.12节构建触摸式转盘

2.12 构建触摸式转盘 iOS 6核心开发手册(第4版) 下一个秘诀是创建一个触摸式转盘,就像老款的iPod上使用的触摸式转盘一样.触摸式转盘提供了无限的可滚动输入.用户可以顺时针或者逆时针旋转他们的手指,并且对象的值将相应地增加或减小.每转一圈,转盘(即转动360°)对应于值改变1.0.顺时针的改变为正,逆时针的改变则为负.每次触摸的值会累加起来,也可以对它进行复位(只需把控件的value属性重新设置为0.0即可).这个属性不是UIControl实例的一个标准部分,即使许多控件都会使用该值.

《iOS 6核心开发手册(第4版)》——1.6节秘诀:测试触摸

1.6 秘诀:测试触摸 iOS 6核心开发手册(第4版) 屏幕上用于直接操作界面的大多数视图元素都不是矩形.这使触摸检测变得复杂,因为实际的视图矩形的某些部分可能不对应于实际的触摸点.图1-2显示了实际发生的问题.右边的截屏图显示了界面及其基于触摸的子视图,左边的截屏图则显示了每个子视图的实际视图界限.每个屏幕上的圆形周围的淡灰色区域都落在界限内,但是对这些区域的触摸应该不会"碰到"正在处理的视图. iOS会在整个视图框架内感知用户点按.这包括未绘图的区域(比如图1-2中的实际圆形外面

《iOS 6核心开发手册(第4版)》——1.14节秘诀:实时触摸反馈

1.14 秘诀:实时触摸反馈 iOS 6核心开发手册(第4版) 你曾经需要录制iOS应用程序的演示吗?这总会涉及折中.可以使用架空相机并与影子作斗争,另外用户的手可能会挡住屏幕,或者可以使用像Reflection(http://reflectionapp.com)这样的工具,但是只能看到直接出现在iOS设备屏幕上的内容.这些应用程序录制缺少关于用户触摸和视觉焦点的任何指示. 秘诀1-13提供了一组简单的类(称为TOUCHkit),它们提供了实时的触摸反馈层级,可供演示使用.利用它,可以同时查看正

《iOS 6核心开发手册(第4版)》——1.1节触摸

1.1 触摸 iOS 6核心开发手册(第4版) Cocoa Touch以可能最简单的方式实现直接操作.它把触摸事件发送给正在处理的视图.作为一名iOS开发人员,你将告诉视图如何做出响应.在深入研究姿势和姿势识别器之前,应该在这种底层触摸技术上打下坚实的基础.它提供了所有基于触摸的交互的必要组件. 每个触摸都会传达信息:触摸发生的位置(当前和以前的位置).使用的是触摸的哪个阶段(在桌面应用程序中实质上是鼠标按下.鼠标移动和鼠标抬起,在直接操作世界中对应于手指或触摸按下.移动和抬起).点按计数(例如