IOS:音频播放

  

在 iPhone 应用或者是游戏的开发过程中,对声音的支持是必不可少的。在我做过的几个应用中,每个都涉及到音效,所以在这里做个简单的归纳,很多都是引用自《iPhone Application Programming Guide》(需要有 Apple ID 才能打开链接),加了一些实际使用的经验。
iPhone OS 主要提供以下了几种播放音频的方法:
System Sound Services
AVAudioPlayer 类
Audio Queue Services
OpenAL

1. System Sound Services 是最底层也是最简单的声音播放服务
调用 AudioServicesPlaySystemSound 这个方法就可以播放一些简单的音频文件,使用此方法只适合播放一些很小的提示或者警告音,因为它有很多限制:
■ 声音长度要小于 30 秒
■ In linear PCM 或者 IMA4 (IMA/ADPCM) 格式的
■ 打包成 .caf, .aif, 或者 .wav 的文件
■ 不能控制播放的进度
■ 调用方法后立即播放声音
■ 没有循环播放和立体声控制
另外,它还可以调用系统的震动功能,方法也很简单。具体的代码可以参考官方的示例  SysSound
,但是官方的示例只有一些简单的用法,从文档中我们发现可以通过 AudioServicesAddSystemSoundCompletion 方法为音频播放添加 CallBack 函数,有了 CallBack 函数我们可以解决不少问题,比如可以克服 System Sound Services 本身不支持循环播放的问题。以下代码可以实现一个在程序中循环播放的背景音乐:

1、首先在工程中导入AudioToolbox.Framework,并将要用到的名字为han。wav的音频文件导入项目里
2、在viewDidLoad方法里用代码声称按钮,按钮关联的方法:

- (void)buttonPress:(id)sender

3、按钮关联的方法实现

// 自定义的c函数,用于清理音频对象

static void onSystemSoundCompletionCallBack(SystemSoundID ssID ,void *clientData)

{

    // 丢弃

    AudioServicesDisposeSystemSoundID(ssID);

}


-(void)buttonPress:(id)sender

{

    //获取声音

    NSString *path = [[NSBundle mainBundle]pathForResource:@"han"ofType:@"wav"];

    NSURL *url = [NSURL fileURLWithPath:path];

    // 获取系统声音的id

    SystemSoundID ssID = 0;

    //将指定的文件创建为系统声音

    AudioServicesCreateSystemSoundID((CFURLRef)url, &ssID);

    //注册回调函数,播放完后清理音频对象

    AudioServicesAddSystemSoundCompletion(ssID,NULL,NULL, onSystemSoundCompletionCallBack, (void *)self);

    // 播放

    AudioServicesPlaySystemSound(ssID);

}

4、运行,点击按钮,会播放声音

  2. AVAudioPlayer 类

