123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- //
- // SLNuiSpeechRecognizer.m
- // SLAiELTS
- //
- // Created by Gusont on 2023/3/6.
- //
- #import "SLNuiSpeechRecognizer.h"
- #import <nuisdk/NeoNuiTts.h>
- #import "NLSPlayAudio.h"
- #import "NuiSdkUtils.h"
- #import <nuisdk/NeoNui.h>
- #import "NLSVoiceRecorder.h"
- #import <AdSupport/ASIdentifierManager.h>
- static BOOL save_log = YES;//不加无法保存
- static BOOL save_wav = YES;
- @interface SLNuiSpeechRecognizer()<NeoNuiSdkDelegate, NlsVoiceRecorderDelegate, NlsPlayerDelegate>
- @property(nonatomic,strong) NeoNui* nui;
- @property(nonatomic,strong) NlsVoiceRecorder *voiceRecorder;
- @property(nonatomic,strong) NSMutableData *recordedVoiceData;
- @property(nonatomic,strong) NuiSdkUtils *utils;
- @property(nonatomic,strong) NLSPlayAudio *voicePlayer;
- @property (nonatomic, strong) NSString *recorderStartTime;
- @property (nonatomic, assign) BOOL isSaveVoice;
- @end
- @implementation SLNuiSpeechRecognizer
- - (instancetype)init {
- self = [super init];
- if (self) {
- [self confignSpeechRecognizer];
- }
- return self;
- }
- -(void)dealloc{
- TLog(@"%s",__FUNCTION__);
- [_nui nui_release];
- }
- - (void)confignSpeechRecognizer {
-
- _voicePlayer = [[NLSPlayAudio alloc] init];
- _voicePlayer.delegate = self;
-
- _voiceRecorder = [[NlsVoiceRecorder alloc] init];
- _voiceRecorder.delegate = self;
- [SLAuthorizationManager requestAuthorization:YMAuthorizationTypeMicrophone grantedBlock:^(BOOL granted) {
-
- }];
- _utils = [[NuiSdkUtils alloc] init];
- [self initNui];
- }
- - (void)initNui {
- if (_nui == NULL) {
- _nui = [NeoNui get_instance];
- _nui.delegate = self;
- }
- //请注意此处的参数配置,其中账号相关需要在Utils.m getTicket 方法中填入后才可访问服务
- NSString * initParam = [self genInitParams];
-
- [_nui nui_initialize:[initParam UTF8String] logLevel:LOG_LEVEL_ERROR saveLog:save_log];
- NSString * parameters = [self genParams];
- [_nui nui_set_params:[parameters UTF8String]];
- }
- #pragma mark - 清除文件缓存
- - (void)clearCacheWithFilePath:(NSString *)path {
-
- //拿到path路径的下一级目录的子文件夹
- NSArray *subPathArr = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
- NSString *filePath = nil;
-
- NSError *error = nil;
- for (NSString *subPath in subPathArr)
- {
- filePath = [path stringByAppendingPathComponent:subPath];
- NSArray *subFilePathArr = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:filePath error:nil];
- if (subFilePathArr.count) {
- [self clearCacheWithFilePath:filePath];
- }else {
- if (![filePath containsString:@"origin_0"]) {
- //删除子文件夹
- [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
- }
- }
- }
- }
- -(NSString*) genInitParams {
- NSString *strResourcesBundle = [[NSBundle mainBundle] pathForResource:@"Resources" ofType:@"bundle"];
- NSString *bundlePath = [[NSBundle bundleWithPath:strResourcesBundle] resourcePath];
- NSString *id_string = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
- NSString *debug_path = [_utils createDir];
- dispatch_async(dispatch_queue_create("sl.nuispeech.voices.file", DISPATCH_QUEUE_CONCURRENT), ^{
- [self clearCacheWithFilePath:debug_path];
- });
-
-
- NSMutableDictionary *dictM = [NSMutableDictionary dictionary];
-
- [dictM setObject:bundlePath forKey:@"workspace"];
- [dictM setObject:debug_path forKey:@"debug_path"];
- [dictM setObject:id_string forKey:@"device_id"];
- [dictM setObject:save_wav ? @"true" : @"false" forKey:@"save_wav"];
-
- //从阿里云获取appkey和token进行语音服务访问
- [dictM setObject:SLNuisdkAppKey forKey:@"app_key"];
- // [dictM setObject:SLNuisdkToken forKey:@"token"];
- //由于token 24小时过期,可以参考getTicket实现从阿里云服务动态获取
- [_utils getTicket:dictM];
- [dictM setObject:@"wss://nls-gateway.cn-shanghai.aliyuncs.com:443/ws/v1" forKey:@"url"];
-
- NSData *data = [NSJSONSerialization dataWithJSONObject:dictM options:NSJSONWritingPrettyPrinted error:nil];
- NSString * jsonStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
- return jsonStr;
- }
- -(NSString*) genParams {
- NSMutableDictionary *nls_config = [NSMutableDictionary dictionary];
- [nls_config setValue:@YES forKey:@"enable_intermediate_result"];
- // 参数可根据实际业务进行配置
- // [nls_config setValue:@true forKey:@"enable_punctuation_prediction"];
- // [nls_config setValue:@true forKey:@"enable_inverse_text_normalization"];
- // [nls_config setValue:@true forKey:@"enable_voice_detection"];
- // [nls_config setValue:@10000 forKey:@"max_start_silence"];
- // [nls_config setValue:@800 forKey:@"max_end_silence"];
- // [nls_config setValue:@16000 forKey:@"sample_rate"];
- // [nls_config setValue:@"opus" forKey:@"sr_format"];
- NSMutableDictionary *dictM = [NSMutableDictionary dictionary];
- [dictM setObject:nls_config forKey:@"nls_config"];
- [dictM setValue:@(SERVICE_TYPE_ASR) forKey:@"service_type"];
- // 如果有HttpDns则可进行设置
- // [dictM setObject:[_utils getDirectIp] forKey:@"direct_ip"];
-
- NSData *data = [NSJSONSerialization dataWithJSONObject:dictM options:NSJSONWritingPrettyPrinted error:nil];
- NSString * jsonStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
- return jsonStr;
- }
- #pragma mark - ------语音识别------
- - (void)startSpeechRecognizer {
- NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
- [formatter setDateFormat:@"yyyyMMdd_HHmmss"];
- NSDate *datenow = [NSDate date];
- NSString *currentTimeString = [formatter stringFromDate:datenow];
- self.recorderStartTime = currentTimeString;
- NSLog(@"currentTimeString----%@",currentTimeString);
- self.recordedVoiceData = nil;
- dispatch_async(dispatch_get_main_queue(), ^{
- if (_nui != nil) {
- [_nui nui_dialog_start:MODE_P2T dialogParam:NULL];
- } else {
- TLog(@"in StartButHandler no nui alloc");
- }
- });
- }
- - (void)stopSpeechRecognizer:(BOOL)isSaveVoice {
- self.isSaveVoice = isSaveVoice;
- if (_nui != nil) {
- [_nui nui_dialog_cancel:NO];
- [_voiceRecorder stop:YES];
- } else {
- TLog(@"in StopButHandler no nui alloc");
- }
- }
- #pragma mark - Nui Listener
- -(void)onNuiEventCallback:(NuiCallbackEvent)nuiEvent
- dialog:(long)dialog
- kwsResult:(const char *)wuw
- asrResult:(const char *)asr_result
- ifFinish:(bool)finish
- retCode:(int)code {
- // TLog(@"onNuiEventCallback event %d finish %d", nuiEvent, finish);
- if (nuiEvent == EVENT_ASR_PARTIAL_RESULT || nuiEvent == EVENT_ASR_RESULT) {
- // TLog(@"ASR RESULT %s finish %d", asr_result, finish);
- NSString *result = [NSString stringWithUTF8String:asr_result];
- NSDictionary *dict = [result mj_JSONObject];
- NSDictionary *payloadDict = [dict objectForKey:@"payload"];
- if (finish && self.recognizerResultBlock && self.isSaveVoice) {
- NSString *voicePath = [_utils createDir];
- voicePath = [voicePath stringByAppendingFormat:@"/%@/origin_0.wav", self.recorderStartTime];
- self.recognizerResultBlock([payloadDict objectForKey:@"result"] ?: @"", voicePath);
- }
- }
- else if (nuiEvent == EVENT_ASR_ERROR) {
- // TLog(@"EVENT_ASR_ERROR error[%d]", code);
- } else if (nuiEvent == EVENT_MIC_ERROR) {
- // TLog(@"MIC ERROR");
- [_voiceRecorder stop:true];
- [_voiceRecorder start];
- }
- //
- //finish 为真(可能是发生错误,也可能是完成识别)表示一次任务生命周期结束,可以开始新的识别
- if (finish) {
-
- }
- return;
- }
- -(int)onNuiNeedAudioData:(char *)audioData length:(int)len {
- // TLog(@"onNuiNeedAudioData");
- static int emptyCount = 0;
- @autoreleasepool {
- @synchronized(_recordedVoiceData){
- if (_recordedVoiceData.length > 0) {
- int recorder_len = 0;
- if (_recordedVoiceData.length > len)
- recorder_len = len;
- else
- recorder_len = _recordedVoiceData.length;
- NSData *tempData = [_recordedVoiceData subdataWithRange:NSMakeRange(0, recorder_len)];
- [tempData getBytes:audioData length:recorder_len];
- tempData = nil;
- NSInteger remainLength = _recordedVoiceData.length - recorder_len;
- NSRange range = NSMakeRange(recorder_len, remainLength);
- [_recordedVoiceData setData:[_recordedVoiceData subdataWithRange:range]];
- emptyCount = 0;
- return recorder_len;
- } else {
- if (emptyCount++ >= 50) {
- TLog(@"_recordedVoiceData length = %lu! empty 50times.", (unsigned long)_recordedVoiceData.length);
- emptyCount = 0;
- }
- return 0;
- }
- }
- }
- return 0;
- }
- -(void)onNuiAudioStateChanged:(NuiAudioState)state {
- // TLog(@"onNuiAudioStateChanged state=%u", state);
- if (state == STATE_CLOSE || state == STATE_PAUSE) {
- [_voiceRecorder stop:YES];
- } else if (state == STATE_OPEN){
- self.recordedVoiceData = [NSMutableData data];
- [_voiceRecorder start];
- }
- }
- -(void)onNuiRmsChanged:(float)rms {
- // TLog(@"onNuiRmsChanged rms=%f", rms);
- if (self.onVolumeChangedBlock) {
- self.onVolumeChangedBlock(rms);
- }
- }
- - (void)recorderDidStart {
- TLog(@"recorderDidStart");
- }
- - (void)recorderDidStop {
- [self.recordedVoiceData setLength:0];
- }
- - (void)voiceDidFail:(NSError *)error {
- TLog(@"recorder error ");
- }
- - (void)voiceRecorded:(NSData *)frame {
- @synchronized(_recordedVoiceData){
- [_recordedVoiceData appendData:frame];
- }
- }
- - (void)playerDidFinish {
- NSLog(@"----->>>playerDidFinish");
- }
- @end
|