最近发现一直在用的百度AI语音合成接口悄悄咪咪把每日配额从上万次降到零了,逼着用户掏钱买昂贵套餐,于是来看看科大讯飞。
讯飞的语音合成(文字转语音)技术一贯很强,官网demo能试用一百多种发音人,每种都很有特点,甚至还有方言和外语发音人,不过免费API只能使用5种干巴巴的基础发音人。
如果我是轻度用户,不通过API而是直接使用demo网页合成并下载语音到本地,可以吗?
打开Chrome控制台研究了一会发现没那么简单,network的media页签下没有发现音频资源。再看ws页签,发现点击“立即合成”按钮后这里有大量数据传输,原来websocket服务端将一条语音拆分成上百条经过Base64编码的分片传输给前端,前端再调用浏览器的Web Audio API来顺序的播放这些分片… 这么做的目的应该是为了让语音能够尽快开始播放,不必等整个音频文件都生成好并且传输到客户端才开始播放,另外还能防止音频文件被人抓取。
我的目的是自由下载合成后的语音,研究过前端js代码后,我想到一个简单粗暴的解决方案:录音。
Chrome浏览器需要开启Local overrides,将js的关键部位魔改后替代原本的js文件,魔改的思路是:语音开始播放时自动开始录音,语音播放完毕后自动停止录音并保存音频文件到本地。顺便把一些特色发音人自带的背景音乐去掉了,讯飞在特色发音人朗读时添加了一些用户不需要的背景音乐,目的可能也是劣化体验避免被录音或抓取吧。
感谢现代浏览器提供的高级特性,使原本复杂的问题可以简单解决,录音这里利用了MediaDevices接口以及它下面的getDisplayMedia API。这里一开始还错用了getUserMedia API,回放时感觉音质好差,结果发现是录到了麦克风的声音,改用getDisplayMedia才实现了高音质的内录,但getDisplayMedia无法单独采集音频,传参时必须{video: true, audio: true}
才能实现录音。
完整的魔改后js文件在这里,所有的修改部位都有//
单行注释。
已知的小缺陷:使用getUserMedia或getDisplayMedia创建的webm音频文件缺失元信息,所以播放时音频总时长会显示一个错误的值,在不同的播放器上有可能是0秒有可能是435小时,但并不影响播放,播完也能正常停止。
接下来我打算有空闲时写一个单行的JavaScript脚本,能添加到chrome书签,在任意网站点击这个书签可以出现一个悬浮的录屏/录音控制台,用户可以选择录屏或录音,自由的选择开始和结束时机,录完下载到本地,还要支持快捷键。也许挺好玩的。