1. 程式人生 > >iOS 訊飛語音之語音聽寫 錄音的實現

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