美文网首页
iOS 中 SystemSoundID(播放系统声音) 和 A

iOS 中 SystemSoundID(播放系统声音) 和 A

作者: flyrees | 来源:发表于2017-11-03 14:53 被阅读0次

    先来介绍一下SystemSoundID:

    SystemSoundID简介

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

    • 你可以用它来播放一个短的声音(30秒以下)

    • 这个接口不支持等级,位置,循环,时间的控制,同时播放功能。在同一时间,你只能播放一个声音。

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

    主要API:

    创建对象:

    OSStatus AudioServicesCreateSystemSoundID ( CFURLRef __nonnull inFileURL,SystemSoundID * __nonnull outSystemSoundID );
    

    销毁对象:

    OSStatus AudioServicesDisposeSystemSoundID ( SystemSoundID inSystemSoundID);
    

    播放声音:(一共2个)
    带有振动效果的播放:

    void AudioServicesPlayAlertSound ( SystemSoundID inSystemSoundID );
    
    void AudioServicesPlaySystemSound ( SystemSoundID inSystemSoundID );
    

    播放完成之后执行的操作:(其中弟四个参数是一个C语言的函数)

    OSStatus AudioServicesAddSystemSoundCompletion ( SystemSoundIDinSystemSoundID, CFRunLoopRef __nullable inRunLoop, CFStringRef __nullableinRunLoopMode, AudioServicesSystemSoundCompletionProc __nonnullinCompletionRoutine, void * __nullable inClientData );
    

    用法详解:

    用法详解:

            //1.获得音效文件的全路径
             NSURL *url=[[NSBundle mainBundle] URLForResource:@"4.wav" withExtension:nil];
    
             //2.加载音效文件,创建音效ID(SoundID,一个ID对应一个音效文件)
             SystemSoundID soundID = 0;
             AudioServicesCreateSystemSoundID((__bridge CFURLRef)url, &soundID);
    
             //把需要销毁的音效文件的ID传递给它既可销毁
             //AudioServicesDisposeSystemSoundID(soundID);
    
            // 完成播放之后执行的soundCompleteCallback函数
             AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, soundCompleteCallback, NULL);
    
             //3.播放音效文件
             //下面的两个函数都可以用来播放音效文件,第一个函数伴随有震动效果
             AudioServicesPlayAlertSound(soundID);
             //AudioServicesPlaySystemSound(<#SystemSoundID inSystemSoundID#>)
    
    #pragma mark - 播放完成之后执行的函数
    void soundCompleteCallback()
    {
        NSLog(@"播放完成");
    }
    

    AVAudioRecorder简介 :
    使用一个录音机,您可以:

    •       录制,直到用户停止录音
      
    •       在一个特定的时间录制声音
      
    •       暂停和恢复录制
      
    •       记录获得输入音频电平数据,您可以使用它们来提供计量水平
      

    说明:
    在创建录音机时除了指定路径外还必须指定录音设置信息,因为录音机必须知道录音文件的格式、采样率、通道数、每个采样点的位数等信息,但是也并不是所有的信息都必须设置,通常只需要几个常用设置。关于录音设置详见帮助文档中的“AV Foundation Audio Settings Constants”。
    ————注意:录音的时候必须设置AVAudioSession,否则将无法录音

    /** * 设置音频会话 */

    -(void)setAudioSession{ AVAudioSession *audioSession=[AVAudioSession sharedInstance];
    

    //设置为播放和录音状态,以便可以在录制完之后播放录音

    [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; [audioSession setActive:YES error:nil]; }
    

    主要API:
    初始化:

    - (instancetype nullable)initWithURL:(NSURL * nonnull)url settings:(NSDictionary<NSString *,id> * nonnull)settings error:(NSError * nullable * nullable)outError
    

    是否准备好录音:

    - (BOOL)prepareToRecord
    

    录音:

    - (BOOL)record
    

    暂停:

    - (void)pause
    

    停止:

    - (void)stop
    

    从一个特定的时间开始录制:

    - (BOOL)recordAtTime:(NSTimeInterval)time
    

    录音的设置:(特别重要)

    @property(readonly) NSDictionary <NSString *,id> *settings
    

    是否启动音频测量:

    //是否启用音频测量,默认为NO,一旦启用音频测量可以通过updateMeters方法更新测量值
    @property(getter=isMeteringEnabled) BOOL meteringEnabled
    

    更新音频测量值:

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

    获取指定声道的分贝值:

    //获得指定声道的分贝峰值,注意如果要获得分贝峰值必须在此之前调用updateMeters方法
    - (float)peakPowerForChannel:(NSUInteger)channelNumber;
    

    再来看一下代码的实现:

    //
    //  ViewController.m
    //  SystemSoundle播放音频
    //
    //  Created by dlios on 15/12/8.
    //  Copyright © 2015年 PFG. All rights reserved.
    //
    
    #import "ViewController.h"
    #import <AVFoundation/AVFoundation.h>
    
    @interface ViewController ()
    @property (nonatomic, strong)UIButton *playerButton;
    @property (nonatomic, strong)UIButton *recorderButton;
    @property (nonatomic, strong)UIButton *avAudionButton;
    @property (nonatomic, strong)UIImageView *imageView;
    @property (nonatomic, strong)UIImageView *imageViewSound;
    
    @property (nonatomic, strong)AVAudioRecorder *reverb;
    @property (nonatomic, strong)NSMutableDictionary *recordSetting;
    @property (nonatomic, strong)AVAudioPlayer *player;
    @property (nonatomic, strong)NSString *path;
    @property (nonatomic, strong)NSTimer *timer;
    @property (nonatomic, assign)double lowPassResults;
    @property (nonatomic, strong)NSArray *arrayImage;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        self.view.backgroundColor = [UIColor grayColor];
        
        AVAudioSession *session = [[AVAudioSession alloc] init];
        //设置会话的工作模式
        [session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
        
        
        [self creatControl];
        //设置录音的格式
        [self creatSetting];
    }
    - (void)creatControl
    {
        self.playerButton = [UIButton buttonWithType:UIButtonTypeCustom];
        
        [self.playerButton setBackgroundColor:[UIColor colorWithRed:arc4random() % 255 / 255. green:arc4random() % 255 / 255. blue:arc4random() % 255 / 255. alpha:.6]];
       
        [self.playerButton setFrame:CGRectMake(0, 0, 100, 40)];
       
        [self.playerButton setCenter:CGPointMake(self.view.frame.size.width / 2, 260)];
      
        [self.playerButton setTitleColor:[UIColor colorWithRed:arc4random() % 225 / 255. green:arc4random() % 225 / 255. blue:arc4random() % 225 / 255. alpha:1] forState:UIControlStateNormal];
       
        [self.playerButton setTitle:@"播放音效" forState:UIControlStateNormal];
        
        [self.playerButton addTarget:self action:@selector(player:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:self.playerButton];
        
        
        self.recorderButton = [UIButton buttonWithType:UIButtonTypeCustom];
       
        [self.recorderButton setBackgroundColor:[UIColor colorWithRed:arc4random() % 255 / 255. green:arc4random() % 255 / 255. blue:arc4random() % 255 / 255. alpha:.6]];
       
        [self.recorderButton setTitle:@"按住录音" forState:UIControlStateNormal];
       
        [self.recorderButton setTitle:@"松开结束" forState:UIControlStateHighlighted];
       
        [self.recorderButton setTitleColor:[UIColor colorWithRed:arc4random() % 225 / 255. green:arc4random() % 225 / 255. blue:arc4random() % 225 / 255. alpha:1] forState:UIControlStateNormal];
       
        [self.recorderButton setFrame:CGRectMake(0, 0, 100, 40)];
       
        [self.recorderButton setCenter:CGPointMake(self.view.frame.size.width / 2, 360)];
       
        //按下
        [self.recorderButton addTarget:self action:@selector(recorderButton:) forControlEvents:UIControlEventTouchDown];
       
        //松开
        [self.recorderButton addTarget:self action:@selector(handleStop:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:self.recorderButton];
        
        
        self.avAudionButton = [UIButton buttonWithType:UIButtonTypeCustom];
       
        [self.avAudionButton setBackgroundColor:[UIColor colorWithRed:arc4random() % 255 / 255. green:arc4random() % 255 / 255. blue:arc4random() % 255 / 255. alpha:.6]];
       
        [self.avAudionButton setFrame:CGRectMake(0, 0, 100, 40)];
       
        [self.avAudionButton setCenter:CGPointMake(self.view.frame.size.width / 2, 460)];
       
        [self.avAudionButton setTitleColor:[UIColor colorWithRed:arc4random() % 225 / 255. green:arc4random() % 225 / 255. blue:arc4random() % 225 / 255. alpha:1] forState:UIControlStateNormal];
       
        [self.avAudionButton setTitle:@"播放本地" forState:UIControlStateNormal];
       
        [self.avAudionButton addTarget:self action:@selector(avAudionButton:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:self.avAudionButton];
        
        self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(20, 100, 30, 60)];
       
        [self.imageView setImage:[UIImage imageNamed:@"RecordingBkg"]];
        [self.view addSubview:self.imageView];
        
        //音量图片数组
        self.arrayImage = @[@"RecordingSignal001",@"RecordingSignal002",@"RecordingSignal003",
                           @"RecordingSignal004", @"RecordingSignal005",@"RecordingSignal006",
                           @"RecordingSignal007",@"RecordingSignal008"];
        
        self.imageViewSound = [[UIImageView alloc] initWithFrame:CGRectMake(60, 100, 20, 60)];
        [self.view addSubview:self.imageViewSound];
    }
    - (void)creatSetting
    {
        self.recordSetting = [[NSMutableDictionary alloc]init];
       
        //设置录音格式  AVFormatIDKey==kAudioFormatLinearPCM
        [self.recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
       
        //设置录音采样率(Hz) 如:AVSampleRateKey==8000/44100/96000(影响音频的质量)
       
        [self.recordSetting setValue:[NSNumber numberWithFloat:44100] forKey:AVSampleRateKey];
       
        //录音通道数  1 或 2
        [self.recordSetting setValue:[NSNumber numberWithInt:1] forKey:AVNumberOfChannelsKey];
       
        //线性采样位数  8、16、24、32
        [self.recordSetting setValue:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
       
        //录音的质量
        [self.recordSetting setValue:[NSNumber numberWithInt:AVAudioQualityHigh] forKey:AVEncoderAudioQualityKey];
    }
    
    #pragma mark - 播放音效
    - (void)player:(UIButton *)button
    {
        //1.获得音效文件的全路径
        NSString *str = [[NSBundle mainBundle] pathForResource:@"4" ofType:@"wav"];
        NSURL *url = [NSURL fileURLWithPath:str];
        
        //2.加载音效文件,创建音效ID(SoundID,一个ID对应一个音效文件)
        SystemSoundID soundID = 0;
    
        //创建声音文件对象
        AudioServicesCreateSystemSoundID((__bridge CFURLRef)url, &soundID);
        
        //3.播放音效文件(带振动)
        AudioServicesPlayAlertSound(soundID);
        
        
        // 完成播放之后执行的soundCompleteCallback函数
        AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, soundCompleteCallback, NULL);
        
        //把需要销毁的音效文件的ID传递给它既可销毁
    //    AudioServicesDisposeSystemSoundID(soundID);
        
    }
    #pragma mark - 播放完成之后执行的函数
    void soundCompleteCallback()
    {
        NSLog(@"播放完成");
    }
    #pragma mark - 按下方法
    - (void)recorderButton:(UIButton *)button
    {
        self.path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"aa.aac"];
    
        NSLog(@"%@", self.path);
    
        self.reverb = nil;
    
        NSError *error = nil;
    
        self.reverb = [[AVAudioRecorder alloc] initWithURL:[NSURL URLWithString:self.path] settings:self.recordSetting error:&error];
        
        //开启音量检查
        self.reverb.meteringEnabled = YES;
        
        if ([self.reverb prepareToRecord]) {
            [self.reverb record];
            
            self.timer = [NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:@selector(timerClick:) userInfo:nil repeats:YES];
                    
        }else{
            NSLog(@"录音没准备好:%@", error);
        }
    }
    #pragma mark - 松开方法
    - (void)handleStop:(UIButton *)button
    {
        [self.reverb stop];
        
        self.reverb = nil;
        
        //销毁定时器
        [self.timer invalidate];
        
        self.timer = nil;
        
        //将图片值为空
        self.imageViewSound.image = [UIImage imageNamed:@""];
    }
    
    - (void)avAudionButton:(UIButton *)button
    {
        self.player = nil;
    
        //创建播放对象
        self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:self.path] error:nil];
    
        if ([self.player prepareToPlay]) {
    
            [self.player play];
    
        }else{
    
            NSLog(@"播放器没有准备好");
    
        }
    }
    #pragma mark - 定时器方法
    - (void)timerClick:(NSTimer *)timer
    {
        //更新分值
        [self.reverb updateMeters];
        
        //call to refresh meter values刷新平均和峰值功率,此计数是以对数刻度计量的,-160表示完全安静,0表示最大输入值
        // 获取指定声道的分贝值:
        const double ALPHA = 0.05;
    
        double peakPowerForChannel = pow(10, (0.05 * [self.reverb peakPowerForChannel:0]));
    
        self.lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * self.lowPassResults;
        
        if (self.lowPassResults>=0.8) {
    
            self.imageViewSound.image = [UIImage imageNamed:[self.arrayImage objectAtIndex:7]];
    
        }else if(self.lowPassResults>=0.7){
    
            self.imageViewSound.image = [UIImage imageNamed:
    [self.arrayImage objectAtIndex:6]];
    
        }else if(self.lowPassResults>=0.6){
    
            self.imageViewSound.image = [UIImage imageNamed:[self.arrayImage objectAtIndex:5]];
    
        }else if(self.lowPassResults>=0.5){
    
            self.imageViewSound.image = [UIImage imageNamed:[self.arrayImage objectAtIndex:4]];
    
        }else if(self.lowPassResults>=0.4){
    
            self.imageViewSound.image = [UIImage imageNamed:[self.arrayImage objectAtIndex:3]];
    
        }else if(self.lowPassResults>=0.3){
    
            self.imageViewSound.image = [UIImage imageNamed:[self.arrayImage objectAtIndex:2]];
    
        }else if(self.lowPassResults>=0.2){
    
            self.imageViewSound.image = [UIImage imageNamed:[self.arrayImage objectAtIndex:1]];
    
        }else if(self.lowPassResults>=0.1){
    
            self.imageViewSound.image = [UIImage imageNamed:[self.arrayImage objectAtIndex:0]];
    
        }else{
    
            self.imageViewSound.image = [UIImage imageNamed:[self.arrayImage objectAtIndex:0]];
    
        }    
    }
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    @end
    

    相关文章

      网友评论

          本文标题:iOS 中 SystemSoundID(播放系统声音) 和 A

          本文链接:https://www.haomeiwen.com/subject/zeytmxtx.html