iOS音频——AVFoundation框架实现音频录制与播放

音频录制与播放可以用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

猜你喜欢

转载自blog.csdn.net/run_in_road/article/details/113524125