小度助手服务 DuerOS Service

小技巧

如果图片看不清楚。你可以 在图片上点击鼠标右键 –> 在新标签页中打开图片 ,然后你可以放大、缩小、移动图片。

dueros_service.c.

概述

小度助手服务 DuerOS Service,是为 音频服务 Audio Service 的子类。

  • 前者完全是按后者的框架实现的。
  • 后者实现时基本上完全覆盖(或继承)前者的方法。
  • 除了创建 Create 与特殊 API 要调用音频子服务的API;一般都调用音频服务的 API。

类图

../_images/fd9bd3df621ab6551a549653a2483711db627f74661160e46a832976547d397b.svg

我们用类图的形式,描述小度助手服务 DuerOS Service 的实现(实际上代码是用 C 语言实现的):

  • 结构体 dueros_service_t ,是内部私有数据。

    • .duer_que: 与内部任务 dueros_task 之间通信的消息队列。
    • .duer_state: DuerOS Service 的状态。
  • private method 部分,是 DuerOS Servcie 内部函数。这些函数的实现大部分都很简单:

    • dueros_task(): 内部任务。
    • dueros_start(): 启动 DuerOS Service。
    • dueros_stop(): 停止 DuerOS Service。
    • dueros_connect(): 连接 DuerOS Service。
    • dueros_disconnect(): 断开 DuerOS Service。
    • dueros_destroy(): 销毁 DuerOS Service。
  • public method 部分,是 DuerOS Servcie 的提供的 API 函数。这些函数的实现大部分都很简单:

    • dueros_service_create() 的实现略微复杂一点,看这里 API
    • dueros_service_state_get() 获得 DuerOS Service 状态。

序列图

../_images/33fe9859823c0f26dffbe31260a3b2a508e6188027a4ff209a666fd8bf450ec1.svg

对像说明:

  • esp_dispatcher_dueros_app.c: 某个应用程序
  • dueros_service.c: 小度助手音频子服务
  • dueros_task(): 音频子服务的内部任务
  • audio_service.c:音频服务

流程说明:

  1. 应用程序 esp_dispatcher_dueros_app.c 调用 DuerOS Service 音频子服务 dueros_service_create()
  2. dueros_service.c 调用 audio_service_create(), 并会将 .service_destroy.service_start , .service_stop , .service_connect , .service_disconnect , 等回调函数作为参数的字段传入。 同时也会将自已的地址,作为 .user_data 参数字段传入。 因 DuerOS Service 音频子服务需要创建内部任务,也会将内部任务函数 dueros_task() 作为 .task_func 参数字段传入。
  3. audio_service.c 将上述回调函数和 .user_data 保存下来。因为 .task_func 不为空(实际上是 .task_stack > 0),故同时创建内部任务。
  4. dueros_task() 调用 duer_initialize() 初始化 lightduer 。
  5. dueros_task() 注册事件回调函数 duer_set_event_callback(duer_event_hook)
  6. duer_init_device_info()
  7. duer_register_device_info_ops()
  8. dueros_task() 设置状态为 SERVICE_STATE_IDLE