AVAudioPlayer 是 AVFoundation.framework 中定义的一个类,所以使用要先在工程中引入 AVFoundation.framework。我们可以把 AVAudioPlayer 看作是一个高级的播放器,它支持广泛的音频格式,主要是以下这些格式:
■ AAC
■ AMR(AdaptiveMulti-Rate, aformatforspeech)
■ ALAC(AppleLossless)
■ iLBC(internetLowBitrateCodec, anotherformatforspeech)
■ IMA4(IMA/ADPCM)
■ linearPCM(uncompressed)
■ μ-lawanda-law
■ MP3(MPEG-1audiolayer3 
AVAudioPlayer 可以播放任意长度的音频文件、支持循环播放、可以同步播放多个音频文件、控制播放进度以及从音频文件的任意一点开始播放等,更高级的功能可以参考 AVAudioPlayer 的文档。要使用 AVAudioPlayer 的对象播放文件,你只需为其指定一个音频文件并设定一个实现了 AVAudioPlayerDelegate 协议的 delegate 对象。这里创建一个类似音乐播放器的界面,可以实现暂停/播放、快进/快退等功能。
虽然 AVAudioPlayer 可以播放很多格式,但是我们在实际开发过程中还是最好使用一些没有压缩的格式,比如 WAVE 文件,这样可以减少系统处理单元的资源占用,以便更好的完成程序的其他功能。另外,在使用 AVAudioPlayer 连续播放 mp3 这类经过压缩的音频文件时,在连接处可能出现一定的间隔时间。

代码实现:
1、创建单视图工程。要先在工程中引入 AVFoundation.framework。并把用到的音频导入工程
2、给视图加上导航栏,将导航栏设为窗口的根视图。在QQViewController.h里代码:

#import <UIKit/UIKit.h>


@interface QQViewController :UIViewController<UITableViewDataSource,UITableViewDelegate>


@property(retain,nonatomic)NSArray *arr;


@end

在.m文件里代码:

#import "QQViewController.h"

#import "QQAAudioPlayerViewController.h"

@interface QQViewController ()


@end


@implementation QQViewController


- (void)dealloc

{

    [_arrrelease];

    [superdealloc];

}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

{

   self = [superinitWithNibName:nibNameOrNilbundle:nibBundleOrNil];

   if (self) {

        self.navigationItem.title =@"音乐列表";

        // Custom initialization

    }

    return self;

}


- (void)viewDidLoad

{

    [superviewDidLoad];

    UITableView *myTableView = [[UITableViewalloc]initWithFrame:self.view.framestyle:UITableViewStylePlain];

    myTableView.delegate =self;

    myTableView.dataSource =self;

    myTableView.separatorStyle =UITableViewCellSelectionStyleBlue;

    [self.viewaddSubview:myTableView];

    [myTableViewrelease];

    

    self.arr = [NSArrayarrayWithObjects:@"123",@"hinder",@"test",@"The Sound Of Slience",nil];

    

}

#pragma =================UITableView  DataSource=================

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

{

    return self.arr.count;

}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

   staticNSString *str =@"identify";

    UITableViewCell *pCell = [tableViewdequeueReusableCellWithIdentifier:str];

   if(pCell ==nil)

    {

        pCell = [[UITableViewCellalloc]initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:str];

    }

    pCell.textLabel.text = [self.arrobjectAtIndex:[indexPathrow]];

    pCell.detailTextLabel.text =@"music";

   return pCell;

}

#pragma tableview Delegate=============================

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{

    QQAAudioPlayerViewController *pAudio = [[QQAAudioPlayerViewControlleralloc]init];

    [self.navigationControllerpushViewController:pAudioanimated:YES];

}


在新添的类 QQAAudioPlayerViewController.h里,代码:

//音乐播放器

@property (nonatomic,retain)AVAudioPlayer *audioPlayer;

//选中音乐的名称

@property (nonatomic,retain)NSString *selectMusicName;


//播放状态

@property (nonatomic,assign)BOOL isPlayState;


//更新时间标签和进度指示器

@property (nonatomic,retain)NSTimer *timer;


//播放按钮事件

-(void)playAndPauseBtnPress:(id)sender;

//播放音乐

-(void)playMusic;

//暂停音乐

-(void)pauseMusic;

//将时间拆分的方法

-(NSString *)formateTime:(NSTimeInterval)_time;

//更新时间标签和进度指示器方法

-(void)updateMeters;

//播放进度指示器改变后触发方法

-(void)progressChange:(id)sender;

//播放进度指示器会改变完成后触发方法

-(void)progressDidChanged:(id)sender;

//音量调节器改变处罚方法

-(void)volumeChange:(id)sender;


在.m文件里代码:

#import "QQAAudioPlayerViewController.h"

enum{

    BUTTON_TAG =1,

    LABEL1_TAG,

    LABEL2_TAG,

    SLI_VOICE_TAG,

    SLI_SONG_TAG,

};

@interface QQAAudioPlayerViewController ()


@end


@implementation QQAAudioPlayerViewController

- (void)dealloc

{

    [_audioPlayer release];

    [_selectMusicNamerelease];

    [_timerrelease];

    [superdealloc];

}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

{

   self = [superinitWithNibName:nibNameOrNilbundle:nibBundleOrNil];

   if (self) {

        self.navigationItem.title =@"正在播放";

        

        

        // Custom initialization

    }

    return self;

}

- (void)viewWillAppear:(BOOL)animated

