37

声如其闻,DuerOS中的声音播放

 3 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzAwOTcyNzA0OQ%3D%3D&%3Bmid=2658975956&%3Bidx=1&%3Bsn=6ae2a39e1b0a88e8268510f4ec3ce175
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

智能语音设备的特点是语音交互成为人机交互的重要方式,智能语音设备的声音输出摆脱了预置的逻辑,成为了响应式反馈,尤其是对声音输入的响应。在智能语音设备上,基于语音交互的服务被称为技能,通过诸如DBP(DuerOS Bot Platform)开放平台开发技能,进而提供基于语音交互的服务,关于面向DuerOS的技能开发可以参考《 面向接口/协议?看DuerOS的技能开发 》。 

feIJ7zu.jpg!mobile

那么, 技能是在智能语音设备上如何播放声音的呢?

在DuerOS 中,主要提供了三种声音的播放方式:音视频媒体播放,TTS 合成的语音播放 和利用TTS合成的媒体及文本混合播放。

FnuiI3R.jpg!mobile

音视频媒体播放

点播和资源类的技能都采用音视频媒体播放的方式。当技能收到用户请求的意图时,技能在响应中返回音视频媒体播放的指令和媒体资源的url,以及其他的相关内容,在智能语音设备收到技能响应的内容后,即可播放技能制定的资源。

基于AudioPlayer的音频播放

音频资源既可以在有屏语音设备(如小度智能屏系列),也可以在无屏语音设备(如小度音箱系列)上播放,主要是通过AudioPlayer 相关指令完成的。

AudioPlayer指令从技能发送给DuerOS,对端上进行音频资源的播放控制。在DuerOS收到该指令后,会经过一系列处理解析为端上对应的播放指令。在云端下发AudioPlayer指令后,端上开始音频资源播放操作。音频资源播放会触发一系列事件上报到云端。这些指令和事件分别是:

指令或事件 功能解释 AudioPlayer.Play指令 播放 AudioPlayer.Stop指令 停止 AudioPlayer.PlaybackStarted事件 播放开始 AudioPlayer.PlaybackStopped事件 播放暂停。 AudioPlayer.PlaybackFinished事件 播放结束,即一首歌播放完后上报的事件 AudioPlayer.PlaybackNearlyFinished事件 在播放即将结束时上报的事件 AudioPlayer.PlaybackFailed事件 当设备端播放audio item发生错误时上报此事件

AudioPlayer.Play指令是驱动播放音频的核心指令,一般地,使用Play指令时,response需要返回shouldEndSession值为true,使端上关闭麦克风。消息 例如下:

{
    "type": "AudioPlayer.Play",
    "playBehavior": "{{STRING}}"
    "audioItem": {
        "audioItemId": "{{STRING}}",
        "stream": {
            "url": "{{STRING}}",
            "outputSpeech": {
                "type": "{{STRING}}",
                "text": "{{STRING}}",
                "ssml": "{{STRING}}",
                "ttsTemplates": {{TTSTemplateStructure}}
            },
            "streamFormat": "{{STRING}}",
            "offsetInMilliSeconds": {{LONG}},
            "token": "{{STRING}}",
            "progressReportIntervalMs": {{LONG}}
        },
        "playerInfo": {
            "content": {{AudioPlayerInfoContentStructure}},
            "controls": [
                {{ControlStructure}},
                {{ControlStructure}},
                ......
            ]
        }
    }
}

当持续播放音频资源的时候,技能需要监听AudioPlayer.PlaybackNearlyFinished事件,通过playBehavior参数对播放的音频队列进行调整,DuerOS 是通过资源迭代的方式完成多个音频资源间连续播放的。

当然,使用全双工特性时,DuerOS的处理稍有不同,详情可以参见《聊聊“全双工”》。

auIvu23.jpg!mobile

基于VideoPlayer 的视频播放