10. esp_dispatcher_dueros_app.c 注册分发器 esp_dispather 功能 esp_dispatcher_reg_exe_func( ACTION_EXE_TYPE_DUER_CONNECT, dueros_action_connect)。 当收到 ACTION_EXE_TYPE_DUER_CONNECT 指令时,执行 dueros_action_connect() 。 11. esp_dispatcher_dueros_app.c 注册分发器 esp_dispather 功能 esp_dispatcher_reg_exe_func( ACTION_EXE_TYPE_DUER_DISCONNECT, dueros_action_disconnect)。 当收到 ACTION_EXE_TYPE_DUER_DISCONNECT 指令时,执行 dueros_action_disconnect()

  1. esp_dispatcher_dueros_app.c 调用 audio_service_set_callback() 设置事件回调函数 .callback_func
  1. esp_dispatcher_dueros_app.c 接收到事件 wifi_service_cb(WIFI_SERV_EVENT_CONNECTED)
  2. esp_dispatcher_dueros_app.c 调用执行分发器功能 esp_dispatcher_execute(ACTION_EXE_TYPE_DUER_CONNECT)
  3. esp_dispatcher 发送消息 ESP_DISPCH_EVENT_TYPE_EXE 给其内部任务。
  4. esp_dispatcher 内部任务执行动作, 实际上是调用 dueros_action_connect()
  5. dueros_action 调用 audio_service_connect()
  6. .service_connect 不为空,audio_service.c 会执行 .service_connect, 实际上是执行 dueros_connect()
  7. dueros_server.c 发送 DUER_CMD_LOGIN 消息给内部任务。
  8. dueros_task() 调用 duer_login()
  9. dueros_task() 调用 duer_start() 启动 lightduer 。
  10. dueros_task() 设置状态为 SERVICE_STATE_IDLE
  11. dueros_task() 调用音频服务事件回调函数 audio_service_callback(SERVICE_STATE_CONNECTING)
  12. audio_service.c 调用应用的事件回调函数 duer_callback()
  1. audio_service.c 接收到 lightduer 的开始事件 DUER_EVENT_START
  2. audio_service.c 通知内部任务已连接 DUER_CMD_CONNECTED
  3. dueros_task() 设置状态为 SERVICE_STATE_CONNECTED
  4. dueros_task() 调用音频服务事件回调函数 audio_service_callback(SERVICE_STATE_CONNECTED)
  5. audio_service.c 调用应用的事件回调函数 duer_callback()
  1. esp_dispatcher_dueros_app.c 接收到事件 rec_engine_cb (REC_EVENT_VAD_START)
  2. esp_dispatcher_dueros_app.c 调用 audio_service_start()
  3. .service_start 不为空,被执行( 实际上是执行 dueros_start() )。
  4. audio_service.c 发送消息 DUER_CMD_START 给内部任务。
  5. 内部任务 dueros_task() 调用 duer_voice_start(RECORD_SAMPLE_RATE)
  6. 内部任务 dueros_task() 调用 duer_dcs_on_listen_started()
  7. dueros_task() 设置状态为 SERVICE_STATE_RUNNING
  8. dueros_task() 调用音频服务事件回调函数 audio_service_callback(SERVICE_STATE_CONNECTED)
  9. audio_service.c 调用应用的事件回调函数 duer_callback()
  10. dueros_task() 从 rec_engine 读数据 rec_engine_data_read()
  11. dueros_task() 调用 duer_voice_send() 发送语音 。
  1. esp_dispatcher_dueros_app.c 接收到事件 rec_engine_cb(), 接收到 REC_EVENT_VAD_STOPREC_EVENT_WAKEUP_END 任一事件。
  2. esp_dispatcher_dueros_app.c 调用 audio_service_stop()
  3. .service_stop 不为空,被执行( 实际上是执行 dueros_stop() )。
  4. audio_service.c 发送消息 DUER_CMD_STOP 给内部任务。
  5. 内部任务 dueros_task() 调用 duer_voice_stop()
  6. dueros_task() 设置状态为 SERVICE_STATE_STOPPED
  7. dueros_task() 调用音频服务事件回调函数 audio_service_callback(SERVICE_STATE_STOPPED)
  8. audio_service.c 调用应用的事件回调函数 duer_callback()
  1. esp_dispatcher_dueros_app.c 接收到事件 wifi_service_cb(WIFI_SERV_EVENT_DISCONNECTED)

  2. esp_dispatcher_dueros_app.c 调用执行分发器功能 esp_dispatcher_execute(ACTION_EXE_TYPE_DUER_CONNECT)

  3. esp_dispatcher 发送消息 ESP_DISPCH_EVENT_TYPE_EXE 给其内部任务。

  4. esp_dispatcher 内部任务执行动作, 实际上是调用 dueros_action_disconnect()

  5. dueros_action 调用 audio_service_disconnect()

  6. audio_service.c 接收到 lightduer 的停止事件 DUER_EVENT_STOPPED

  7. dueros_service.c 调用 audio_service_disconnect()

    70~74 或 75~76 二者选其一。

  8. .service_connect 不为空,audio_service.c 会执行 .service_connect, 实际上是执行 dueros_connect()

  9. dueros_server.c 发送 DUER_CMD_QUIT 消息给内部任务。

  10. dueros_task() 调用 duer_stop() 停止 lightduer 。

  11. dueros_task() 设置状态为 SERVICE_STATE_IDLE

  12. dueros_task() 调用音频服务事件回调函数 audio_service_callback(SERVICE_STATE_CONNECTING)

  13. audio_service.c 调用应用的事件回调函数 duer_callback()

  1. (实际上没有代码)调用 audio_service_destroy(), 销毁 DuerOS Service音频子服务。
  2. .service_destroy 不为空, 其被 audio_service.c 调用( 实际上是执行 dueros_destory() )。
  3. dueros_server.c 发送 DUER_CMD_DESTROY 消息给内部任务。
  4. dueros_task() 调用 duer_voice_stop()
  5. dueros_task() 设置状态为 SERVICE_STATE_IDLE
  6. dueros_service.c 中止内部任务 dueros_task() 。

API

  • dueros_service_create()

  • audio_service_create

  • audio_service_set_callback()

    ../_images/337e9a872be68a76515a2b6dfe5180b5c1f57a8e4e35fed874deb189dfb377f7.svg
  • audio_service_connect()

  • dueros_connect()

    ../_images/19dc2df0eb77a42f469442a98ca931296e8344ff053b8bc80a5e6ccc9cdfc114.svg
  • audio_service_start()

  • dueros_start()

    ../_images/b988a575269ae64277005aaebab19e28c1bf732738849a4dddd8dea50f120a3b.svg
  • audio_service_stop()

  • dueros_stop()

    ../_images/e0e68b36112d29bcf04e7bfc371e443bebe052e7ea3a5acb1c9d79ede44a95b1.svg
  • audio_service_disconnect()

  • dueros_disconnect()

    ../_images/6beb6b3751a26b6f077eddb6f7880f37190fc5b93072b0d6705a980776bf2db5.svg
  • audio_service_destroy()

  • dueros_destory()

    ../_images/eba0253eb3dd1d2daccff3907e5af79c4ab81a2056ca34ca4db27e91f51f2d50.svg