iOS 文章详情H5界面文字内容语音播报(TTS)

前言

为了满足需求, 关爱老年人, 在文章详情页添加字体放大缩小功能之后, 又要增加语音报告功能。在中国人口老年化的大背景下, 总结 iOS 语音播报功能, 写下了这篇文章。

简单语音合成播报Demo代码

正文

文本转语音技术, 也叫TTS, 是Text To Speech的缩写.

一、语音播报相关属性介绍

内容文本转语音播报, 需要使用到AVFoundation框架中的 AVSpeechSynthesizer 和 AVSpeechUtterance 这两个关键类。

// 合成器 控制播放,暂停
@property(nonatomic,strong) AVSpeechSynthesizer * synthesizerAV;
// 实例化发声的对象,及朗读的内容,可以控制说话的语速 等
@property(nonatomic,strong) AVSpeechUtterance *utterance;

按住command点击AVSpeechSynthesizer可以看到

//将发声的对象添加到合成器队列中, 开始语音播报
- (void)speakUtterance:(AVSpeechUtterance *)utterance;
//停止结束语音播报
- (BOOL)stopSpeakingAtBoundary:(AVSpeechBoundary)boundary;
//暂停语音播报
- (BOOL)pauseSpeakingAtBoundary:(AVSpeechBoundary)boundary;
//继续语音播报
- (BOOL)continueSpeaking;

AVSpeechSynthesizerDelegate代理方法

#pragma mark - AVSpeechSynthesizerDelegate
//已经开始
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didStartSpeechUtterance:(AVSpeechUtterance *)utterance{

}
//已经说完
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didFinishSpeechUtterance:(AVSpeechUtterance *)utterance{

//如果朗读要循环朗读,可以在这里再次调用朗读方法
//[_avSpeaker speakUtterance:utterance];
}
//已经暂停
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didPauseSpeechUtterance:(AVSpeechUtterance *)utterance{

}
//已经继续说话
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didContinueSpeechUtterance:(AVSpeechUtterance *)utterance{

}
//已经取消说话
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didCancelSpeechUtterance:(AVSpeechUtterance *)utterance{

}
//将要说某段话
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer willSpeakRangeOfSpeechString:(NSRange)characterRange utterance:(AVSpeechUtterance *)utterance{

}

按住command点击AVSpeechSynthesizer可以看到

//实例化发声的对象,设置需要发声内容
+ (instancetype)speechUtteranceWithString:(NSString *)string;
//设置合成语音的语言 defaults to your system language
@property(nonatomic, retain, nullable) AVSpeechSynthesisVoice *voice;
//设置语速 0.0f~1.0f
//Values are pinned between AVSpeechUtteranceMinimumSpeechRate and AVSpeechUtteranceMaximumSpeechRate.
@property(nonatomic) float rate;              
//声音的音调 0.5f~2.0f  [0.5 - 2] Default = 1
@property(nonatomic) float pitchMultiplier;  
 //设置朗读的音量 [0-1] Default = 1
@property(nonatomic) float volume;          

语言种类 : Language

ar-SA 沙特阿拉伯(阿拉伯文)
en-ZA, 南非(英文)
nl-BE, 比利时(荷兰文)
en-AU, 澳大利亚(英文)
th-TH, 泰国(泰文)
de-DE, 德国(德文)
en-US, 美国(英文)
pt-BR, 巴西(葡萄牙文)
pl-PL, 波兰(波兰文)
en-IE, 爱尔兰(英文)
el-GR, 希腊(希腊文)
id-ID, 印度尼西亚(印度尼西亚文)
sv-SE, 瑞典(瑞典文)
tr-TR, 土耳其(土耳其文)
pt-PT, 葡萄牙(葡萄牙文)
ja-JP, 日本(日文)
ko-KR, 南朝鲜(朝鲜文)
hu-HU, 匈牙利(匈牙利文)
cs-CZ, 捷克共和国(捷克文)
da-DK, 丹麦(丹麦文)
es-MX, 墨西哥(西班牙文)
fr-CA, 加拿大(法文)
nl-NL, 荷兰(荷兰文)
fi-FI, 芬兰(芬兰文)
es-ES, 西班牙(西班牙文)
it-IT, 意大利(意大利文)
he-IL, 以色列(希伯莱文,阿拉伯文)
no-NO, 挪威(挪威文)
ro-RO, 罗马尼亚(罗马尼亚文)
zh-HK, 香港(中文)
zh-TW, 台湾(中文)
sk-SK, 斯洛伐克(斯洛伐克文)
zh-CN, 中国(中文)
ru-RU, 俄罗斯(俄文)
en-GB, 英国(英文)
fr-FR, 法国(法文)
hi-IN 印度(印度文)