{

    NSString *path = [[NSBundlemainBundle]pathForResource:self.selectMusicNameofType:@"mp3"];

   NSURL *url = [NSURLfileURLWithPath:path];

    self.audioPlayer = [[AVAudioPlayeralloc]initWithContentsOfURL:urlerror:nil];

    self.audioPlayer.delegate =self;

    self.audioPlayer.meteringEnabled =YES;

    [self.audioPlayerplay];

    

    self.isPlayeState =NO;

}


- (void)viewWillDisappear:(BOOL)animated

{

    [self.audioPlayerstop];

    [self.audioPlayerrelease];

    self.audioPlayer =nil;

}

- (void)viewDidLoad

{

    [superviewDidLoad];

    self.title =self.selectMusicName;

    //创建play/pause按钮

    UIButton *audioButton = [UIButtonbuttonWithType:UIButtonTypeRoundedRect];

    audioButton.frame =CGRectMake(120,80,80, 40);

    audioButton.tag =BUTTON_TAG;

    [audioButton setTitle:@"play"forState:UIControlStateNormal];

    [audioButton addTarget:selfaction:@selector(playAndPauseBtnPress:)forControlEvents:UIControlEventTouchUpInside];

    [self.viewaddSubview:audioButton];

    //创建播放时间按钮

   UILabel *label = [[UILabelalloc]initWithFrame:CGRectMake(100,160,120, 30)];

    label.tag =LABEL1_TAG;

    label.text =@"00:00 of 00:00";

    [self.viewaddSubview: label];

    [labelrelease];

    //创建音量进度条

   UISlider *voiceSlider = [[UISlideralloc]initWithFrame:CGRectMake(100,220,200, 20)];

    voiceSlider.tag =SLI_VOICE_TAG;

    [self.viewaddSubview:voiceSlider];

    [voiceSliderrelease];

    [voiceSlider addTarget:selfaction:@selector(volumeChange:)forControlEvents:UIControlEventValueChanged];

    //创建音量标签

   UILabel *voiceLabel = [[UILabelalloc]initWithFrame:CGRectMake(10,220,85, 20)];

    voiceLabel.text =@"音量";

    [self.viewaddSubview:voiceLabel];

    [voiceLabelrelease];

    //创建播放进度条

   UISlider *songSider = [[UISlideralloc]initWithFrame:CGRectMake(100,280,210, 20)];

    songSider.thumbTintColor = [UIColorgreenColor];

    songSider.tintColor = [UIColorredColor];

    [songSider setThumbImage:[UIImageimageNamed:@""]forState:UIControlStateNormal];

    songSider.tag =SLI_SONG_TAG;

    [self.viewaddSubview:songSider];

    [songSiderrelease];

    [songSider addTarget:selfaction:@selector(progressChange:)forControlEvents:UIControlEventValueChanged];

    [songSider addTarget:selfaction:@selector(progressDidChang:)forControlEvents:UIControlEventValueChanged];

    //创建播放标签

   UILabel *songLabel = [[UILabelalloc]initWithFrame:CGRectMake(10,280,85, 20)];

    songLabel.text =@"播放进度";

    [self.viewaddSubview:songLabel];

    [songLabelrelease];

    

// Do any additional setup after loading the view.

}

//播放/暂停按钮关联方法

- (void)playAndPauseBtnPress:(id)sender

{

   UIButton *pBtn = (UIButton *)[self.viewviewWithTag:BUTTON_TAG];

    self.isPlayeState = !self.isPlayeState;

    if(self.isPlayeState)

    {

        [pBtn setTitle:@"pause"forState:UIControlStateNormal];

        [selfplayeMusic];

    }

   else

    {

        [pBtn setTitle:@"play"forState:UIControlStateNormal];

        [selfpauseMusic];

    }

}

//播放状态关联的方法

- (void)playeMusic

{

    [self.audioPlayerplay];

    

   UISlider *voice = (UISlider *)[self.viewviewWithTag:SLI_VOICE_TAG];

   UISlider *song = (UISlider *)[self.viewviewWithTag:SLI_SONG_TAG];

   UILabel *timeLabel = (UILabel *)[self.viewviewWithTag:LABEL1_TAG];

    

    [timeLabelsetEnabled:YES];

    voice.enabled =YES;

    song.enabled =YES;

    

    voice.value =self.audioPlayer.volume;

    

    self.timer = [NSTimerscheduledTimerWithTimeInterval:0.1ftarget:selfselector:@selector(updateMeters)userInfo:Nilrepeats:YES];

    

}

