iOS 訊飛語音之語音聽寫 錄音的實現
引入庫
第一步 獲取appid
appid是第三方應用整合訊飛開放平臺SDK的身份標識,SDK靜態庫和appid是繫結的,每款應用必須保持唯一,否則會出現10407錯誤碼。appid在開放平臺申請應用時可以獲得,下載SDK後可從SDK中sample資料夾的Demo工程裡找到(例如: /sample/MSCDemo/MSCDemo/Definition.h 的APPID_VALUE)
第二步 工程配置
引入庫
將開發工具包中lib目錄下的iflyMSC.framework新增到工程中,同時請將Demo中依賴的其他庫也新增到工程中。 按下圖示例新增 SDK 所需要的 iOS系統庫:
注意:
1 .新增iflyMSC.framework時,請檢查工程BuildSetting中的framwork path的設定,如果出現找不到framework的情況,可以將path清空,在Xcode中刪除framework,然後重新新增。
2 .iflyMSC.framework最低支援iOS 8.0。
3 .如果使用aiui,需要新增libicucord.tbd。
設定bitcode
在Xcode 7,8預設開啟了Bitcode,而Bitcode 需要工程依賴的所有類庫同時支援。MSC SDK暫時還不支援Bitcode,可以先臨時關閉。後續MSC SDK支援Bitcode 時,會在訊飛開放平臺上進行SDK版本更新,QQ支援群中同時會有相關提醒,請關注。關閉此設定,只需在Targets - Build Settings 中搜索Bitcode 即可,找到相應選項,設定為NO。
使用者隱私許可權配置
iOS 10釋出以來,蘋果為了使用者資訊保安,加入隱私許可權設定機制,讓使用者來選擇是否允許。 隱私許可權配置可在info.plist 新增相關privacy欄位,MSC SDK中需要用到的許可權主要包括麥克風許可權、聯絡人許可權和地理位置許可權:
<key>NSMicrophoneUsageDescription</key> <string></string> <key>NSLocationUsageDescription</key> <string></string> <key>NSLocationAlwaysUsageDescription</key> <string></string> <key>NSContactsUsageDescription</key> <string></string>
即在Info.plist 中增加下圖設定
第三步初始化
//Appid是應用的身份資訊,具有唯一性,初始化時必須要傳入Appid。
NSString *initString = [[NSString alloc] initWithFormat:@"appid=%@", @"YourAppid"];
[IFlySpeechUtility createUtility:initString];
線上語音識別
_iFlySpeechRecognizer = [IFlySpeechRecognizer sharedInstance];
_iFlySpeechRecognizer.delegate = self;
//設定識別引數
//設定為聽寫模式
[_iFlySpeechRecognizer setParameter: @"iat" forKey: [IFlySpeechConstant IFLY_DOMAIN]];
//asr_audio_path 是錄音檔名,設定value為nil或者為空取消儲存,預設儲存目錄在Library/cache下。
[_iFlySpeechRecognizer setParameter:nil forKey:[IFlySpeechConstant ASR_AUDIO_PATH]];
[_iFlySpeechRecognizer setParameter:@"20000" forKey:[IFlySpeechConstant NET_TIMEOUT]];
//設定是否返回標點符號
[_iFlySpeechRecognizer setParameter:@"0" forKey:[IFlySpeechConstant ASR_PTT]];
// //設定語音後端點:後端點靜音檢測時間,即使用者停止說話多長時間內即認為不再輸入, 自動停止錄音
// [_iFlySpeechRecognizer setParameter:@"10000" forKey:[IFlySpeechConstant VAD_EOS]];
//設定語音前端點:靜音超時時間,即使用者多長時間不說話則當做超時處理
[_iFlySpeechRecognizer setParameter:@"10000" forKey:[IFlySpeechConstant VAD_BOS]];
控制器遵循IFlySpeechRecognizerDelegate協議,
實現協議方法
/*!
* 識別結果回撥
*
* 在進行語音識別過程中的任何時刻都有可能回撥此函式,你可以根據errorCode進行相應的處理,當errorCode沒有錯誤時,表示此次會話正常結束;否則,表示此次會話有錯誤發生。特別的當呼叫`cancel`函式時,引擎不會自動結束,需要等到回撥此函式,才表示此次會話結束。在沒有回撥此函式之前如果重新呼叫了`startListenging`函式則會報錯誤。
*
* @param errorCode 錯誤描述
*/
- (void) onCompleted:(IFlySpeechError *) errorCode;
/*!
* 識別結果回撥
*
* 在識別過程中可能會多次回撥此函式,你最好不要在此回撥函式中進行介面的更改等操作,只需要將回調的結果儲存起來。<br>
* 使用results的示例如下:
* <pre><code>
* - (void) onResults:(NSArray *) results{
* NSMutableString *result = [[NSMutableString alloc] init];
* NSDictionary *dic = [results objectAtIndex:0];
* for (NSString *key in dic){
* [result appendFormat:@"%@",key];//合併結果
* }
* }
* </code></pre>
*
* @param results -[out] 識別結果,NSArray的第一個元素為NSDictionary,NSDictionary的key為識別結果,sc為識別結果的置信度。
* @param isLast -[out] 是否最後一個結果
*/
- (void) onResults:(NSArray *) results isLast:(BOOL)isLast;
開始識別:
[_iFlySpeechRecognizer startListening];
結束識別:
[self.iFlySpeechRecognizer stopListening];
因為語音識別返回的格式都是下邊的樣式:
{"sn":1,"ls":true,"bg":0,"ed":0,"ws":[{"bg":0,"cw":[{"w":"呵呵","sc":0}]},{"bg":0,"cw":[{"w":"哈哈","sc":0}]},{"bg":0,"cw":[{"w":"。","sc":0}]}]}
所以要解析資料:
- (NSString *)stringFromJson:(NSString*)params
{
if (params == NULL) {
return nil;
}
NSMutableString *tempStr = [[NSMutableString alloc] init];
NSDictionary *resultDic = [NSJSONSerialization JSONObjectWithData: //返回的格式必須為utf8的,否則發生未知錯誤
[params dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
if (resultDic!= nil) {
NSArray *wordArray = [resultDic objectForKey:@"ws"];
for (int i = 0; i < [wordArray count]; i++) {
NSDictionary *wsDic = [wordArray objectAtIndex: i];
NSArray *cwArray = [wsDic objectForKey:@"cw"];
for (int j = 0; j < [cwArray count]; j++) {
NSDictionary *wDic = [cwArray objectAtIndex:j];
NSString *str = [wDic objectForKey:@"w"];
[tempStr appendString: str];
}
}
}
return tempStr;
}
注意設定等待時間,預設_iFlySpeechRecognizer等待時間是5s,也就是5s之內檢測不到說話的聲音,就會自動關閉
離線語音識別
[self.iFlySpeechRecognizer startListening];
[self.iFlySpeechRecognizer writeAudio:[NSData dataWithContentsOfURL:[NSURL fileURLWithPath:pat]]];
[self.iFlySpeechRecognizer stopListening];
pat是指語音檔案的路徑,也是在上邊提到的協議的基礎上,資料會通過協議返回,但是需要注意的是,不能連續不間隔的實現多個語音檔案,需要間隔1s或者其他的時間,連續不間隔的實現識別多個語音會出問題
錄音的實現
因為訊飛只有在線的情況才可以錄音,並且錄音的路徑是固定的無法改變,所以自己寫一個錄音控制器,最好自己寫一個專門的Record管理檔案,因為錄音路徑需要記下來
h檔案
#import <Foundation/Foundation.h>
@interface RecordHelper : NSObject
- (void)startRecord:(NSString *)path;
- (void)stopRecord;
@end
m檔案的實現
#import "RecordHelper.h"
#import <AVFoundation/AVFoundation.h>
@interface RecordHelper()
@property (nonatomic , strong) AVAudioSession *session;
@property (nonatomic , strong) AVAudioRecorder *recorder;
@property (nonatomic , strong) NSURL *recordFileUrl;
@end
@implementation RecordHelper
- (void)startRecord:(NSString *)path{
[self session];
//獲取檔案路徑
self.recordFileUrl = [NSURL fileURLWithPath:path];
//設定引數
NSDictionary *recordSetting = [[NSDictionary alloc] initWithObjectsAndKeys:
//取樣率 8000/11025/22050/44100/96000(影響音訊的質量)
[NSNumber numberWithFloat: 8000.0],AVSampleRateKey,
// 音訊格式
[NSNumber numberWithInt: kAudioFormatLinearPCM],AVFormatIDKey,
//取樣位數 8、16、24、32 預設為16
[NSNumber numberWithInt:16],AVLinearPCMBitDepthKey,
// 音訊通道數 1 或 2
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
//錄音質量
[NSNumber numberWithInt:AVAudioQualityHigh],AVEncoderAudioQualityKey,
nil];
_recorder = [[AVAudioRecorder alloc] initWithURL:self.recordFileUrl settings:recordSetting error:nil];
if (_recorder) {
_recorder.meteringEnabled = YES;
[_recorder prepareToRecord];
[_recorder record];
}else{
NSLog(@"音訊格式和檔案儲存格式不匹配,無法初始化Recorder");
}
}
- (void)stopRecord{
if ([self.recorder isRecording]) {
[self.recorder stop];
_recorder = nil;
}
NSFileManager *manager = [NSFileManager defaultManager];
if ([manager fileExistsAtPath:[self.recordFileUrl path]]){
NSLog(@"錄音成功");
}else{
NSLog(@"錄音失敗");
}
}
- (AVAudioSession *)session{
if(!_session){
_session = [AVAudioSession sharedInstance];
NSError *sessionError;
[_session setCategory:AVAudioSessionCategoryRecord error:&sessionError];
if (_session == nil) {
NSLog(@"Error creating session: %@",[sessionError description]);
}else{
[_session setActive:YES error:nil];
}
}
return _session;
}
@end
注意:需要自己建立資料夾,該類不會根據路徑自己建立資料夾,路徑裡面包含檔案格式例如.wav, .pcm