二、文章详情H5界面内容语音播报使用

①添加框架, 导入头文件, 设置代理
添加 AVFoundation 框架

导入头文件

#import<AVFoundation/AVFoundation.h>

设置代理(非必需设置项,看需求)

@interface ViewController ()<AVSpeechSynthesizerDelegate>
②创建对象
// 合成器 控制播放,暂停
@property(nonatomic,strong) AVSpeechSynthesizer * synthesizerAV;
// 实例化发声的对象,及朗读的内容,可以控制说话的语速 等
@property(nonatomic,strong) AVSpeechUtterance *utterance;

这地方模拟H5界面文章详情内容

//模拟服务器返回数据
    NSString *content = @"<p>  日前,湖北邮政公司党组对全省邮政企业30个红旗支局党支部开展了示范引领“回头看”检查,检查指标涉及党员“三亮”载体覆盖率、业务收入增幅等10项党建工作及经营管理指标。检查结果显示,全省邮政企业30个红旗党支部示范引领作用十分明显,主要表现为三个方面:一是党建工作真正落地。全省邮政企业30个红旗支局党支部扎实开展了“三亮三比三创”活动,充分发挥了党员的先锋模范作用,党员劳动竞赛完成率均在100%以上,党员“三亮”载体覆盖率均为100%。同时,各支部明确了特色支部的建设方向,加强了党员队伍建设。二是业务收入快速增长。全省邮政企业30个红旗支局党支部所在支局共实现业务收入2。15亿元,净增业务收入2660万元,平均增幅16。5%,其中武汉市江夏区城关支局党支部所在支局业务收入增幅达46%、荆门市沙洋县沈集支局党支部所在支局业务收入增幅达37。95%、孝感市肖港支局党支部所在支局业务收入增幅达30。2%,收入增长势头喜人;人均劳动生产率达到37。26万元,其中孝感市三汊支局党支部、胡金店支局党支部、肖港支局党支部所在支局劳动生产率分别达到59万元、58。4万元、57。5万元,业绩表现突出。三是储蓄余额规模快速扩张。全省邮政企业30个红旗支局党支部所在支局累计储蓄余额规模达到198。49亿元,1-7月份新增储蓄余额过亿的有11个支局,其中武汉市韩家墩支局党支部、钟家村支局党支部以及青山区钢花支局党支部所在支局新增储蓄余额分别达到4。89亿元、2。51亿元和2。12亿元,储蓄余额增长势头强劲。<br></p>";
    //去除HTML标签处理
    NSString *contentStr = [self filterHTML:content];
    //将Unicode转变为字符串时"."->"。",需要替换字符
    NSString *contentString = [contentStr stringByReplacingOccurrencesOfString:@"。" withString:@"."];

在服务器返回的内容content中有HTML标签需要去除,使用下面方法 :

//处理HTML标签
-(NSString *)filterHTML:(NSString *)html
{
    NSScanner * scanner = [NSScanner scannerWithString:html];
    NSString * text = nil;
    while([scanner isAtEnd]==NO)
    {
        [scanner scanUpToString:@"<" intoString:nil];
        [scanner scanUpToString:@">" intoString:&text];
        html = [html stringByReplacingOccurrencesOfString:[NSString stringWithFormat:@"%@>",text] withString:@""];
    }
    return html;
}

创建语音播报对象

_synthesizerAV = [[AVSpeechSynthesizer alloc] init];
_utterance = [AVSpeechUtterance speechUtteranceWithString:contentString];
③设置相关属性
// 语速 0.0f~1.0f   AVSpeechUtteranceMaximumSpeechRate / 4.0f;
_utterance.rate = 0.45f;
// 声音的音调 0.5f~2.0f
_utterance.pitchMultiplier = 0.8f;
//设置合成语音的语言 defaults to your system language   zh-TW  zh-CN
_utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"];
//设置朗读的音量 [0-1] Default = 1
_utterance.volume = 0.8;
④开始、暂停/继续、结束
开始文章内容朗读播报
[_synthesizerAV speakUtterance:_utterance];
暂停朗读播报
//暂停朗读
//AVSpeechBoundaryImmediate 立即停止
//AVSpeechBoundaryWord    当前词结束后停止
[_synthesizerAV pauseSpeakingAtBoundary:AVSpeechBoundaryImmediate];
继续朗读播报
[_synthesizerAV continueSpeaking];
结束朗读播报
//AVSpeechBoundaryImmediate 立即停止
//AVSpeechBoundaryWord    当前词结束后停止
[_synthesizerAV stopSpeakingAtBoundary:AVSpeechBoundaryImmediate];
⑤实现后台播放

1.在配置里设置