视频资源只可以在有屏语音设备(如小度智能屏系列)上播放,主要是通过VideoPlayer 相关指令完成的。

VideoPlayer提供了VideoPlayer指令接口和VideoPlayer事件接口。VideoPlayer指令是技能向DuerOS发送的,对视频进行控制的指令,如播放指令、停止播放指令等。DuerOS收到指令后会转化成端上能识别的播放指令,对视频进行相应的控制。VideoPlayer事件是指在视频播放过程中触发一系列事件,DuerOS会将这些事件上报给技能,请求技能进行处理。这些指令和事件分别是:

指令或事件 功能解释 VideoPlayer.Play指令 播放 VideoPlayer.Stop指令 停止 VideoPlayer.ClearQueue指令 用于清除video_player播放队列 VideoPlayer.PlaybackStarted事件 播放开始 VideoPlayer.PlaybackStopped事件 播放暂停 VideoPlayer.PlaybackFinished事件 播放结束,即一个视频播放完后上报的事件 VideoPlayer.PlaybackNearlyFinished事件 在播放即将结束时上报的事件。 VideoPlayer.ProgressReportIntervalElapsed事件 本事件用来统计播放情况。如果Play指令有progressReportIntervalInMilliseconds,则在播放对应video item时,每隔此时间上报本事件。 VideoPlayer.ProgressReportDelayElapsed事件 本事件用来统计播放情况。如果Play指令中有progressReportDelayInMilliseconds,则对应video item播放此时间长后会上报本事件 VideoPlayer.PlaybackStutterStarted事件 在PlaybackStarted事件之后,如果设备端缓冲视频数据慢于播放速度时,会上报此事件。 VideoPlayer.PlaybackStutterFinished事件 PlaybackStutterStarted事件之后,缓冲恢复到正常状态,可重新开始播放时端上会上报本事件。 VideoPlayer.PlaybackPaused事件 视频播放时,如果发生对话/闹钟等行为,则视频播放会暂停,此时,端上会上报PlaybackPaused事件和PlaybackResumed事件。 VideoPlayer.PlaybackResumed事件 视频播放时,如果发生对话/闹钟等行为,则视频播放会暂停,此时,端上会上报PlaybackPaused事件和PlaybackResumed事件。 VideoPlayer.PlaybackQueueCleared事件 设备端处理完ClearQueue指令后会上报此事件。

技能在返回VideoPlayer.Play指令时,对于show设备中控需要补充RenderVideoPlayerInfo指令用于播放器界面的渲染,消息样例如下:

{
    "type": "VideoPlayer.Play",
    "playBehavior": "{{STRING}}"
    "videoItem": {
        "videoItemId": "{{STRING}}",
        "stream": {
            "url": "{{STRING}}",
            "offsetInMilliseconds": {{LONG}},
            "stopPointsInMilliseconds":[
                {{LONG}},
                {{LONG}},
                ...
            ],
            "expiryTime": {{STRING}}
            "progressReport": {
                "progressReportDelayInMilliseconds": {{LONG}},
                "progressReportIntervalInMilliseconds": {{LONG}}
            },
            "token": "{{STRING}}",
            "expectedPreviousToken": {{STRING}}
        }
    }
}

使用VideoPlayer持续播放视频资源的方法与音频资源持续播放的方式类似。

音视频媒体播放是技能播放声音的重要方法,在非资源类技能中也有着广泛的应用。

uUrQZ36.jpg!mobile

基于TTS 的语音播放

音视频资源有着很好的表现力,但面向动态播报的内容预先录制的成本比较高,对于各种各样的文本播报,一般采用TTS 合成的方式完成语音播放。

TTS 的语音播报指令——outputSpeech

outputSpeech是基于TTS的语音播报指令,表示本次返回结果中需要播报的语音信息,消息样例如下:

......

