美文网首页
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