// // Copyright 1999-2015 MyApp // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "MTAudioManager.h" #import #import "NSTimer+BlocksKit.h" #import "DDAudioManager.h" @interface MTAudioManager() @property (nonatomic, strong) AVAudioSession *session; @property (nonatomic, strong) NSURL *recordFileURL; @property (nonatomic, copy) NSString *recordUrlKey; @property (nonatomic, copy) didPlayFinish finishBlock; @property (nonatomic, strong) NSTimer *recordProgressTimer; @end @implementation MTAudioManager + (instancetype)sharedInstance { static MTAudioManager *instance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [[MTAudioManager alloc] init]; }); return instance; } - (instancetype)init { self = [super init]; if(self) { [self activeAudioSession]; } return self; } - (void)activeAudioSession { self.session = [AVAudioSession sharedInstance]; NSError *sessionError = nil; [self.session setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:&sessionError]; UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" AudioSessionSetProperty ( kAudioSessionProperty_OverrideAudioRoute, sizeof (audioRouteOverride), &audioRouteOverride ); #pragma clang diagnostic pop if(!self.session) { NSLog(@"Error creating session: %@", [sessionError description]); } else { [self.session setActive:YES error:nil]; } [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]]; } - (void)playWithData:(NSData *)data finish:(void (^)(void))didFinish; { [self stopPlay]; self.finishBlock = didFinish; if (self.player) { if (self.player.isPlaying) { [self.player stop]; } self.player.delegate = nil; self.player = nil; } NSError *playerError = nil; self.player = [[AVAudioPlayer alloc] initWithData:data error:&playerError]; if (self.player) { self.player.delegate = self; [self.player play]; } else { NSLog(@"Error creating player: %@", [playerError description]); } } - (void)stopPlay { if (self.player) { if (self.player.isPlaying) { [self.player stop]; } self.player.delegate = nil; self.player = nil; // 恢复其他app音频播放 // [[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil]; if (self.finishBlock) { self.finishBlock(); self.finishBlock = nil; } } } - (BOOL)initRecord { [self activeAudioSession]; //录音设置 NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc]init]; //设置录音格式 AVFormatIDKey==kAudioFormatLinearPCM [recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey]; //设置录音采样率(Hz) 如:AVSampleRateKey==8000/44100/96000(影响音频的质量) [recordSetting setValue:[NSNumber numberWithFloat:16000.0] forKey:AVSampleRateKey]; //调低采样率,防止小程序播放不支持 //录音通道数 1 或 2 [recordSetting setValue:[NSNumber numberWithInt:1] forKey:AVNumberOfChannelsKey]; //线性采样位数 8、16、24、32 [recordSetting setValue:[NSNumber numberWithInt:8] forKey:AVLinearPCMBitDepthKey]; //设置最小8位,防止小程序播放不支持 //录音的质量 [recordSetting setValue:[NSNumber numberWithInt:AVAudioQualityHigh] forKey:AVEncoderAudioQualityKey]; NSTimeInterval timeInterval = [[NSDate date] timeIntervalSince1970]; NSString *strUrl = [NSString stringWithFormat:@"%@/%f.m4a", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject], timeInterval]; NSURL *url = [NSURL fileURLWithPath:strUrl]; self.recordUrlKey = strUrl; NSError *error; //初始化 _recorder = [[AVAudioRecorder alloc]initWithURL:url settings:recordSetting error:&error]; //开启音量检测 self.recorder.meteringEnabled = YES; if ([self.recorder prepareToRecord]){ return YES; } return NO; } - (BOOL)startRecord { BOOL succees = [self.recorder record]; if (succees) { __weak MTAudioManager * weakSelf = self; NSTimer *timer = [NSTimer bk_scheduleTimerWithTimeInterval:0.1 repeats:YES usingBlock:^(NSTimer * _Nonnull timer) { if ([weakSelf.recordDelegate respondsToSelector:@selector(audioManager:audioPath:recordingProgress:)]) { [weakSelf.recordDelegate audioManager:weakSelf audioPath:weakSelf.recordUrlKey recordingProgress:[weakSelf recordTime]]; } }]; self.recordProgressTimer = timer; } return succees; } - (void)stopRecord { NSTimeInterval duration = self.recorder.currentTime; [self.recorder stop]; // 恢复其他app音频播放 // [[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil]; [self.recordProgressTimer invalidate]; self.recordProgressTimer = nil; if ([self.recordDelegate respondsToSelector:@selector(audioManagerDidStopedRecord:audioPath:duration:)]) { [self.recordDelegate audioManagerDidStopedRecord:self audioPath:self.recordUrlKey duration:round(duration)]; } } - (CGFloat)peakPowerMeter { return 0.5; } - (NSTimeInterval)recordTime { return (self.recorder.currentTime); } - (void)handleInterruption:(NSNotification *)noti { ; } #pragma mark - AVAudioPlayerDelegate - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag { // 恢复其他app音频播放 // [[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil]; if (self.finishBlock) { self.finishBlock(); self.finishBlock = nil; } } /* if an error occurs while encoding it will be reported to the delegate. */ - (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError * __nullable)error { ; } @end