"response" : {
        "outputSpeech" : {
            "type" : "{{STRING}}",
            "text" : "{{STRING}}",
            "ssml" : "{{STRING}}",
        },
        "card" : {},
        "directives" : [],
        "expectSpeech": {{BOOLEAN}},
        "shouldEndSession" : {{BOOLEAN}}
    }

在outputSpeech的指令机构中,TTS合成有如下的类型:

  • PlainText:普通文本。

  • SSML:一种结构化语言,用于辅助描述语音发音声调。

当type取值为PlainText时,该字段为必选字段。长度不能超过256个字符。当type为SSML时,该字段为必选字段,长度不能超过256个字符,SSML 会在下一节“基于TTS的媒体和文本合成播放”中在进行描述。

outputSpeech 的变种——reprompt

在需要用户输入时,如果用户离开了,麦克风没有进行语音的输入,或用户输入的语音请求系统无法解析成技能的任何意图,则可以使用reprompt来播放预置的内容。

reprompt.outputSpeech参数定义与上述outputSpeech的定义一致,消息样例如下:

"response" : {
        "outputSpeech" : {
            "type" : "{{STRING}}",
            "text" : "{{STRING}}",
            "ssml" : "{{STRING}}",
        },
        "reprompt" : {
            "outputSpeech" : {
                "type" : "{{STRING}}",
                "text" : "{{STRING}}",
                "ssml" : "{{STRING}}",
            }
        },
        "card" : {},
        "directives" : [],
        "expectSpeech": {{BOOLEAN}},
        "shouldEndSession" : {{BOOLEAN}}
    }

repromt指令实际上是outputSpeech指令的变种,是一种应用在特定场景的TTS 语音播报。

eQJ32mj.jpg!mobile

长文本的播放

TTS 播报中对文本长度的限制往往被人们所诟病。话术太长往往会被截断,或者在播放的过程中,由于长时间没有用户交互导致session 被关闭,现象就是在TTS 播放一段时间后,技能退出了,用户需要重新打开技能才能继续在技能中交互。

针对长文本的播报,目前DuerOS 提供了两种解决方案:分段持续播放和媒体转换播放。

分段持续播放

既然长文本在播放过程中无法维持session, 那么我们可以把长文本分割成多个短文本,在前一个短文本播放完毕之后,在继续播放下一个短文本,如此类推,实现长文本的持续完整播放。

具体的方式是应用DuerOS 的StreamResponse 特性,StreamResponse 定义了技能在执行过程中,下发部分结果到端上执行,在端执行完这部分结果后,上报事件以获取技能的其它结果,适应于以下场景:技能返回shouldEndSession=false和StreamResponse.SendPart指令。

StreamResponse.SendPart指令告知DuerOS平台本次只返回部分满足结果,期望在StreamResponse.NextRequired事件时继续返回结果。技能在返回本指令时,如果shouldEndSession=true,DuerOS平台将忽略本指令。技能在返回本指令时,如果shouldEndSession=false,DuerOS平台在本次结果执行后,下发StreamResponse.NextRequired事件给技能,消息样例如下:

{
    "type": "StreamResponse.SendPart",
    "token": "{{STRING}}"
}

技能在收到StreamResponse.NextRequired事件后,返回计划内的下一个响应结果, request中事件样例如下:

{
    "type": "StreamResponse.NextRequired",
    "requestId": "{{STRING}}",
    "timestamp": "{{STRING}}",
    "token": "{{STRING}}"
}

StreamResponse.SendPart指令 和StreamResponse.NextRequired事件组成了一种类似迭代器的机制,使技能可以完成长文本的分段发送。

当然,StreamResponse的应用场景还有很多,长文本的TTS播报只是其中的一个典型应用而已。

imAjeeq.jpg!mobile

媒体转换播放

既然长文本的TTS播报受限于长度,那能否将长文本实时在线转换为音频资源,然后采用AudioPlayer.play 指令播放来突破文本长度的限制呢?答案是肯定的。

