123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- //
- // PQSpeechTranscriberUtil.m
- // BFFramework
- //
- // Created by ak on 2021/12/8.
- // 说明文档:https://help.aliyun.com/document_detail/173528.html
- #import <Foundation/Foundation.h>
- #import "NeoNui.h"
- #import "PQSpeechTranscriberUtil.h"
- #import <AdSupport/ASIdentifierManager.h>
- #import "NLSVoiceRecorder.h"
- @interface PQSpeechTranscriberUtil ()<NeoNuiSdkDelegate,NlsVoiceRecorderDelegate> {
-
-
- }
- @property(nonatomic,strong) NeoNui* nui;
- @property(nonatomic,strong) NlsVoiceRecorder *voiceRecorder;
- @property(nonatomic,strong) NSMutableData *recordedVoiceData;
- //
- @end
- @implementation PQSpeechTranscriberUtil
- - (id)init {
-
- self = [super init];
-
-
- _voiceRecorder = [[NlsVoiceRecorder alloc] init];
- _voiceRecorder.delegate = self;
-
- [self initNui];
-
- NSString *version = [NSString stringWithUTF8String:[_nui nui_get_version]];
- NSLog(@"nui_get_version is %@",version);
-
-
- return self;
-
-
- }
- /// 开始识别
- - (void)startTranscriber{
-
- if (_nui != nil) {
- [_nui nui_dialog_start:MODE_P2T dialogParam:NULL];
- } else {
- NSLog(@"in StartButHandler no nui alloc");
- }
- }
- /// 结束识别
- - (void)endTranscriber{
- self.recordedVoiceData = nil;
-
- if (_nui != nil) {
- [_nui nui_dialog_cancel:NO];
- [_voiceRecorder stop:YES];
- dispatch_async(dispatch_get_main_queue(), ^{
-
- });
- } else {
- NSLog(@"in StopButHandler no nui alloc");
- }
- }
- //初始化SDK
- - (void) initNui {
- if (_nui == NULL) {
- _nui = [NeoNui get_instance];
- _nui.delegate = self;
- }
- //请注意此处的参数配置,其中账号相关需要在Utils.m getTicket 方法中填入后才可访问服务
- NSString * initParam = [self genInitParams];
-
- int initcode = [_nui nui_initialize:[initParam UTF8String] logLevel:LOG_LEVEL_VERBOSE saveLog:false];
- NSLog(@"初始化结果%d",initcode);
-
- NSString * parameters = [self genParams];
- int setparamscode = [_nui nui_set_params:[parameters UTF8String]];
-
- NSLog(@"设置参数结果%d",setparamscode);
- }
- //析构SDK
- - (void)terminateNui {
- [_nui nui_release];
- }
- //Get Document Dir
- -(NSString *)dirDoc {
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
- NSString *documentsDirectory = [paths objectAtIndex:0];
- NSLog(@"app_home_doc: %@",documentsDirectory);
- return documentsDirectory;
- }
- //create dir for saving files
- -(NSString *)createDir {
- NSString *documentsPath = [self dirDoc];
- NSFileManager *fileManager = [NSFileManager defaultManager];
- NSString *testDirectory = [documentsPath stringByAppendingPathComponent:@"voices"];
- // 创建目录
- BOOL res=[fileManager createDirectoryAtPath:testDirectory withIntermediateDirectories:YES attributes:nil error:nil];
- if (res) {
- NSLog(@"文件夹创建成功");
- }else
- NSLog(@"文件夹创建失败");
- return testDirectory;
- }
- -(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 = [self createDir];
- //
- 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:@"false" forKey:@"save_wav"];
-
- //从阿里云获取appkey和token进行语音服务访问
- [dictM setObject:@"oTOh8zDVK6iswF9o" forKey:@"app_key"];
- [dictM setObject:@"7968a3cc7e8d4b87936bacd85211887b" 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 {
- //https://help.aliyun.com/document_detail/173528.html 参数说明
- NSMutableDictionary *nls_config = [NSMutableDictionary dictionary];
- //是否返回中间识别结果,默认值:False。
- [nls_config setValue:@YES forKey:@"enable_intermediate_result"];
-
- //是否在后处理中添加标点,默认值:False
- [nls_config setValue:@YES forKey:@"enable_punctuation_prediction"];
- //是否在后处理中执行ITN。设置为true时,中文数字将转为阿拉伯数字输出,默认值:False。
- [nls_config setValue:@YES forKey:@"enable_inverse_text_normalization"];
- [nls_config setValue:@YES forKey:@"enable_voice_detection"];
- [nls_config setValue:@10000 forKey:@"max_start_silence"];
- [nls_config setValue:@800 forKey:@"max_end_silence"];
- //语音断句检测阈值,静音时长超过该阈值被认为断句。取值范围:200ms~2000ms,默认值:800ms。
- [nls_config setValue:@800 forKey:@"max_sentence_silence"];
- //是否开启返回词信息。默认值:False。
- [nls_config setValue:@NO forKey:@"enable_words"];
- [nls_config setValue:@16000 forKey:@"sample_rate"];
- //音频编码格式,支持OPUS编码和PCM原始音频。默认值:OPUS。
- [nls_config setValue:@"opus" forKey:@"sr_format"];
-
- //ADD BY AK
- [nls_config setValue:@YES forKey:@"enable_sentence_detection"];
-
-
- NSMutableDictionary *dictM = [NSMutableDictionary dictionary];
- [dictM setObject:nls_config forKey:@"nls_config"];
- [dictM setValue:@(SERVICE_TYPE_SPEECH_TRANSCRIBER) 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 - Voice Recorder Delegate
- -(void) recorderDidStart{
- NSLog(@"recorderDidStart");
- }
- -(void) recorderDidStop{
- [self.recordedVoiceData setLength:0];
- NSLog(@"recorderDidStop");
- }
- -(void) voiceRecorded:(NSData*) frame{
- @synchronized(_recordedVoiceData){
- [_recordedVoiceData appendData:frame];
- }
- }
- -(void) voiceDidFail:(NSError*)error{
- NSLog(@"recorder error ");
- }
- #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 {
- NSLog(@"onNuiEventCallback event %d finish %d", nuiEvent, finish);
- if (nuiEvent == EVENT_ASR_PARTIAL_RESULT || nuiEvent == EVENT_ASR_RESULT || nuiEvent == EVENT_SENTENCE_END) {
-
- NSString *result = [NSString stringWithUTF8String:asr_result];
- NSLog(@"识别结果: %@ finish %d", result, finish);
-
- if (self.delegate && [self.delegate respondsToSelector:@selector(eventCallback:asrResult:)])
- {
- [self.delegate eventCallback:self asrResult:result];
- }
-
- } else if (nuiEvent == EVENT_ASR_ERROR) {
- NSLog(@"EVENT_ASR_ERROR error[%d]", code);
- } else if (nuiEvent == EVENT_MIC_ERROR) {
- NSLog(@"MIC ERROR");
- [_voiceRecorder stop:YES];
- [_voiceRecorder start];
- }
-
- //finish 为真(可能是发生错误,也可能是完成识别)表示一次任务生命周期结束,可以开始新的识别
- if (finish) {
- dispatch_async(dispatch_get_main_queue(), ^{
-
- });
- }
-
- return;
- }
- //录音数据回调,在该回调中填充录音数据。
- -(int)onNuiNeedAudioData:(char *)audioData length:(int)len {
- 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) {
- NSLog(@"_recordedVoiceData length = %lu! empty 50times.", (unsigned long)_recordedVoiceData.length);
- emptyCount = 0;
- }
- return 0;
- }
-
- }
- }
- return 0;
- }
- -(void)onNuiAudioStateChanged:(NuiAudioState)state{
- NSLog(@"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 {
- NSLog(@"onNuiRmsChanged rms=%f", rms);
- }
- @end
|