一篇文章讲明白iOS开发系列

简介: 一篇文章讲明白iOS开发系列

--iOS多媒体

概览

音频 音效 音乐 音频会话 录音 音频队列服务 视频 MPMoviePlayerController MPMoviePlayerViewController AVPlayer 摄像头 UIImagePickerController拍照和视频录制 AVFoundation拍照和录制视频 总结 音频

在iOS中音频播放从形式上可以分为音效播放和音乐播放。前者主要指的是一些短音频播放,通常作为点缀音频,对于这类音频不需要进行进度、循环等控制。后者指的是一些较长的音频,通常是主音频,对于这些音频的播放通常需要进行精确的控制。在iOS中播放两类音频分别使用AudioToolbox.framework和AVFoundation.framework来完成音效和音乐播放。

音效

AudioToolbox.framework是一套基于C语言的框架,使用它来播放音效其本质是将短音频注册到系统声音服务(System Sound Service)。System Sound Service是一种简单、底层的声音播放服务,但是它本身也存在着一些限制:

音频播放时间不能超过30s 数据必须是PCM或者IMA4格式 音频文件必须打包成.caf、.aif、.wav中的一种(注意这是官方文档的说法,实际测试发现一些.mp3也可以播放)

使用System Sound Service 播放音效的步骤如下:

调用AudioServicesCreateSystemSoundID( CFURLRef inFileURL, SystemSoundID outSystemSoundID)函数获得系统声音ID。 如果需要监听播放完成操作,则使用AudioServicesAddSystemSoundCompletion( SystemSoundID inSystemSoundID,

CFRunLoopRef inRunLoop, CFStringRef inRunLoopMode, AudioServicesSystemSoundCompletionProc inCompletionRoutine, void inClientData)方法注册回调函数。 调用AudioServicesPlaySystemSound(SystemSoundID inSystemSoundID) 或者AudioServicesPlayAlertSound(SystemSoundID inSystemSoundID) 方法播放音效(后者带有震动效果)。

下面是一个简单的示例程序:

//

// KCMainViewController.m

// Audio

//

// Created by Kenshin Cui on 14/03/30.

// Copyright (c) 2014年 cmjstudio. All rights reserved.

// //代码效果参考:http://www.zidongmutanji.com/zsjx/373379.html

音效播放

#import "KCMainViewController.h"

#import

@interface KCMainViewController ()

@end

@implementation KCMainViewController

- (void)viewDidLoad {

【super viewDidLoad】;

【self playSoundEffect:@"videoRing.caf"】;

}

/

播放完成回调函数

@param soundID 系统声音ID

@param clientData 回调时传递的数据

/

void soundCompleteCallback(SystemSoundID soundID,void clientData){

NSLog(@"播放完成...");

}

/

播放音效文件

@param name 音频文件名称

/

