美文网首页
iOS12.1语音播报问题

iOS12.1语音播报问题

作者: MrLuJincang | 来源:发表于2018-11-13 18:15 被阅读2725次

    问题描述:
    业物需求,需要使用类似支付宝收款到账的通知,之前采用iOS10.0的原线上ServiceExtension进行收到通知修改通知内容然后采用系统AVSpeechSynthesizer 进行播放,iOS10-12.1之前通知一切正常,当12.1一更新之后APP通知会只有通知栏没有通知语音,因此查阅文档采坑终于找到了解决方案 ,时间短任务重没时间写太多,写文章半小时前刚搞定,所以暂时先附上代码有需要的先解决,之后再修改详细文章。

    解决思想

    1.先使用讯飞语音合成SDK将文字转化为PCM格式文件(讯飞只支持这玩意)

    2.然后用lame工具转为MP3格式

    3.使用AudioService进行MP3播放(试过其他播放方式不行。。。)

    代码(先凑合看后续更新)

    //  NotificationService.m
    //  JZServiceExtension
    //
    //  Created by Jincang Lu on 2018/11/13.
    //  Copyright © 2018年 shanghai KaoPush Network Technology Co., Ltd. All rights reserved.
    //
    
    #import "NotificationService.h"
    #import <AVFoundation/AVFoundation.h>
    #import <iflyMSC/iflyMSC.h>
    #import "lame.h"
    #define kTime 0.6
    static SystemSoundID soundID = 10;
    #define IF_APPID                            @"自己申请"
    
    API_AVAILABLE(ios(10.0))
    @interface NotificationService ()<AVSpeechSynthesizerDelegate,IFlySpeechSynthesizerDelegate>
    
    @property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
    @property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
    @property (nonatomic, strong) IFlySpeechSynthesizer *iFlySpeechSynthesizer;
    
    @end
    
    @implementation NotificationService
    
    - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler  API_AVAILABLE(ios(10.0)){
        self.contentHandler = contentHandler;
        self.bestAttemptContent = [request.content mutableCopy];
        
        NSString *initString = [[NSString alloc] initWithFormat:@"appid=%@", IF_APPID];
        [IFlySpeechUtility createUtility:initString];
        
        // Modify the notification content here...
        self.bestAttemptContent.title = [NSString stringWithFormat:@"%@", self.bestAttemptContent.title];
        self.bestAttemptContent.body = [NSString stringWithFormat:@"%@", self.bestAttemptContent.body];
         self.bestAttemptContent.sound = nil;
        [self syntheticVoice:[NSString stringWithFormat:@"%@",self.bestAttemptContent.body]];
    //    self.bestAttemptContent.sound = [UNNotificationSound soundNamed:@"xindong.caf"];
        
    }
    
    
    - (void)syntheticVoice:(NSString *)string {
        
        //获取语音合成单例
        _iFlySpeechSynthesizer = [IFlySpeechSynthesizer sharedInstance];
        //设置协议委托对象
        _iFlySpeechSynthesizer.delegate = self;
        //设置合成参数
        //设置在线工作方式
        [_iFlySpeechSynthesizer setParameter:[IFlySpeechConstant TYPE_CLOUD]
                                      forKey:[IFlySpeechConstant ENGINE_TYPE]];
        //设置音量,取值范围 0~100
        [_iFlySpeechSynthesizer setParameter:@"100"
                                      forKey: [IFlySpeechConstant VOLUME]];
        //发音人,默认为”xiaoyan”,可以设置的参数列表可参考“合成发音人列表”
        [_iFlySpeechSynthesizer setParameter:@"xiaoyan"
                                      forKey: [IFlySpeechConstant VOICE_NAME]];
        //保存合成文件名,如不再需要,设置为nil或者为空表示取消,默认目录位于library/cache下
        [_iFlySpeechSynthesizer setParameter:@"xfffs.pcm"
                                      forKey: [IFlySpeechConstant TTS_AUDIO_PATH]];
        //启动合成会话
        //        [_iFlySpeechSynthesizer startSpeaking: @"接着到账111111111110元"];
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES);
        NSString *path = [paths objectAtIndex:0];
        NSLog(@"psth==%@",path);
        [_iFlySpeechSynthesizer synthesize: string toUri:[NSString stringWithFormat:@"%@/xfffss.pcm",path]];
        
    }
    
    //合成结束
    - (void) onCompleted:(IFlySpeechError *) error {
        NSLog(@"合成完成--%@-%d",error.errorDesc,error.errorCode);
        [self convertToMp3];
        self.contentHandler(self.bestAttemptContent);
    }
    
    
    - (void)convertToMp3
    {
        NSString *fileName = [NSString stringWithFormat:@"/%@.mp3", @"yuyin"];
        NSString *filePath = [[NSHomeDirectory() stringByAppendingFormat:@"/Documents/"] stringByAppendingPathComponent:fileName];
        NSLog(@"%@",filePath);
    //    NSString *mp3Url = [NSURL URLWithString:filePath];
        @try {
            int read,write;
            NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES);
            NSString *path = [paths objectAtIndex:0];
            //只读方式打开被转换音频文件
            FILE *pcm = fopen([[NSString stringWithFormat:@"%@/xfffss.pcm",path] cStringUsingEncoding:1], "rb");
            fseek(pcm, 4 * 1024, SEEK_CUR);//删除头,否则在前一秒钟会有杂音
            //只写方式打开生成的MP3文件
            FILE *mp3 = fopen([filePath cStringUsingEncoding:1], "wb");
            
            const int PCM_SIZE = 8192;
            const int MP3_SIZE = 8192;
            short int pcm_buffer[PCM_SIZE * 2];
            unsigned char mp3_buffer[MP3_SIZE];
            //这里要注意,lame的配置要跟AVAudioRecorder的配置一致,否则会造成转换不成功
            lame_t lame = lame_init();
            lame_set_in_samplerate(lame, 11025.0);//采样率
            lame_set_VBR(lame, vbr_default);
            lame_init_params(lame);
            
            do {
                //以二进制形式读取文件中的数据
                read = (int)fread(pcm_buffer, 2 * sizeof(short int), PCM_SIZE, pcm);
                if (read == 0)
                    write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
                else
                    write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
                
                //二进制形式写数据到文件中  mp3_buffer:数据输出到文件的缓冲区首地址  write:一个数据块的字节数  1:指定一次输出数据块的个数   mp3:文件指针
                fwrite(mp3_buffer, write, 1, mp3);
                
            } while (read != 0);
            
            lame_close(lame);
            fclose(mp3);
            fclose(pcm);
            
        } @catch (NSException *exception) {
            NSLog(@"%@",[exception description]);
        } @finally {
            NSLog(@"MP3生成成功!!!");
            //    NSString *str = [_iFlySpeechSynthesizer parameterForKey:[IFlySpeechConstant TTS_AUDIO_PATH]];
            //    NSString *str = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@/xfff",path] ofType:@"mp3"];
            NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/yuyin.mp3",[NSHomeDirectory() stringByAppendingFormat:@"/Documents/"]]];
            AudioServicesCreateSystemSoundID((__bridge CFURLRef _Nonnull)(url), &soundID);
            AudioServicesPlayAlertSound(soundID);
            AudioServicesPlayAlertSoundWithCompletion(soundID, ^{
                NSLog(@"播放完成");
            });
        }
    }
    
    //合成开始
    - (void) onSpeakBegin {
        
    }
    //合成缓冲进度
    - (void) onBufferProgress:(int) progress message:(NSString *)msg {
        NSLog(@"-----进度---------%@",msg);
    }
    //合成播放进度
    - (void) onSpeakProgress:(int) progress beginPos:(int)beginPos endPos:(int)endPos {
        NSLog(@"====%d==%d=====",beginPos,endPos);
    }
    
    
    
    - (void)serviceExtensionTimeWillExpire {
        // Called just before the extension will be terminated by the system.
        // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
    //    self.contentHandler(self.bestAttemptContent);
    }
    
    
    
    
    
    
    @end```
    
    extension  plist里面需要加就可以播放了 如果音质变化需要自己去调试参数
    <key>UIBackgroundModes</key>
        <array>
            <string>audio</string> 
        </array>
    
    
    QQ 873702616
    
    截止11.16号 支付宝 收钱吧 12.1也没解决此问题 希望大家尽量先不要在这个方法上浪费太多时间了,上边这个方法提交版本会有问题,提供一种解决思路 希望大家有后续方案进行探讨
    

    相关文章

      网友评论

          本文标题:iOS12.1语音播报问题

          本文链接:https://www.haomeiwen.com/subject/mmglfqtx.html