//暂停按钮关联的方法

- (void)pauseMusic

{

    [self.audioPlayerpause];

    

   UISlider *voice = (UISlider *)[self.viewviewWithTag:SLI_VOICE_TAG];

   UISlider *song = (UISlider *)[self.viewviewWithTag:SLI_SONG_TAG];

    

    [self.timerinvalidate];

    

    voice.enabled =NO;

    song.enabled =NO;

    

}


- (void)updateMeters

{

    [self.audioPlayerupdateMeters];

    

   UISlider *song = (UISlider *)[self.viewviewWithTag:SLI_SONG_TAG];

    song.value = self.audioPlayer.currentTime/self.audioPlayer.duration;

    

   UILabel *timerLbel = (UILabel *)[self.viewviewWithTag:LABEL1_TAG];

    timerLbel.text = [NSStringstringWithFormat:@"%@ of %@",[selfformateTime:self.audioPlayer.currentTime],[selfformateTime:self.audioPlayer.duration]];

}

//分割时间的方法

- (NSString *)formateTime:(NSTimeInterval)_time

{

   int num = (int)_time;

   int min = num/60;

   int sec = num%60;

   if(num <60)

    {

       return [NSStringstringWithFormat:@"0:%2d",sec];

    }

   else

    {

       return  [NSStringstringWithFormat:@"%2d:%2d",min,sec];

    }

}


#pragma mark-指示器触发

- (void)progressChange:(id)sender

{

    [self.audioPlayerpause];

    

   UISlider *song = (UISlider *)[self.viewviewWithTag:SLI_SONG_TAG];

   UILabel *timerLabel = (UILabel *)[self.viewviewWithTag:LABEL1_TAG];

    self.audioPlayer.currentTime = song.value * self.audioPlayer.duration;

    timerLabel.text = [NSStringstringWithFormat:@"%@ of %@",[selfformateTime:self.audioPlayer.currentTime],[selfformateTime:self.audioPlayer.duration]];

    

}

//播放进度指示条改变时关联的方法

- (void)progressDidChang:(id)sender

{

    [self.audioPlayerplay];

}

//播放进度指示条改变完关联的方法

- (void)volumeChange:(id)sender

{

   UISlider *voice = (UISlider *)[self.viewviewWithTag:SLI_VOICE_TAG];

   self.audioPlayer.volume = voice.value;

}


#pragma mark  AVAudioPlayerDelegate

//音乐播放完关联的方法

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

{

   UISlider *voice = (UISlider *)[self.viewviewWithTag:SLI_VOICE_TAG];

   UISlider *song = (UISlider *)[self.viewviewWithTag:SLI_SONG_TAG];

    

    voice.enabled =NO;

    song.enabled =NO;

    

   UIButton *pBtn = (UIButton *)[self.viewviewWithTag:BUTTON_TAG];

    [pBtn setTitle:@"plaay"forState:UIControlStateNormal];

}


运行结果:



选中某一行后:



点击“play”按钮,开始播放音乐,同时按钮标题变为pause。



3. Audio Queue Services
如果以上两种音频播放的解决方案都无法满足你的需求,那么我想你肯定需要使用 Audio Queue Services。使用 Audio Queue Services 对音频进行播放,你可以完全实现对声音的控制。例如,你可以在声音数据从文件读到内存缓冲区后对声音进行一定处理再进行播放,从而实现对音频的快速/慢速播放的功能。
因为 Audio Queue Services 相对复杂很多,Apple 官方已经把它整理为一本书了,具体可以参考 Audio Queue Services Programming Guide 和 SpeakHere 的程序示例。


4. OpenAL
OpenAL 是一套跨平台的开源的音频处理接口,与图形处理的 OpenGL 类似,它为音频播放提供了一套更加优化的方案。它最适合开发游戏的音效,用法也与其他平台下相同。
iPhone 支持 OpenAL 1.1,我没有在实际开发中使用过,具体的文档可以参考 OpenAL 的网站 http://openal.org和 oalTouch 的程序示例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值