DuerOS 提供一种在线将文本转化成音频资源的方法,在技能返回Play指令的时候,content为指定schema的tts,DuerOS会进行及时的批量替换。

schema示例如下:

以下是文本“度秘提醒你今天是妈妈的生日” tts://dueros.baidu.com?text=%E5%BA%A6%E7%A7%98%E6%8F%90%E9%86%92%E4%BD%A0%E4%BB%8A%E5%A4%A9%E6%98%AF%E5%A6%88%E5%A6%88%E7%9A%84%E7%94%9F%E6%97%A5&from=标明技能来源&expire=86400

其中参数需要urlencode, php使用rawurlencode函数即可,其他编程语言类似。

  • text:文本长度5k以内

  • from: botid,需要传相关来源

  • expire: 音频地址的保存时间,最多不超过7天,单位是秒

使用每天转换播放长文本的示例如下:

{
    "directive": {
        "header": {
            "messageId": "YXVkaW9fbmV3cysxNjAwMTU2ODI4Xzk2NmExampiMQ==",
            "name": "Play",
            "namespace": "ai.dueros.device_interface.audio_player"
        },
        "payload": {
            "audioItem": {
                "audioItemId": "9696687530282687670",
                "stream": {
                    "expiryTime": "2020-10-01T00:00:00+08:00",
                    "offsetInMilliseconds": 0,
                    "progressReport": {
                        "progressReportIntervalInMilliseconds": 15000
                    },
                    "streamFormat": "AUDIO_MPEG",
                    "token": "eyJib3RfaWQiOiJhdWRpb19uZXdzIiwicmVzdWx0X3Rva2VuIjoiNjk0ODQ2MDY5Mjc0NmYwYjY3YTRhNzI5ZWMwZDE1ZGUiLCJib3RfdG9rZW4iOiI5Njk2Njg3NTMwMjgyNjg3NjcwIiwibGF1bmNoX2lkcyI6WyJhdWRpb19uZXdzIl19",
                    "url": "tts:\/\/dueros.baidu.com?text=%25E9%2598%25AE%25E6%2588%2590%25E5%258F%2591%25E8%25B5%25B4%25E7%2591%259E%25E4%25B8%25BD%25E7%259D%25A3%25E5%25AF%25BC%25E6%25A3%2580%25E6%259F%25A5%25E7%2596%25AB%25E6%2583%2585%25E9%2598%25B2%25E6%258E%25A7%25EF%25BC%259A%25E5%258A%25A1%25E5%25BF%25853%25E6%2597%25A5%25E5%2586%2585%25E5%25AE%258C%25E6%2588%2590%25E5%2585%25A8%25E5%2591%2598%25E6%25A0%25B8%25E9%2585%25B8%25E6%25A3%2580%25E6%25B5%258B%25E3%2580%2582%25E6%258E%258C%25E4%25B8%258A%25E6%2598%25A5%25E5%259F%258E%25E8%25AE%25AF9%25E6%259C%258814%25E6%2597%25A5%25EF%25BC%258C%25E4%25BA%2591%25E5%258D%2597%25E7%259C%2581%25E7%259C%2581%25E5%25A7%2594%25E5%2589%25AF%25E4%25B9%25A6%25E8%25AE%25B0%25E3%2580%2581%25E7%259C%2581%25E9%2595%25BF%25E3%2580%2581%25E7%259C%2581%25E5%25A7%2594%25E7%259C%2581%25E6%2594%25BF%25E5%25BA%259C%25E5%25BA%2594%25E5%25AF%25B9%25E6%2596%25B0%25E5%2586%25A0%25E8%2582%25BA%25E7%2582%258E%25E7%2596%25AB%25E6%2583%2585%25E5%25B7%25A5%25E4%25BD%259C%25E9%25A2%2586%25E5%25AF%25BC%25E5%25B0%258F%25E7%25BB%2584%25E7%25BB%2584%25E9%2595%25BF%25E9%2598%25AE%25E6%2588%2590%25E5%258F%2591%25E8%25B5%25B6%25E8%25B5%25B4%25E5%25BE%25B7%25E5%25AE%258F%25E5%2582%25A3%25E6%2597%258F%25E6%2599%25AF%25E9%25A2%2587%25E6%2597%258F%25E8%2587%25AA%25E6%25B2%25BB%25E5%25B7%259E%25E7%2591%259E%25E4%25B8%25BD%25E5%25B8%2582%25E7%259D%25A3%25E5%25AF%25BC%25E6%25A3%2580%25E6%259F%25A5%25E7%2596%25AB%25E6%2583%2585%25E9%2598%25B2%25E6%258E%25A7%25E5%25B7%25A5%25E4%25BD%259C%25EF%25BC%258C%25E5%25AF%25B9%25E5%25BD%2593%25E5%2589%258D%25E7%2596%25AB%25E6%2583%2585%25E9%2598%25B2%25E6%258E%25A7%25E5%25BD%25A2%25E5%258A%25BF%25E8%25BF%259B%25E8%25A1%258C%25E5%2586%258D%25E5%2588%2586%25E6%259E%2590%25E3%2580%2581%25E5%2586%258D%25E7%25A0%2594%25E5%2588%25A4%25EF%25BC%258C%25E5%25AF%25B9%25E8%25BE%25B9%25E5%25A2%2583%25E7%25AE%25A1%25E6%258E%25A7%25E5%2592%258C%25E9%2598%25B2%25E6%258E%25A7%25E6%258E%25AA%25E6%2596%25BD%25E8%25BF%259B%25E8%25A1%258C%25E5%2586%258D%25E7%25A0%2594%25E7%25A9%25B6%25E3%2580%2581%25E5%2586%258D%25E5%25AE%2589%25E6%258E%2592%25E3%2580%2582%25E5%25BD%2593%25E6%2599%259A%25EF%25BC%258C%25E9%2598%25AE%25E6%2588%2590%25E5%258F%2591%25E4%25B8%258E%25E5%259B%25BD%25E5%25AE%25B6%25E5%258D%25AB%25E7%2594%259F%25E5%2581%25A5%25E5%25BA%25B7%25E5%25A7%2594%25E8%25B5%25B4%25E4%25BA%2591%25E5%258D%2597%25E4%25B8%2593%25E5%25AE%25B6%25E7%25BB%2584%25E8%25BF%259B%25E8%25A1%258C%25E5%25B7%25A5%25E4%25BD%259C%25E5%25BA%25A7%25E8%25B0%2588%25EF%25BC%258C%25E4%25BB%258B%25E7%25BB%258D%25E8%25BE%25B9%25E5%25A2%2583%25E7%2596%25AB%25E6%2583%2585%25E9%2598%25B2%25E6%258E%25A7%25E6%2583%2585%25E5%2586%25B5%25E5%258F%258A%25E5%25A2%2583%25E5%25A4%2596%25E7%2596%25AB%25E6%2583%2585%25E8%25BE%2593%25E5%2585%25A5%25E5%25A4%2584%25E7%25BD%25AE%25E5%25BA%2594%25E5%25AF%25B9%25E5%25B7%25A5%25E4%25BD%259C%25EF%25BC%258C%25E5%2590%25AC%25E5%258F%2596%25E4%25B8%2593%25E5%25AE%25B6%25E7%25BB%2584%25E5%25AF%25B9%25E5%25BA%2594%25E6%2580%25A5%25E5%2593%258D%25E5%25BA%2594%25E3%2580%2581%25E5%2585%25A8%25E5%2591%2598%25E6%25A0%25B8%25E9%2585%25B8%25E6%25A3%2580%25E6%25B5%258B%25E3%2580%2581%25E4%25BA%25BA%25E5%2591%2598%25E7%25AE%25A1%25E6%258E%25A7%25E3%2580%2581%25E6%25B5%2581%25E8%25A1%258C%25E7%2597%2585%25E5%25AD%25A6%25E8%25B0%2583%25E6%259F%25A5%25E3%2580%2581%25E5%258C%25BB%25E7%2596%2597%25E6%2595%2591%25E6%25B2%25BB%25E3%2580%2581%25E4%25BF%25A1%25E6%2581%25AF%25E6%258A%25A5%25E9%2580%2581%25E7%25AD%2589%25E6%2596%25B9%25E9%259D%25A2%25E5%25B7%25A5%25E4%25BD%259C%25E7%259A%2584%25E6%2584%258F%25E8%25A7%2581%25E5%25BB%25BA%25E8%25AE%25AE%25E3%2580%2582&speaker=1100&speed=5&audio=http%253A%252F%252Fdueros-short-video.bj.bcebos.com%252Fshort-video%252Fstop_1_24k.wav&from=news"
                }
            },
            "playBehavior": "ENQUEUE"
        }
    }
}