2.在AppDelegate.m里添加代码

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *error = nil;
[session setCategory:AVAudioSessionCategoryPlayback error:&error];
[session setActive:YES error:&error];
[Bmob registerWithAppKey:BMOB_AppID];
return YES;
}

小知识点

iOS7之后才有该功能, 不过现在Xcode 8最低支持就是iOS 8.0了。

后记

除了选择系统的语音播报, 当然你还可以选择讯飞的文字转语音技术,不过它受网络的影响比较大,而且离线转语音价格比较贵,最便宜的要8000RMB/2000装机量。

还有一种是使用 百度语音SDK

①下载离在线合成语音包
②记住这3个key
③查看官方示例Demo, 实现播放和设置声音代码
-(void)configureSDK{
    NSLog(@"TTS version info: %@", [BDSSpeechSynthesizer version]);
    [BDSSpeechSynthesizer setLogLevel:BDS_PUBLIC_LOG_VERBOSE];
    [[BDSSpeechSynthesizer sharedInstance] setSynthesizerDelegate:self];
    [self configureOnlineTTS];
    [self configureOfflineTTS];
}
// 配置在线
-(void)configureOnlineTTS{
    //#error "Set api key and secret key"
    [[BDSSpeechSynthesizer sharedInstance] setApiKey:@"e7QA3FWob8EbzLDP7I6fCtcY" withSecretKey:@"17d90e1974d0bcb31725245f96718e73"];
}
// 配置离线
-(void)configureOfflineTTS{
    NSString offlineEngineSpeechData = [[NSBundle mainBundle] pathForResource:@"Chinese_Speech_Female" ofType:@"dat"];
    NSString offlineEngineTextData = [[NSBundle mainBundle] pathForResource:@"Chinese_Text" ofType:@"dat"];
    NSString offlineEngineEnglishSpeechData = [[NSBundle mainBundle] pathForResource:@"English_Speech_Female" ofType:@"dat"];
    NSString offlineEngineEnglishTextData = [[NSBundle mainBundle] pathForResource:@"English_Text" ofType:@"dat"];
    NSString offlineEngineLicenseFile = [[NSBundle mainBundle] pathForResource:@"offline_engine_tmp_license" ofType:@"dat"];
    //#error "set offline engine license"
    NSError err = [[BDSSpeechSynthesizer sharedInstance] loadOfflineEngine:offlineEngineTextData speechDataPath:offlineEngineSpeechData licenseFilePath:offlineEngineLicenseFile withAppCode:@"9353239"]; //
    if (err) {
        return;
    }
    err = [[BDSSpeechSynthesizer sharedInstance] loadEnglishDataForOfflineEngine:offlineEngineEnglishTextData speechData:offlineEngineEnglishSpeechData];
    if (err) {
        return;
    }
}
// 播放失败
-(void)synthesizerErrorOccurred:(NSError *)error speaking:(NSInteger)SpeakSentence synthesizing:(NSInteger)SynthesizeSentence{
    [[BDSSpeechSynthesizer sharedInstance] cancel];
}
// 合成参数设置
// 声音
[[BDSSpeechSynthesizer sharedInstance] setSynthesizerParam:[NSNumber numberWithInt:BDS_SYNTHESIZER_SPEAKER_FEMALE] forKey:BDS_SYNTHESIZER_PARAM_SPEAKER ];
// 音量
[[BDSSpeechSynthesizer sharedInstance] setSynthesizerParam:[NSNumber numberWithInt:5] forKey:BDS_SYNTHESIZER_PARAM_VOLUME];
// 音速
[[BDSSpeechSynthesizer sharedInstance] setSynthesizerParam:[NSNumber numberWithInt:5] forKey:BDS_SYNTHESIZER_PARAM_SPEED];
// 音调
 [[BDSSpeechSynthesizer sharedInstance] setSynthesizerParam:[NSNumber numberWithInt:5] forKey:BDS_SYNTHESIZER_PARAM_PITCH];
// 压缩
[[BDSSpeechSynthesizer sharedInstance] setSynthesizerParam:[NSNumber numberWithInt: BDS_SYNTHESIZER_AUDIO_ENCODE_MP3_16K] forKey:BDS_SYNTHESIZER_PARAM_AUDIO_ENCODING ];

我是楚简约,感谢您的阅读,

喜欢就点个赞呗,“❤喜欢”,

鼓励一下,你在看,我就继续写~

非简书用户,可以点右上角的三个“...”,然后"在Safari中打开”,就可以点赞咯~


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,978评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,954评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,623评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,324评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,390评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,741评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,892评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,655评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,104评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,569评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,254评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,834评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,725评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,950评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,260评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,446评论 2 348

推荐阅读更多精彩内容