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

开发 开发工具
智能语音设备的特点是语音交互成为人机交互的重要方式,智能语音设备的声音输出摆脱了预置的逻辑,成为了响应式反馈,尤其是对声音输入的响应。

[[344223]]

智能语音设备的特点是语音交互成为人机交互的重要方式,智能语音设备的声音输出摆脱了预置的逻辑,成为了响应式反馈,尤其是对声音输入的响应。

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

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

音视频媒体播放

点播和资源类的技能都采用音视频媒体播放的方式。当技能收到用户请求的意图时,技能在响应中返回音视频媒体播放的指令和媒体资源的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,使端上关闭麦克风。消息示例如下:

  1.     "type""AudioPlayer.Play"
  2.     "playBehavior""{{STRING}}" 
  3.     "audioItem": { 
  4.         "audioItemId""{{STRING}}"
  5.         "stream": { 
  6.             "url""{{STRING}}"
  7.             "outputSpeech": { 
  8.                 "type""{{STRING}}"
  9.                 "text""{{STRING}}"
  10.                 "ssml""{{STRING}}"
  11.                 "ttsTemplates": {{TTSTemplateStructure}} 
  12.             }, 
  13.             "streamFormat""{{STRING}}"
  14.             "offsetInMilliSeconds": {{LONG}}, 
  15.             "token""{{STRING}}"
  16.             "progressReportIntervalMs": {{LONG}} 
  17.         }, 
  18.         "playerInfo": { 
  19.             "content": {{AudioPlayerInfoContentStructure}}, 
  20.             "controls": [ 
  21.                 {{ControlStructure}}, 
  22.                 {{ControlStructure}}, 
  23.                 ...... 
  24.             ] 
  25.         } 
  26.     } 

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

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

基于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指令用于播放器界面的渲染,消息样例如下:

  1.     "type""VideoPlayer.Play"
  2.     "playBehavior""{{STRING}}" 
  3.     "videoItem": { 
  4.         "videoItemId""{{STRING}}"
  5.         "stream": { 
  6.             "url""{{STRING}}"
  7.             "offsetInMilliseconds": {{LONG}}, 
  8.             "stopPointsInMilliseconds":[ 
  9.                 {{LONG}}, 
  10.                 {{LONG}}, 
  11.                 ... 
  12.             ], 
  13.             "expiryTime": {{STRING}} 
  14.             "progressReport": { 
  15.                 "progressReportDelayInMilliseconds": {{LONG}}, 
  16.                 "progressReportIntervalInMilliseconds": {{LONG}} 
  17.             }, 
  18.             "token""{{STRING}}"
  19.             "expectedPreviousToken": {{STRING}} 
  20.         } 
  21.     } 

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

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

基于TTS 的语音播放

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

TTS 的语音播报指令——outputSpeech

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

  1. ...... 
  2.  
  3. "response" : { 
  4.         "outputSpeech" : { 
  5.             "type" : "{{STRING}}"
  6.             "text" : "{{STRING}}"
  7.             "ssml" : "{{STRING}}"
  8.         }, 
  9.         "card" : {}, 
  10.         "directives" : [], 
  11.         "expectSpeech": {{BOOLEAN}}, 
  12.         "shouldEndSession" : {{BOOLEAN}} 
  13.     } 

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

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

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

outputSpeech 的变种——reprompt

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

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

  1. "response" : { 
  2.        "outputSpeech" : { 
  3.            "type" : "{{STRING}}"
  4.            "text" : "{{STRING}}"
  5.            "ssml" : "{{STRING}}"
  6.        }, 
  7.        "reprompt" : { 
  8.            "outputSpeech" : { 
  9.                "type" : "{{STRING}}"
  10.                "text" : "{{STRING}}"
  11.                "ssml" : "{{STRING}}"
  12.            } 
  13.        }, 
  14.        "card" : {}, 
  15.        "directives" : [], 
  16.        "expectSpeech": {{BOOLEAN}}, 
  17.        "shouldEndSession" : {{BOOLEAN}} 
  18.    } 

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

长文本的播放

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事件给技能,消息样例如下:

  1.     "type""StreamResponse.SendPart"
  2.     "token""{{STRING}}" 

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

  1.     "type""StreamResponse.NextRequired"
  2.     "requestId""{{STRING}}"
  3.     "timestamp""{{STRING}}"
  4.     "token""{{STRING}}" 

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

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

媒体转换播放

既然长文本的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天,单位是秒

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

  1.     "directive": { 
  2.         "header": { 
  3.             "messageId""YXVkaW9fbmV3cysxNjAwMTU2ODI4Xzk2NmExampiMQ=="
  4.             "name""Play"
  5.             "namespace""ai.dueros.device_interface.audio_player" 
  6.         }, 
  7.         "payload": { 
  8.             "audioItem": { 
  9.                 "audioItemId""9696687530282687670"
  10.                 "stream": { 
  11.                     "expiryTime""2020-10-01T00:00:00+08:00"
  12.                     "offsetInMilliseconds": 0, 
  13.                     "progressReport": { 
  14.                         "progressReportIntervalInMilliseconds": 15000 
  15.                     }, 
  16.                     "streamFormat""AUDIO_MPEG"
  17.                     "token""eyJib3RfaWQiOiJhdWRpb19uZXdzIiwicmVzdWx0X3Rva2VuIjoiNjk0ODQ2MDY5Mjc0NmYwYjY3YTRhNzI5ZWMwZDE1ZGUiLCJib3RfdG9rZW4iOiI5Njk2Njg3NTMwMjgyNjg3NjcwIiwibGF1bmNoX2lkcyI6WyJhdWRpb19uZXdzIl19"
  18.                     "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" 
  19.                 } 
  20.             }, 
  21.             "playBehavior""ENQUEUE" 
  22.         } 
  23.     } 

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

基于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地址。

小结

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

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

【本文来自51CTO专栏作者“老曹”的原创文章,作者微信公众号:喔家ArchiSelf,id:wrieless-com】

戳这里,看该作者更多好文

 

责任编辑:武晓燕 来源: 51CTO专栏
相关推荐

2013-06-14 17:28:11

Windows PhoWP开发播放声音

2011-08-08 10:23:41

iPhone 流播放 文件

2012-12-27 14:29:38

Android开发流媒体

2019-11-22 09:05:20

DuerOS编程语音

2011-07-22 15:59:15

iPhone 声音 文件

2013-04-08 09:31:05

iOS开发系统声音服务

2012-06-05 09:39:32

Windows 7声音主题

2011-03-07 09:32:54

Ubuntu11.04

2009-04-22 08:57:25

Windows 7微软操作系统

2018-05-18 14:12:41

Chrome 66自动播放

2011-10-21 10:37:05

华为Juiper

2010-06-21 10:13:03

Ubuntu 10.1

2009-09-22 14:20:39

C#播放声音

2010-01-07 18:22:40

VB.NET声音播放

2010-01-11 17:30:40

VB.NET播放声音

2011-11-25 13:52:05

Windows Pho声音播放

2021-01-27 12:02:50

AndroidDuerOS调试

2009-10-12 16:20:15

2010-01-13 11:03:13

VB.NET声音播放
点赞
收藏

51CTO技术栈公众号