-(void)playSoundEffect:(NSString )name{

NSString audioFile=【【NSBundle mainBundle】 pathForResource:name ofType:nil】;

NSURL fileUrl=【NSURL fileURLWithPath:audioFile】;

//1.获得系统声音ID

SystemSoundID soundID=0;

/**

inFileUrl:音频文件url

outSystemSoundID:声音id(此函数会将音效文件加入到系统音频服务中并返回一个长整形ID)

/

AudioServicesCreateSystemSoundID((__bridge //代码效果参考:http://www.zidongmutanji.com/bxxx/453614.html

CFURLRef)(fileUrl), soundID);

//如果需要在播放完之后执行某些操作,可以调用如下方法注册一个播放完成回调函数

AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, soundCompleteCallback, NULL);

//2.播放音频

AudioServicesPlaySystemSound(soundID);//播放音效

// AudioServicesPlayAlertSound(soundID);//播放音效并震动

}

@end

音乐

如果播放较大的音频或者要对音频有精确的控制则System Sound Service可能就很难满足实际需求了,通常这种情况会选择使用AVFoundation.framework中的AVAudioPlayer来实现。AVAudioPlayer可以看成一个播放器,它支持多种音频格式,而且能够进行进度、音量、播放速度等控制。首先简单看一下AVAudioPlayer常用的属性和方法:

属性

说明

@property(readonly, getter=isPlaying) BOOL playing

是否正在播放,只读

@property(readonly) NSUInteger numberOfChannels

音频声道数,只读

@property(readonly) NSTimeInterval duration

音频时长

@property(readonly) NSURL url

音频文件路径,只读

@property(readonly) NSData data

音频数据,只读

@property float pan

立体声平衡,如果为-1.0则完全左声道,如果0.0则左右声道平衡,如果为1.0则完全为右声道//代码效果参考:http://www.zidongmutanji.com/zsjx/536747.html

@property float volume

音量大小,范围0-1.0

@property BOOL enableRate

是否允许改变播放速率

@property float rate

播放速率,范围0.5-2.0,如果为1.0则正常播放,如果要修改播放速率则必须设置enableRate为YES

@property NSTimeInterval currentTime

当前播放时长

@property(readonly) NSTimeInterval deviceCurrentTime

输出设备播放音频的时间,注意如果播放中被暂停此时间也会继续累加

@property NSInteger numberOfLoops

循环播放次数,如果为0则不循环,如果小于0则无限循环,大于0则表示循环次数

@property(readonly) NSDictionary settings

音频播放设置信息,只读

@property(getter=isMeteringEnabled) BOOL meteringEnabled

是否启用音频测量,默认为NO,一旦启用音频测量可以通过updateMeters方法更新测量值

对象方法

说明

- (instancetype)initWithContentsOfURL:(NSURL )url error:(NSError )outError

使用文件URL初始化播放器,注意这个URL不能是HTTP URL,AVAudioPlayer不支持加载网络媒体流,只能播放本地文件

- (instancetype)initWithData:(NSData *)data error:(NSError )outError

使用NSData初始化播放器,注意使用此方法时必须文件格式和文件后缀一致,否则出错,所以相比此方法更推荐使用上述方法或- (instancetype)initWithData:(NSData )data fileTypeHint:(NSString )utiString error:(NSError )outError方法进行初始化

- (BOOL)prepareToPlay;

加载音频文件到缓冲区,注意即使在播放之前音频文件没有加载到缓冲区程序也会隐式调用此方法。

- (BOOL)play;

播放音频文件

- (BOOL)playAtTime:(NSTimeInterval)time

在指定的时间开始播放音频

- (void)pause;

暂停播放

- (void)stop;

停止播放

- (void)updateMeters

更新音频测量值,注意如果要更新音频测量值必须设置meteringEnabled为YES,通过音频测量值可以即时获得音频分贝等信息

- (float)peakPowerForChannel:(NSUInteger)channelNumber;

获得指定声道的分贝峰值,注意如果要获得分贝峰值必须在此之前调用updateMeters方法

- (float)averagePowerForChannel:(NSUInteger)channelNumber

获得指定声道的分贝平均值,注意如果要获得分贝平均值必须在此之前调用updateMeters方法

@property(nonatomic, copy) NSArray channelAssignments

获得或设置播放声道

代理方法

说明

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer )player successfully:(BOOL)flag

音频播放完成

- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer )player error:(NSError )error

音频解码发生错误

AVAudioPlayer的使用比较简单:

初始化AVAudioPlayer对象,此时通常指定本地文件路径。

设置播放器属性,例如重复次数、音量大小等。

调用play方法播放。

下面就使用AVAudioPlayer实现一个简单播放器,在这个播放器中实现了播放、暂停、显示播放进度功能,当然例如调节音量、设置循环模式、甚至是声波图像(通过分析音频分贝值)等功能都可以实现,这里就不再一一演示。界面效果如下:

当然由于AVAudioPlayer一次只能播放一个音频文件,所有上一曲、下一曲其实可以通过创建多个播放器对象来完成,这里暂不实现。播放进度的实现主要依靠一个定时器实时计算当前播放时长和音频总时长的比例,另外为了演示委托方法,下面的代码中也实现了播放完成委托方法,通常如果有下一曲功能的话播放完可以触发下一曲音乐播放。下面是主要代码:

//

// ViewController.m

// KCAVAudioPlayer

//

// Created by Kenshin Cui on 14/03/30.

// Copyright (c) 2014年 cmjstudio. All rights reserved.

//

#import "ViewController.h"

#import

#define kMusicFile @"刘若英 - 原来你也在这里.mp3"

#define kMusicSinger @"刘若英"

#define kMusicTitle @"原来你也在这里"

@interface ViewController ()

@property (nonatomic,strong) AVAudioPlayer audioPlayer;//播放器

@property (weak, nonatomic) IBOutlet UILabel controlPanel; //控制面板

@property (weak, nonatomic) IBOutlet UIProgressView playProgress;//播放进度

@property (weak, nonatomic) IBOutlet UILabel musicSinger; //演唱者

@property (weak, nonatomic) IBOutlet UIButton playOrPause; //播放/暂停按钮(如果tag为0认为是暂停状态,1是播放状态)

@property (weak ,nonatomic) NSTimer timer;//进度更新定时器

@end

@implementation ViewController

- (void)viewDidLoad {

【super viewDidLoad】;

【self setupUI】;

}

/

初始化UI

/

-(void)setupUI{

self.title=kMusicTitle;

self.musicSinger.text=kMusicSinger;

}

-(NSTimer )timer{

if (!_timer) {

_timer=【NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(updateProgress) userInfo:nil repeats:true】;

}

return _timer;

}

/**

创建播放器

@return 音频播放器

/

-(AVAudioPlayer )audioPlayer{

if (!_audioPlayer) {

NSString urlStr=【【NSBundle mainBundle】pathForResource:kMusicFile ofType:nil】;

NSURL url=【NSURL fileURLWithPath:urlStr】;

NSError error=nil;

//初始化播放器,注意这里的Url参数只能时文件路径,不支持HTTP Url

_audioPlayer=【【AVAudioPlayer alloc】initWithContentsOfURL:url error:error】;

//设置播放器属性

_audioPlayer.numberOfLoops=0;//设置为0不循环

_audioPlayer.delegate=self;

【_audioPlayer prepareToPlay】;//加载音频文件到缓存

if(error){

NSLog(@"初始化播放器过程发生错误,错误信息:%@",error.localizedDescription);

return nil;

}

}

return _audioPlayer;

}

/**

播放音频

/

-(void)play{

if (!【self.audioPlayer isPlaying】) {

【self.audioPlayer play】;

self.timer.fireDate=【NSDate distantPast】;//恢复定时器

}

}

/**

暂停播放

/

-(void)pause{

if (【self.audioPlayer isPlaying】) {

【self.audioPlayer pause】;

self.timer.fireDate=【NSDate distantFuture】;//暂停定时器,注意不能调用invalidate方法,此方法会取消,之后无法恢复

}

}

/**

点击播放/暂停按钮

@param sender 播放/暂停按钮

/

- (IBAction)playClick:(UIButton )sender {

if(sender.tag){

sender.tag=0;

【sender setImage:【UIImage imageNamed:@"playing_btn_play_n"】 forState:UIControlStateNormal】;

【sender setImage:【UIImage imageNamed:@"playing_btn_play_h"】 forState:UIControlStateHighlighted】;

【self pause】;

}else{

sender.tag=1;

【sender setImage:【UIImage imageNamed:@"playing_btn_pause_n"】 forState:UIControlStateNormal】;

【sender setImage:【UIImage imageNamed:@"playing_btn_pause_h"】 forState:UIControlStateHighlighted】;

【self play】;

}

}

/*

更新播放进度

/

-(void)updateProgress{

float progress= self.audioPlayer.currentTime /self.audioPlayer.duration;

【self.playProgress setProgress:progress animated:true】;

}

#pragma mark - 播放器代理方法

-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer )player successfully:(BOOL)flag{

NSLog(@"音乐播放完成...");

}

@end运行效果:

音频会话

事实上上面的播放器还存在一些问题,例如通常我们看到的播放器即使退出到后台也是可以播放的,而这个播放器如果退出到后台它会自动暂停。如果要支持后台播放需要做下面几件事情:

1.设置后台运行模式:在plist文件中添加Required background modes,并且设置item 0=App plays audio or streams audio/video using AirPlay(其实可以直接通过Xcode在Project Targets-Capabilities-Background Modes中设置)

2.设置AVAudioSession的类型为AVAudioSessionCategoryPlayback并且调用setActive::方法启动会话。

AVAudioSession audioSession=【AVAudioSession sharedInstance】;

【audioSession setCategory:AVAudioSessionCategoryPlayback error:nil】;

【audioSession setActive:YES error:nil】;

3.为了能够让应用退到后台之后支持耳机控制,建议添加远程控制事件(这一步不是后台播放必须的)

前两步是后台播放所必须设置的,第三步主要用于接收远程事件,这部分内容之前的文章中有详细介绍,如果这一步不设置虽让也能够在后台播放,但是无法获得音频控制权(如果在使用当前应用之前使用其他播放器播放音乐的话,此时如果按耳机播放键或者控制中心的播放按钮则会播放前一个应用的音频),并且不能使用耳机进行音频控制。第一步操作相信大家都很容易理解,如果应用程序要允许运行到后台必须设置,正常情况下应用如果进入后台会被挂起,通过该设置可以上应用程序继续在后台运行。但是第二步使用的AVAudioSession有必要进行一下详细的说明。

在iOS中每个应用都有一个音频会话,这个会话就通过AVAudioSession来表示。AVAudioSession同样存在于AVFoundation框架中,它是单例模式设计,通过sharedInstance进行访问。在使用Apple设备时大家会发现有些应用只要打开其他音频播放就会终止,而有些应用却可以和其他应用同时播放,在多种音频环境中如何去控制播放的方式就是通过音频会话来完成的。下面是音频会话的几种会话模式:

会话类型

说明

是否要求输入

是否要求输出

是否遵从静音键

AVAudioSessionCategoryAmbient

混音播放,可以与其他音频应用同时播放

AVAudioSessionCategorySoloAmbient

独占播放

AVAudioSessionCategoryPlayback

后台播放,也是独占的

AVAudioSessionCategoryRecord

录音模式,用于录音时使用

AVAudioSessionCategoryPlayAndRecord

播放和录音,此时可以录音也可以播放

AVAudioSessionCategoryAudioProcessing

硬件解码音频,此时不能播放和录制

AVAudioSessionCategoryMultiRoute

多种输入输出,例如可以耳机、USB设备同时播放

注意:是否遵循静音键表示在播放过程中如果用户通过硬件设置为静音是否能关闭声音。

根据前面对音频会话的理解,相信大家开发出能够在后台播放的音频播放器并不难,但是注意一下,在前面的代码中也提到设置完音频会话类型之后需要调用setActive::方法将会话激活才能起作用。类似的,如果一个应用已经在播放音频,打开我们的应用之后设置了在后台播放的会话类型,此时其他应用的音频会停止而播放我们的音频,如果希望我们的程序音频播放完之后(关闭或退出到后台之后)能够继续播放其他应用的音频的话则可以调用setActive::方法关闭会话。代码如下:

//

// ViewController.m

// KCAVAudioPlayer

//

// Created by Kenshin Cui on 14/03/30.

// Copyright (c) 2014年 cmjstudio. All rights reserved.

// AVAudioSession 音频会话

#import "ViewController.h"

#import

#define kMusicFile @"刘若英 - 原来你也在这里.mp3"

#define kMusicSinger @"刘若英"

#define kMusicTitle @"原来你也在这里"

@interface ViewController ()

@property (nonatomic,strong) AVAudioPlayer audioPlayer;//播放器

@property (weak, nonatomic) IBOutlet UILabel controlPanel; //控制面板

@property (weak, nonatomic) IBOutlet UIProgressView playProgress;//播放进度

@property (weak, nonatomic) IBOutlet UILabel musicSinger; //演唱者

@property (weak, nonatomic) IBOutlet UIButton playOrPause; //播放/暂停按钮(如果tag为0认为是暂停状态,1是播放状态)

<span style="background: rgba(255, 255, 25

相关文章
|
2天前
|
开发框架 数据可视化 Java
iOS开发-SwiftUI简介
iOS开发-SwiftUI简介
|
10天前
|
IDE 开发工具 Android开发
安卓与iOS开发对比:平台选择对项目成功的影响
【9月更文挑战第10天】在移动应用开发的世界中,选择正确的平台是至关重要的。本文将深入探讨安卓和iOS这两大主要移动操作系统的开发环境,通过比较它们的市场份额、开发工具、编程语言和用户群体等方面,为开发者提供一个清晰的指南。我们将分析这两个平台的优势和劣势,并讨论如何根据项目需求和目标受众来做出最佳选择。无论你是初学者还是有经验的开发者,这篇文章都将帮助你更好地理解每个平台的特性,并指导你做出明智的决策。
|
8天前
|
API Android开发 iOS开发
安卓与iOS开发中的线程管理对比
【9月更文挑战第12天】在移动应用的世界中,安卓和iOS平台各自拥有庞大的用户群体。开发者们在这两个平台上构建应用时,线程管理是他们必须面对的关键挑战之一。本文将深入探讨两大平台在线程管理方面的异同,通过直观的代码示例,揭示它们各自的设计理念和实现方式,帮助读者更好地理解如何在安卓与iOS开发中高效地处理多线程任务。
|
10天前
|
开发框架 Android开发 iOS开发
探索安卓与iOS开发的差异:构建未来应用的指南
在移动应用开发的广阔天地中,安卓与iOS两大平台各占半壁江山。本文将深入浅出地对比这两大操作系统的开发环境、工具和用户体验设计,揭示它们在编程语言、开发工具以及市场定位上的根本差异。我们将从开发者的视角出发,逐步剖析如何根据项目需求和目标受众选择适合的平台,同时探讨跨平台开发框架的利与弊,为那些立志于打造下一个热门应用的开发者提供一份实用的指南。
27 5
|
10天前
|
开发工具 Android开发 iOS开发
安卓与iOS开发:平台选择的艺术与科学
在移动应用开发的广阔天地中,安卓与iOS两大平台如同东西方哲学的碰撞,既有共通之处又各具特色。本文将深入探讨这两个平台的设计理念、开发工具和市场定位,旨在为开发者提供一份简明扼要的指南,帮助他们在这场技术与商业的博弈中找到自己的道路。通过比较分析,我们将揭示每个平台的优势与局限,以及它们如何影响应用的性能、用户体验和市场接受度。无论你是初涉江湖的新手,还是经验丰富的老手,这篇文章都将为你的选择提供新的视角和思考。
26 5
|
10天前
|
开发工具 Android开发 Swift
探索安卓与iOS开发的差异:从新手到专家的旅程
在数字时代的浪潮中,移动应用开发已成为连接世界的桥梁。本文将深入探讨安卓与iOS这两大主流平台的开发差异,带领读者从零基础出发,逐步了解各自的特点、开发环境、编程语言及市场策略。无论你是梦想成为移动应用开发者的初学者,还是希望扩展技能边界的资深开发者,这篇文章都将为你提供宝贵的见解和实用的建议。
|
11天前
|
人工智能 Android开发 iOS开发
安卓与iOS开发:平台选择的艺术
在移动应用开发的广阔天地里,安卓和iOS两大操作系统各占半壁江山。本文将深入探讨这两个平台的开发环境、工具及市场趋势,帮助开发者在选择适合自己项目的平台时做出更明智的决策。通过比较各自的优势与局限,我们不仅能更好地理解每个系统的核心特性,还能洞察未来技术发展的脉络。无论你是刚入行的新手还是资深开发者,这篇文章都将为你提供有价值的参考和启示。
24 5
|
11天前
|
开发工具 Android开发 iOS开发
安卓与iOS开发:一场操作系统的较量
在数字时代的浪潮中,安卓和iOS这两大操作系统如同海上的两艘巨轮,各自承载着不同的使命与梦想。本文将深入浅出地探讨这两个系统在开发领域的异同,从用户体验、开发工具、市场趋势等多个维度进行比较分析。通过这场技术的较量,我们可以更好地理解每个系统的优势与局限,以及它们如何影响我们的日常生活和工作。
|
10天前
|
Linux Android开发 iOS开发
探索Android与iOS开发:平台之战还是互补共生?
在移动应用开发的浩瀚宇宙中,Android和iOS这两大星系始终吸引着无数开发者的目光。它们各自拥有独特的引力场,引领着技术潮流的方向。本文将穿梭于这两个平台的星际空间,揭示它们背后的力量对比,以及如何在这两者之间找到平衡点,共同推动移动应用开发的进步。
20 1
|
10天前
|
移动开发 开发框架 Android开发
安卓与iOS开发:平台之战的新篇章
在移动应用开发的广阔天地中,安卓和iOS始终占据着主导地位。本文通过比较这两个平台的发展历程、技术特点及未来趋势,探讨了它们之间的竞争与合作。文章旨在为开发者提供一个清晰的平台选择指南,并预测未来移动开发的可能走向。
18 1