DuerOS的个人开发者版本在官方的介绍中已经停止申请, 代码也大半年没人更新了, 不过好在这个版本需要的麦克风阵列可以自行在网上购买, 相关的代码也是托管在Github上, 于是在研究了网上的各位大神的文章后, 终于把DuerOS运行起来了...
选购硬件
树莓派3B+: 网上到处有卖, 需要买相关的套件, 单独的板子是无法玩的.
麦克风阵列: ReSpeaker树莓派4麦克风阵列扩展板
烧录系统
在树莓派上烧录raspbian-2018.4.18这个镜像. 千万不要烧录官网最新的镜像, 最新的镜像可能无法安装某些第三方库(比如pyaudio死活安装不了). 也不要安装DuerOS_For_Raspberry这个镜像, 因为这个镜像是针对Raspberry3B的, 3B+安装DuerOS这个镜像后会无法开机
安装声卡驱动
按照官方的文档去安装声卡驱动就行. 官方文档: http://wiki.seeedstudio.com/cn/ReSpeaker_4_Mic_Array_for_Raspberry_Pi/
运行装DuerOS
官方的文档: https://developer.baidu.com/forum/topic/show/244796?pageNo=1 安装完成后会有两个问题:
- 运行enter_trigger_start.sh 脚本, 服务器有回应但是没有声音
- 无法运行wakeup_trigger_start.sh 脚本
解决第一个问题
修改/home/pi/DUerOS-Python-Client/app/framework 目录下面的play.py文件
# -*- coding: utf-8 -*-
"""
基于GStreamer的播放模块
"""
import gi
import logging
import app.app_config as app_config
gi.require_version('Gst', '1.0')
from gi.repository import Gst
Gst.init(None)
logging.basicConfig(level=app_config.LOGGER_LEVEL)
logger = logging.getLogger(__file__)
class Player(object):
'''
播放器实现类
'''
def __init__(self):
# create a new gstreamer pipeline
self.pipeline = Gst.Pipeline.new("mypipeline")
# add a file source to the pipeline
self.urisrc = Gst.ElementFactory.make("uridecodebin","source")
self.urisrc.connect("pad-added", self.decode_link)
self.pipeline.add(self.urisrc)
# add a convertor to the pipeline
self.convert = Gst.ElementFactory.make("audioconvert","convert")
self.pipeline.add(self.convert)
# add an alsa sink to the pipeline and link it to theconvertor
self.sink = Gst.ElementFactory.make("alsasink", "sink")
self.pipeline.add(self.sink)
self.convert.link(self.sink)
self.bus = self.pipeline.get_bus()
self.bus.add_signal_watch()
self.bus.enable_sync_message_emission()
def decode_link(self, dbin, pad):
pad.link(self.convert.get_static_pad("sink"))
def play(self, uri):
'''
播放
:param uri:播放资源地址
:return:
'''
self.convert.unlink(self.sink)
self.pipeline.set_state(Gst.State.NULL)
# start playing
logger.info('播放资源 uri: {}'.format(uri))
self.urisrc.set_property("uri", uri)#'http://zhangmenshiting.qianqian.com/data2/music/067eaeefb2eb0498fe404edba700c6b1/599610520/599610520.mp3?xcode=d8bf0fee68258ce2350a5c038dd045b5')
self.convert.link(self.sink)
self.pipeline.set_state(Gst.State.PLAYING)
def stop(self):
'''
停止
:return:
'''
logger.info('停止')
self.urisrc.unlink(self.convert)
self.convert.unlink(self.sink)
self.pipeline.set_state(Gst.State.NULL)
def pause(self):
'''
暂停
:return:
'''
logger.info('暂停')
self.pipeline.set_state(Gst.State.PAUSED)
def resume(self):
'''
回复播放
:return:
'''
logger.info('回复播放')
self.pipeline.set_state(Gst.State.PLAYING)
def add_callback(self, name, callback):
'''
播放状态回调
:param name: {eos, ...}
:param callback: 回调函数
:return:
'''
if not callable(callback):
return
def on_message(bus, message):
callback()
self.bus.connect('sync-message::{}'.format(name), on_message)
@property
def duration(self):
'''
播放时长
:return:
'''
success, duration = self.pipeline.query_duration(Gst.Format.TIME)
if success:
return int(duration / Gst.MSECOND)
@property
def position(self):
'''
播放位置
:return:
'''
success, position = self.pipeline.query_position(Gst.Format.TIME)
if not success:
position = 0
return int(position / Gst.MSECOND)
@property
def state(self):
'''
播放状态
:return:
'''
# GST_STATE_VOID_PENDING no pending state.
# GST_STATE_NULL the NULL state or initial state of an element.
# GST_STATE_READY the element is ready to go to PAUSED.
# GST_STATE_PAUSED the element is PAUSED, it is ready to accept and process data.
# Sink elements however only accept one buffer and then block.
# GST_STATE_PLAYING the element is PLAYING, the GstClock is running and the data is flowing.
_, state, _ = self.pipeline.get_state(Gst.SECOND)
return 'FINISHED' if state != Gst.State.PLAYING else 'PLAYING'
修改/home/pi/DUerOS-Python-Client/app 目录下面的enter_trigger_main.py文件
# -*- coding: utf-8 -*-
'''
通过输入[Enter]触发唤醒状态
'''
import logging
from sdk.dueros_core import DuerOS
from app.framework.mic import Audio
from app.framework.player import Player
from app.utils.prompt_tone import PromptTone
logging.basicConfig(level=logging.INFO)
def directive_listener(directive_content):
'''
云端下发directive监听器
:param directive_content:云端下发directive内容
:return:
'''
content = u'云端下发directive:%s' % (directive_content)
logging.info(content)
def main():
# 创建录音设备(平台相关)
audio = Audio()
# 创建播放器(平台相关)
player = Player()
dueros = DuerOS(player)
dueros.set_directive_listener(directive_listener)
audio.link(dueros)
dueros.start()
audio.start()
#prompt_tone_player = PromptTone()
while True:
try:
try:
print '\n'
input('单击[Enter]建,然后发起对话\n')
except SyntaxError:
pass
# 唤醒态提示音
#prompt_tone_player.play()
dueros.listen()
except KeyboardInterrupt:
break
dueros.stop()
audio.stop()
if __name__ == '__main__':
main()
解决第二个问题
还未解决...