IOS开发之使用Speex格式实现简单的语音聊天功能(二)
来源:互联网 发布:游戏碎片整理软件 编辑:程序博客网 时间:2024/05/22 04:56
今天我们继续上一篇博客“IOS开发之使用Speex格式实现简单的语音聊天功能(一)”继续往下讲,主要是讲述一下PlayManager与RecorderManager两个类的功能。
首先要讲的是RecorderManager,该类的主要功能就是负责对用户的语音进行录制,和停止录制。
#import <Foundation/Foundation.h>#import "Encapsulator.h"@protocol RecordingDelegate <NSObject>- (void)recordingFinishedWithFileName:(NSString *)filePath time:(NSTimeInterval)interval;- (void)recordingTimeout;- (void)recordingStopped; //录音机停止采集声音- (void)recordingFailed:(NSString *)failureInfoString;@optional- (void)levelMeterChanged:(float)levelMeter;@end@interface RecorderManager : NSObject <EncapsulatingDelegate> { Encapsulator *encapsulator; NSString *filename; NSDate *dateStartRecording; NSDate *dateStopRecording; NSTimer *timerLevelMeter; NSTimer *timerTimeout;}@property (nonatomic, weak) id<RecordingDelegate> delegate;@property (nonatomic, strong) Encapsulator *encapsulator;@property (nonatomic, strong) NSDate *dateStartRecording, *dateStopRecording;@property (nonatomic, strong) NSTimer *timerLevelMeter;@property (nonatomic, strong) NSTimer *timerTimeout;+ (RecorderManager *)sharedManager;- (void)startRecording;- (void)stopRecording;- (void)cancelRecording;- (NSTimeInterval)recordedTimeInterval;@end
该类的主要结构就是上面头文件中所展示的,包括一个委托RecordingDelegate,以及RecorderManager本身的类函数。该类使用了单例模式,通过调用函数shareManager即可获取它实例本身。
startRecording函数负责录音工作:
- (void)startRecording { if ( ! mAQRecorder) { mAQRecorder = new AQRecorder(); OSStatus error = AudioSessionInitialize(NULL, NULL, interruptionListener, (__bridge void *)self); if (error) printf("ERROR INITIALIZING AUDIO SESSION! %d\n", (int)error); else { UInt32 category = kAudioSessionCategory_PlayAndRecord; error = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category); if (error) printf("couldn't set audio category!"); //添加属性监听,一旦有属性改变则调用其中的propListener函数 error = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, propListener, (__bridge void *)self); if (error) printf("ERROR ADDING AUDIO SESSION PROP LISTENER! %d\n", (int)error); UInt32 inputAvailable = 0; UInt32 size = sizeof(inputAvailable); // we do not want to allow recording if input is not available error = AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable, &size, &inputAvailable); if (error) printf("ERROR GETTING INPUT AVAILABILITY! %d\n", (int)error); // we also need to listen to see if input availability changes error = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioInputAvailable, propListener, (__bridge void *)self); if (error) printf("ERROR ADDING AUDIO SESSION PROP LISTENER! %d\n", (int)error); error = AudioSessionSetActive(true); if (error) printf("AudioSessionSetActive (true) failed"); } } //获取音频存放地址 filename = [NSString stringWithString:[Encapsulator defaultFileName]]; NSLog(@"filename:%@",filename); if ( ! self.encapsulator) { self.encapsulator = [[Encapsulator alloc] initWithFileName:filename]; self.encapsulator.delegete = self; } else { [self.encapsulator resetWithFileName:filename]; } if ( ! mAQRecorder->IsRunning()) { NSLog(@"audio session category : %@", [[AVAudioSession sharedInstance] category]); Boolean recordingWillBegin = mAQRecorder->StartRecord(encapsulator); if ( ! recordingWillBegin) { if ([self.delegate respondsToSelector:@selector(recordingFailed:)]) { [self.delegate recordingFailed:@"程序错误,无法继续录音,请重启程序试试"]; } return; } } self.dateStartRecording = [NSDate date]; if (!levelMeterStates) { levelMeterStates = (AudioQueueLevelMeterState *)malloc(sizeof(AudioQueueLevelMeterState) * 1); } self.timerLevelMeter = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(updateLevelMeter:) userInfo:nil repeats:YES]; self.timerTimeout = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(timeoutCheck:) userInfo:nil repeats:NO];}
在startRecording函数中,先实例化类AQRecorder,该类是用C++实现的,主要用作录制音频文件(核心类)。随后调用函数AudioSessionInitialize初始化音频,并添加回调函数interruptionListener,若监听被打断则停止AQRecorder类的录制工作。若返回值不是error则对音频添加相应的属性,并且回调函数为propListener,若监听的属性不正确,就停止录音。当然了,所有的音频都是以文件为单位的,在startRecording函数中利用[EncapsulatordefaultFileName]来获取音频的存放地址,Encapsulator类也是一个很重要的类,它封装了ogg,极大的方便了我们调用它里面的函数来实现录音。
函数- (void)stopRecording的作用大家想必都知道就是停止录音,但是不取消音频;
函数- (void)cancelRecording的作用则是停止录音并且取消;
函数recordedTimeInterval则是获取录音时间,单位为float;
#import <Foundation/Foundation.h>#import <AVFoundation/AVFoundation.h>#import "Decapsulator.h"@protocol PlayingDelegate <NSObject>- (void)playingStoped;@end@interface PlayerManager : NSObject <DecapsulatingDelegate, AVAudioPlayerDelegate> { Decapsulator *decapsulator; AVAudioPlayer *avAudioPlayer; }@property (nonatomic, strong) Decapsulator *decapsulator;@property (nonatomic, strong) AVAudioPlayer *avAudioPlayer;@property (nonatomic, weak) id<PlayingDelegate> delegate;+ (PlayerManager *)sharedManager;- (void)playAudioWithFileName:(NSString *)filename delegate:(id<PlayingDelegate>)newDelegate;- (void)stopPlaying;@end
可以看到该类与RecordingManager一样,也使用了单例并且其中有委托对象PlayingDelegate,函数playingStoped用于暂停播放。
该类有两个主要函数"playAudioWithFileName"与“stopPlaying”前者可以根据音频的文件名字来播放音频,后者则是停止播放。
- (void)playAudioWithFileName:(NSString *)filename delegate:(id<PlayingDelegate>)newDelegate { if ( ! filename) { return; } if ([filename rangeOfString:@".spx"].location != NSNotFound) { [[AVAudioSession sharedInstance] setActive:YES error:nil]; [self stopPlaying]; self.delegate = newDelegate; self.decapsulator = [[Decapsulator alloc] initWithFileName:filename]; self.decapsulator.delegate = self; [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; [self.decapsulator play]; //开启距离监听 [self startProximityMonitering]; } else if ([filename rangeOfString:@".mp3"].location != NSNotFound) { if ( ! [[NSFileManager defaultManager] fileExistsAtPath:filename]) { NSLog(@"要播放的文件不存在:%@", filename); [self.delegate playingStoped]; [newDelegate playingStoped]; return; } [self.delegate playingStoped]; self.delegate = newDelegate; NSError *error; self.avAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:filename] error:&error]; if (self.avAudioPlayer) { [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; [[AVAudioSession sharedInstance] setActive:YES error:nil]; self.avAudioPlayer.delegate = self; [self.avAudioPlayer play]; [self startProximityMonitering]; } else { [self.delegate playingStoped]; } } else { [self.delegate playingStoped]; }}
该函数首先判断音频文件是.spx格式的还是.mp3格式,随后通过解析类Decapsulator来解析音频并播放之(与Encapsulator类对应)。再类中还实现了距离监听的功能,当用户脸靠近手机时则会按掉屏幕打开听他,当远离时则打开扬声器屏幕变亮。
总而言之,对好奇想尝试一下开发ios语音的人来说,这几个类绝对是个福音,封装的很好,调用起来也很方便。若想用作开发语音聊天的产品,则需要我们要加深理解他背后压缩与解压缩的的原理了。
- IOS开发之使用Speex格式实现简单的语音聊天功能(二)
- IOS开发之使用Speex格式实现简单的语音聊天功能(二)
- IOS开发之使用Speex格式实现简单的语音聊天功能(一)
- IOS开发之使用Speex格式实现简单的语音聊天功能(一)
- 开源语音格式speex教程(for IOS)
- 开源语音格式speex教程(for IOS)
- 开源语音格式speex教程(for iOS)
- 开源语音格式speex教程(for iOS)
- 开源语音格式speex教程(for IOS)
- 开源语音格式speex教程(for IOS)
- 开源语音格式speex教程(for IOS)
- 开源语音格式speex教程(for iOS)
- 开源语音格式speex教程(for iOS)
- Unity 实现简单的语音聊天 [iOS版本]
- 开源语音格式speex教程-IOS
- IOS语音聊天实现
- iOS 使用XMPP框架开发IM聊天模块,实现简单的文字聊天
- 音频压缩工具——Speex的使用(Android&iOS语音录音技术预演)
- java 排序算法实现 其五:希尔排序
- PAT 1023. Have Fun with Numbers (20)
- 简单的TestNG.xml在Eclipse中跑TestNG suite
- 当今世界十大经典算法
- Css控制显示文本个数
- IOS开发之使用Speex格式实现简单的语音聊天功能(二)
- JAVA文件的上传与下载的例子
- Facebook API学习获取FB用户信息
- sybase的分页处理
- mysqldump导出 触发器,存储过程,事件,函数
- Codility -- PermMissingElem
- 使用 HTML5 webSocket API实现即时通讯的功能
- 安卓各大系统属性设置,及屏幕锁定,点亮屏幕,连接wifi设置
- 使用jQuery中的getJSON()方法获取数据