/************************************************************
|
* * Hyphenate CONFIDENTIAL
|
* __________________
|
* Copyright (C) 2016 Hyphenate Inc. All rights reserved.
|
*
|
* NOTICE: All information contained herein is, and remains
|
* the property of Hyphenate Inc.
|
* Dissemination of this information or reproduction of this material
|
* is strictly forbidden unless prior written permission is obtained
|
* from Hyphenate Inc.
|
*/
|
|
#import "EMCDDeviceManager+Media.h"
|
#import "EMAudioPlayerUtil.h"
|
#import "EMAudioRecorderUtil.h"
|
#import "EMVoiceConverter.h"
|
#import "DemoErrorCode.h"
|
#import "EaseLocalDefine.h"
|
|
typedef NS_ENUM(NSInteger, EMAudioSession){
|
EM_DEFAULT = 0,
|
EM_AUDIOPLAYER,
|
EM_AUDIORECORDER
|
};
|
|
@implementation EMCDDeviceManager (Media)
|
#pragma mark - AudioPlayer
|
|
+ (NSString*)dataPath
|
{
|
NSString *dataPath = [NSString stringWithFormat:@"%@/Library/appdata/chatbuffer", NSHomeDirectory()];
|
NSFileManager *fm = [NSFileManager defaultManager];
|
if(![fm fileExistsAtPath:dataPath]){
|
[fm createDirectoryAtPath:dataPath
|
withIntermediateDirectories:YES
|
attributes:nil
|
error:nil];
|
}
|
return dataPath;
|
}
|
|
// Play the audio
|
- (void)asyncPlayingWithPath:(NSString *)aFilePath
|
completion:(void(^)(NSError *error))completon{
|
BOOL isNeedSetActive = YES;
|
// Cancel if it is currently playing
|
if([EMAudioPlayerUtil isPlaying]){
|
[EMAudioPlayerUtil stopCurrentPlaying];
|
isNeedSetActive = NO;
|
}
|
|
if (isNeedSetActive) {
|
[self setupAudioSessionCategory:EM_AUDIOPLAYER
|
isActive:YES];
|
}
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
NSString *wavFilePath = [[aFilePath stringByDeletingPathExtension] stringByAppendingPathExtension:@"wav"];
|
if ([EMVoiceConverter isMP3File:aFilePath]) {
|
wavFilePath = aFilePath;
|
} else {
|
if (![fileManager fileExistsAtPath:wavFilePath]) {
|
BOOL covertRet = [self convertAMR:aFilePath toWAV:wavFilePath];
|
if (!covertRet) {
|
if (completon) {
|
completon([NSError errorWithDomain:NSEaseLocalizedString(@"error.initRecorderFail", @"File format conversion failed")
|
code:EMErrorFileTypeConvertionFailure
|
userInfo:nil]);
|
}
|
return ;
|
}
|
}
|
}
|
[EMAudioPlayerUtil asyncPlayingWithPath:wavFilePath
|
completion:^(NSError *error)
|
{
|
[self setupAudioSessionCategory:EM_DEFAULT
|
isActive:NO];
|
if (completon) {
|
completon(error);
|
}
|
}];
|
}
|
|
- (void)stopPlaying{
|
[EMAudioPlayerUtil stopCurrentPlaying];
|
[self setupAudioSessionCategory:EM_DEFAULT
|
isActive:NO];
|
}
|
|
- (void)stopPlayingWithChangeCategory:(BOOL)isChange{
|
[EMAudioPlayerUtil stopCurrentPlaying];
|
if (isChange) {
|
[self setupAudioSessionCategory:EM_DEFAULT
|
isActive:NO];
|
}
|
}
|
|
- (BOOL)isPlaying{
|
return [EMAudioPlayerUtil isPlaying];
|
}
|
|
#pragma mark - Recorder
|
|
+(NSTimeInterval)recordMinDuration{
|
return 1.0;
|
}
|
|
// Start recording
|
- (void)asyncStartRecordingWithFileName:(NSString *)fileName
|
completion:(void(^)(NSError *error))completion{
|
NSError *error = nil;
|
|
if ([self isRecording]) {
|
if (completion) {
|
error = [NSError errorWithDomain:NSEaseLocalizedString(@"error.recordStoping", @"Record voice is not over yet")
|
code:EMErrorAudioRecordStoping
|
userInfo:nil];
|
completion(error);
|
}
|
return ;
|
}
|
|
if (!fileName || [fileName length] == 0) {
|
error = [NSError errorWithDomain:NSEaseLocalizedString(@"error.notFound", @"File path not exist")
|
code:-1
|
userInfo:nil];
|
completion(error);
|
return ;
|
}
|
|
BOOL isNeedSetActive = YES;
|
if ([self isRecording]) {
|
[EMAudioRecorderUtil cancelCurrentRecording];
|
isNeedSetActive = NO;
|
}
|
|
[self setupAudioSessionCategory:EM_AUDIORECORDER
|
isActive:YES];
|
|
_recorderStartDate = [NSDate date];
|
|
NSString *recordPath = [NSString stringWithFormat:@"%@/%@", [EMCDDeviceManager dataPath], fileName];
|
[EMAudioRecorderUtil asyncStartRecordingWithPreparePath:recordPath
|
completion:completion];
|
}
|
|
// Stop recording
|
-(void)asyncStopRecordingWithCompletion:(void(^)(NSString *recordPath,
|
NSInteger aDuration,
|
NSError *error))completion{
|
NSError *error = nil;
|
|
if(![self isRecording]){
|
if (completion) {
|
error = [NSError errorWithDomain:NSEaseLocalizedString(@"error.recordNotBegin", @"Recording has not yet begun")
|
code:EMErrorAudioRecordNotStarted
|
userInfo:nil];
|
completion(nil,0,error);
|
}
|
return;
|
}
|
|
__weak typeof(self) weakSelf = self;
|
_recorderEndDate = [NSDate date];
|
|
if([_recorderEndDate timeIntervalSinceDate:_recorderStartDate] < [EMCDDeviceManager recordMinDuration]){
|
if (completion) {
|
error = [NSError errorWithDomain:NSEaseLocalizedString(@"error.recordTooShort", @"Recording time is too short")
|
code:EMErrorAudioRecordDurationTooShort
|
userInfo:nil];
|
completion(nil,0,error);
|
}
|
|
// If the recording time is too shorty,in purpose delay one second
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)([EMCDDeviceManager recordMinDuration] * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
[EMAudioRecorderUtil asyncStopRecordingWithCompletion:^(NSString *recordPath) {
|
[weakSelf setupAudioSessionCategory:EM_DEFAULT isActive:NO];
|
}];
|
});
|
return ;
|
}
|
|
[EMAudioRecorderUtil asyncStopRecordingWithCompletion:^(NSString *recordPath) {
|
if (completion) {
|
if (recordPath) {
|
// Convert wav to amr
|
NSString *amrFilePath = [[recordPath stringByDeletingPathExtension]
|
stringByAppendingPathExtension:@"amr"];
|
BOOL convertResult = [self convertWAV:recordPath toAMR:amrFilePath];
|
NSError *error = nil;
|
if (convertResult) {
|
// Remove the wav
|
NSFileManager *fm = [NSFileManager defaultManager];
|
[fm removeItemAtPath:recordPath error:nil];
|
}
|
else {
|
error = [NSError errorWithDomain:NSEaseLocalizedString(@"error.initRecorderFail", @"File format conversion failed")
|
code:EMErrorFileTypeConvertionFailure
|
userInfo:nil];
|
}
|
completion(amrFilePath,(int)[self->_recorderEndDate timeIntervalSinceDate:self->_recorderStartDate],error);
|
}
|
[weakSelf setupAudioSessionCategory:EM_DEFAULT isActive:NO];
|
}
|
}];
|
}
|
|
// Cancel recording
|
-(void)cancelCurrentRecording{
|
[EMAudioRecorderUtil cancelCurrentRecording];
|
[self setupAudioSessionCategory:EM_DEFAULT isActive:NO];
|
}
|
|
-(BOOL)isRecording{
|
return [EMAudioRecorderUtil isRecording];
|
}
|
|
#pragma mark - Private
|
-(NSError *)setupAudioSessionCategory:(EMAudioSession)session
|
isActive:(BOOL)isActive{
|
BOOL isNeedActive = NO;
|
if (isActive != _currActive) {
|
isNeedActive = YES;
|
_currActive = isActive;
|
}
|
NSError *error = nil;
|
NSString *audioSessionCategory = nil;
|
switch (session) {
|
case EM_AUDIOPLAYER:
|
audioSessionCategory = AVAudioSessionCategoryPlayback;
|
break;
|
case EM_AUDIORECORDER:
|
audioSessionCategory = AVAudioSessionCategoryRecord;
|
break;
|
default:
|
audioSessionCategory = AVAudioSessionCategoryAmbient;
|
break;
|
}
|
|
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
|
|
if (![_currCategory isEqualToString:audioSessionCategory]) {
|
[audioSession setCategory:audioSessionCategory error:nil];
|
}
|
if (isNeedActive) {
|
BOOL success = [audioSession setActive:isActive
|
withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation
|
error:&error];
|
if(!success || error){
|
error = [NSError errorWithDomain:NSEaseLocalizedString(@"error.initPlayerFail", @"Failed to initialize AVAudioPlayer")
|
code:-1
|
userInfo:nil];
|
return error;
|
}
|
}
|
_currCategory = audioSessionCategory;
|
|
return error;
|
}
|
|
#pragma mark - Convert
|
|
- (BOOL)convertAMR:(NSString *)amrFilePath
|
toWAV:(NSString *)wavFilePath
|
{
|
BOOL ret = NO;
|
BOOL isFileExists = [[NSFileManager defaultManager] fileExistsAtPath:amrFilePath];
|
if (isFileExists) {
|
[EMVoiceConverter amrToWav:amrFilePath wavSavePath:wavFilePath];
|
isFileExists = [[NSFileManager defaultManager] fileExistsAtPath:wavFilePath];
|
if (isFileExists) {
|
ret = YES;
|
}
|
}
|
|
return ret;
|
}
|
|
- (BOOL)convertWAV:(NSString *)wavFilePath
|
toAMR:(NSString *)amrFilePath {
|
BOOL ret = NO;
|
BOOL isFileExists = [[NSFileManager defaultManager] fileExistsAtPath:wavFilePath];
|
if (isFileExists) {
|
[EMVoiceConverter wavToAmr:wavFilePath amrSavePath:amrFilePath];
|
isFileExists = [[NSFileManager defaultManager] fileExistsAtPath:amrFilePath];
|
if (!isFileExists) {
|
|
} else {
|
ret = YES;
|
}
|
}
|
|
return ret;
|
}
|
|
@end
|