通过分段持续播放和媒体转换播放这两种解决方案,在DuerOS上可以相对有效地解决TTS 文本播放的问题。

Znm6fe.jpg!mobile

基于TTS 的媒体与文本合成播放

音视频资源可以有效地提升声音的品质和效果,TTS 文本播报能解决动态内容的播放问题,二者结合可以进一步提升技能的表现效果,提升服务的用户体验。

目前,DuerOS 提供的可行方式是在技能中使用SSML。DuerOS支持基础标签和扩展标签两种:基础标签里的所有标签都是SSML标准标签,相当于SSML标签的子集;扩展标签指DuerOS使用标准SSML语言定制的标签。

基础标签目前包括6种:

  • speak:根标签

  • audio:根据url合成已有音频

  • say-as:设置数字、符号等的读法

  • sub:替换目标单词

  • silence:设置静音,在文本播报的开头或者结尾增加静音片段,最大10s

  • phoneme:多音字注音

对于audio标签而言,音频以服务器可以访问的的地址给出,目前支持16K采样和24K采样,16bit,单声道,44字节头的wave格式文件。出于性能的约束,要求必须将相应的音频文件上传到百度云bos平台,使用bos提供的地址。单个请求最大限制3个并列的audio资源,单个audio资源大小限制为3M。

