音频录制与播放可以用AVFoundation,也可以用Core Audio中的Audio Queue实现。一下以AVFoundation框架实现。
音频播放
AVAudioPlayer类可以实现一般音频播放,用于播放大于5秒中声音,但是不能播放网络媒体文件。
下面是一个播放器的实例:
#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
@interface ViewController ()
<AVAudioPlayerDelegate>
{
AVAudioPlayer *player;
}
@property (weak, nonatomic) IBOutlet UIButton *btnPlay;
@property (weak, nonatomic) IBOutlet UILabel *label;
- (IBAction)play:(id)sender;
- (IBAction)stop:(id)sender;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (IBAction)stop:(id)sender
{
if (player)
{
[player stop];
player.delegate = nil;
player = nil;
_label.text = @"播放停止";
[_btnPlay setTitle:@"播放停止" forState:UIControlStateNormal];
}
}
- (IBAction)play:(id)sender
{
NSError *error = nil;
if (player == nil)
{
NSString *path = [[NSBundle mainBundle] pathForResource:@"mark" ofType:@"caf"];
NSURL *url = [NSURL fileURLWithPath:path];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
if (error)
{
NSLog(@"%@", [error description]);
self.label.text = @"播放错误";
return;
}
player.delegate = self;
}
if (player.isPlaying == NO)
{
[player play];
_label.text = @"播放中……";
[_btnPlay setTitle:@"播放中" forState:UIControlStateNormal];
}
else if (player.isPlaying == YES)
{
[player pause];
_label.text = @"播放暂停";
[_btnPlay setTitle:@"播放暂停" forState:UIControlStateNormal];
}
}
#pragma mark -实现AVAudioPlayerDelegate协议方法
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player
successfully:(BOOL)flag
{
NSLog(@"播放完成");
_label.text = @"播放完成";
}
-(void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player
error:(NSError *)error
{
NSLog(@"播放错误发生:%@", [error description]);
_label.text = @"播放错误";
}
-(void)audioPlayerEndInterruption:(AVAudioPlayer *)player
{
NSLog(@"中断返回");
_label.text = @"中断返回";
}
-(void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
{
NSLog(@"播放中断");
_label.text = @"播放中断";
}
@end
音频录制
AVAudioRecider类可以实现音频录制。
- (IBAction)recording:(id)sender
{
NSMutableDictionary *settings = [NSMutableDictionary dictionary];
[settings setValue:[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey];
settings[AVSampleRateKey] = [NSNumber numberWithFloat:44100.0];
settings[AVNumberOfChannelsKey] = [NSNumber numberWithInt:1];
settings[AVLinearPCMBitDepthKey] = [NSNumber numberWithInt:16];
settings[AVLinearPCMIsBigEndianKey] = [NSNumber numberWithBool:NO];
settings[AVLinearPCMIsFloatKey] = [NSNumber numberWithBool:NO];
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"mark" ofType:@"caf"];
NSURL *fileUrl = [NSURL fileURLWithPath:filePath];
NSError *error;
recorder = [[AVAudioRecorder alloc] initWithURL:fileUrl settings:settings error:&error];
}
一个录音加播放的实际例子:
#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
@interface ViewController ()
<AVAudioRecorderDelegate>
{
AVAudioRecorder *recorder;
AVAudioPlayer *player;
}
@property (weak, nonatomic) IBOutlet UILabel *label;
- (IBAction)recording:(id)sender;
- (IBAction)stop:(id)sender;
- (IBAction)play:(id)sender;
-(NSString *)p_documentsDirectory;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_label.text = @"停止";
}
-(NSString *)p_documentsDirectory
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [paths objectAtIndex:0];
}
- (IBAction)play:(id)sender
{
if (recorder.isRecording)
{
[recorder stop];
recorder.delegate = nil;
recorder = nil;
}
if (player.isPlaying)
{
[player stop];
}
NSString *filePath = [NSString stringWithFormat:@"%@/rec_audio.caf", [self p_documentsDirectory]];
NSURL *fileUrl = [NSURL fileURLWithPath:filePath];
NSError *error = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
[[AVAudioSession sharedInstance] setActive:YES error:&error];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileUrl error:&error];
if (error)
{
NSLog(@" %@ ", [error description]);
}
else
{
[player play];
_label.text = @"播放……";
}
}
- (IBAction)stop:(id)sender
{
_label.text = @"停止……";
if (recorder.isRecording)
{
[recorder stop];
recorder.delegate = nil;
recorder = nil;
}
if (player.isPlaying)
{
[player stop];
}
}
- (IBAction)recording:(id)sender
{
if (recorder == nil)
{
NSString *filePath = [NSString stringWithFormat:@"%@/rec_audio.caf", [self p_documentsDirectory]];
NSURL *fileUrl = [NSURL fileURLWithPath:filePath];
NSError *error = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryRecord error:&error];
[[AVAudioSession sharedInstance] setActive:YES error:&error];
NSMutableDictionary *settings = [NSMutableDictionary dictionary];
[settings setValue:[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey];
settings[AVSampleRateKey] = [NSNumber numberWithFloat:44100.0];
settings[AVNumberOfChannelsKey] = [NSNumber numberWithInt:1];
settings[AVLinearPCMBitDepthKey] = [NSNumber numberWithInt:16];
settings[AVLinearPCMIsBigEndianKey] = [NSNumber numberWithBool:NO];
settings[AVLinearPCMIsFloatKey] = [NSNumber numberWithBool:NO];
recorder = [[AVAudioRecorder alloc] initWithURL:fileUrl settings:settings error:&error];
recorder.delegate = self;
}
if (recorder.isRecording)
{
return;
}
if (recorder && player.isPlaying)
{
[player stop];
}
[recorder record];
_label.text = @"录制中……";
}
#pragma mark - 实现AVAudioRecorderDelegate协议方法
-(void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder
successfully:(BOOL)flag
{
NSLog(@"录制完成");
}
-(void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder
error:(NSError *)error
{
NSLog(@"录制错误发生:%@", [error localizedDescription]);
}
-(void)audioRecorderBeginInterruption:(AVAudioRecorder *)recorder
{
NSLog(@"播放中断");
}
-(void)audioRecorderEndInterruption:(AVAudioRecorder *)recorder
withOptions:(NSUInteger)flags
{
NSLog(@"中断返回");
}
@end
语音合成
一个例子,将文字用语音合成播放。
#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
@interface ViewController ()
<AVSpeechSynthesizerDelegate,
UITextViewDelegate>
@property (weak, nonatomic) IBOutlet UITextView *textView;
@property (weak, nonatomic) IBOutlet UISlider *slider;
@property (nonatomic, strong) AVSpeechSynthesizer *speechSynthesizer;
@property (nonatomic, strong) NSArray *voices;
- (IBAction)speakButtonWasPressed:(id)sender;
- (IBAction)speechSpeedShouldChange:(id)sender;
-(BOOL)textView:(UITextView *)textView
shouldChangeTextInRange:(NSRange)range
replacementText:(NSString *)text;
-(void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer
didStartSpeechUtterance:(AVSpeechUtterance *)utterance;
-(void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer
didFinishSpeechUtterance:(AVSpeechUtterance *)utterance;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[_textView.layer setBorderWidth:0.5f];
[_textView.layer setBorderColor:[UIColor grayColor].CGColor];
_textView.delegate = self;
_speechSynthesizer = [[AVSpeechSynthesizer alloc] init];
_speechSynthesizer.delegate = self;
_voices = @[[AVSpeechSynthesisVoice voiceWithLanguage:@"en-US"],
[AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"]];
}
-(BOOL)textView:(UITextView *)textView
shouldChangeTextInRange:(NSRange)range
replacementText:(NSString *)text
{
BOOL retval = YES;
if ([text isEqualToString:@"\n"])
{
[_textView resignFirstResponder];
retval = NO;
}
return retval;
}
- (IBAction)speechSpeedShouldChange:(id)sender
{
UISlider *slider = sender;
NSInteger val = round(slider.value);
NSLog(@"%@", [NSString stringWithFormat:@"%ld", val]);
}
- (IBAction)speakButtonWasPressed:(id)sender
{
AVSpeechUtterance *utt = [AVSpeechUtterance speechUtteranceWithString:_textView.text];
utt.rate = _slider.value;
utt.voice = _voices[1];
utt.pitchMultiplier = 0.8;
[_speechSynthesizer speakUtterance:utt];
}
-(void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didStartSpeechUtterance:(AVSpeechUtterance *)utterance
{
NSLog(@"语音开始合成");
}
-(void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didFinishSpeechUtterance:(AVSpeechUtterance *)utterance
{
NSLog(@"语音合成完成");
}
@end