扩展标签目前包括4种:

  • background:设置背景声

  • say-as:在属性interpret-as加入两个新值,仅对英文有效

  • poem:设置诗词,属性值 “wuyan”代表五言诗;“qiyan”代表七言诗;“songci”代表宋词

  • space:在所包含文本的空格处生成停顿

其中background标签与audio 标签具有类似的性质,要求必须将相应的音频文件上传到百度云bos平台,使用bos提供的资源url地址。

关于在DuerOS 中如何使用SSML,以及SSML 的更多信息,可以参考《 生动化你的表达——DuerOS中的SSML应用 》。

fuy2Ib7.jpg!mobile

小结

声音的播放是智能语音设备的基础能力,直接播放音视频资源是一种直接的声音播放方式,面向动态文本内容的声音播放一般采用TTS合成的方式实现。outputSpeech 是DuerOS中的TTS合成指令,repromt指令是outputSpeech 指令在特定场景下的变种。对于长文本的播放,DuerOS 提供了分段连续播放和媒体在线转换两种解决方案,DuerOS中的SSML 播放则可以相对有效地将媒体资源播放和TTS语音播放结合起来,从而使DuerOS 技能给用户带来更好的用户体验。

除了SSML之外,如何进一步提高语音合成的表现力呢?家中的孩童能否在“小度系列产品”上听到爸爸声音讲故事呢? 一系列与声音播放相关的新功能特性已经在路上了,DuerOS,值得期待!

FryUBff.jpg!mobile

(文中图片都来自网络,如有侵权,联系作者删除)

【关联阅读】


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK