# 硬件抽象层

SDK 正常工作依赖硬件设备平台提供的软硬件接口,包括麦克风、扬声器、摄像头、加密库等模块。我们设计了硬件抽象层,提供一致的接口定义,具体的接口实现需要 SDK 的接入方提供。

# 1. Module 抽象

头文件:wmpf/module.h

我们把每个模块抽象成一个wx_module类型,目前有如下几种 module:

类型 头文件 说明
wx_audio_module wmpf/hardware/audio.h 音频模块,用于从麦克风和扬声器输入/输出音频流
wx_camera_module wmpf/hardware/camera.h 摄像头模块,用于从摄像头获取视频流
wx_crypto_module wmpf/crypto.h 签名算法模块。SDK 依赖系统的加密库中的签名算法。
wx_video_module wmpf/hardware/video.h 视频模块,用于创建远端视频流

当按需实现这几种 Module 后,在调用 wx_init() 初始化 SDK 的时候,将使用如下函数指针把 Module 提供给 SDK 使用:

typedef wx_error_t (*wx_get_module_t)(const char* id,
                                      struct wx_module** module);

SDK 调用实现的函数时,会传入一个 ID,需要返回此 ID 所对应的 wx_module 的实例。

参数

属性 类型 说明
id char* module ID,在后续定义
module struct wx_module** 对应的 module 实例

当前支持的 module ID 已经预先定义在各个头文件中:

ID 头文件
WX_AUDIO_MODULE_ID wmpf/hardware/audio.h
WX_CAMERA_MODULE_ID wmpf/hardware/camera.h
WX_CRYPTO_MODULE_ID wmpf/crypto.h
WX_VIDEO_MODULE_ID wmpf/hardware/video.h

返回值

wx_error_t SDK 根据此返回值,判断请求的 module 是否有效。

例如一台设备不具备摄像头,那么当 SDK 请求 WX_CAMERA_MODULE_ID 时,只需返回 WXERROR_UNIMPLEMENTED

错误码 说明
WXERROR_OK 请求的 module 有效。
WXERROR_UNIMPLEMENTED 请求的 module 无效。

示例代码

// 假设已经实现了如下module:
extern struct wx_audio_module audio_module;
extern struct wx_camera_module camera_module;
extern struct wx_crypto_module crypto_module;
// 现实现HAL获取Module的函数如下:
wx_error_t hal_get_module(const char* id, struct wx_module** module_out) {
  if (!strcmp(id, WX_AUDIO_MODULE_ID)) {
    *module_out = (struct wx_module*)&audio_module;
    return WXERROR_OK;
  } else if (!strcmp(id, WX_CAMERA_MODULE_ID)) {
    *module_out = (struct wx_module*)&camera_module;
    return WXERROR_OK;
  } else if (!strcmp(id, WX_CRYPTO_MODULE_ID)) {
    *module_out = (struct wx_module*)&crypto_module;
    return WXERROR_OK;
  }
  // 假设当前设备没有屏幕,因此不需提供 wx_video_module,那么就返回 WXERROR_UNIMPLEMENTED
  return WXERROR_UNIMPLEMENTED;
}

# 2. 音频模块

头文件:wmpf/hardware/audio.h

音频模块,需要配置一个 wx_audio_module 类型的实例。该类型主要包含如下几个函数指针,用来获取音频输入/输出设备的信息,或操作音频设备。

运行时,VoIP 将顺序调用这 4 个函数,完成对音频输入/输出设备的配置。

# 2.1 get_number_of_devices

获取指定类型音频输入/输出设备的数量。

wx_error_t (*get_number_of_devices)(struct wx_audio_module* module,
                                    wx_audio_device_type_t device_type,
                                    size_t* num_devices_out);

参数

属性 类型 说明
module struct wx_audio_module* context
device_type wx_audio_device_type_t 设备类型,可选值
WX_AUDIO_DEVICE_IN(音频输入设备,如麦克风)
WX_AUDIO_DEVICE_OUT(音频输出设备,如扬声器)
num_devices_out size_t* 返回对应类型的音频设备的数量

返回值

wx_error_t SDK 根据此返回值,判断得到的设备数量是否有效

错误码 说明
WXERROR_OK 成功
WXERROR_INVALID_ARGUMENT num_devices_out 为空

# 2.2 get_device_name

查询指定类型(如 WX_AUDIO_DEVICE_IN 表示麦克风)音频输入/输出设备列表中第 index 个设备的 ID

wx_error_t (*get_device_name)(struct wx_audio_module* module,
                              size_t index,
                              wx_audio_device_type_t device_type,
                              char** device_name_out);

参数

属性 类型 说明
module struct wx_audio_module* context
index size_t 设备列表中指定的设备。取值范围[0, num_devices_out)
device_type wx_audio_device_type_t 设备类型,同 get_number_of_devices
device_name_out char** 返回对应设备的 ID

返回值

wx_error_t SDK 根据此返回值,判断得到的设备 ID 是否有效

错误码 说明
WXERROR_OK 成功
WXERROR_INVALID_ARGUMENT num_devices_out 为空
WXERROR_OUT_OF_RANGE index 超出范围

# 2.3 get_device_info

查询指定类型和设备 ID 的设备的详细信息。该函数用于返回一些在不用打开音频设备的情况下就能获取到的音频设备信息,如支持的音频编码格式。

wx_error_t (*get_device_info)(struct wx_audio_module* module,
                              const char* id,
                              wx_audio_device_type_t device_type,
                              const struct wx_metadata** metadata_out);

参数

属性 类型 说明
module struct wx_audio_module* context
id const char* get_device_name 查到的设备 ID,或者宏 WX_AUDIO_DEVICE_PRIMARY 表示任意有效的设备。
device_type wx_audio_device_type_t get_number_of_devices 的 device_type
metadata_out const struct wx_metadata** 返回对应设备的详情。二级指针指向的对象可以是局部变量。

返回值

wx_error_t SDK 根据此返回值,判断得到的设备详情是否有效

错误码 说明
WXERROR_OK 成功

# 2.4 open

调用指定的音频输入/输出设备。

wx_error_t (*open)(struct wx_audio_module* module,
                   const char* id,
                   wx_audio_device_type_t device_type,
                   struct wx_audio_device** device_out);

参数

属性 类型 说明
module struct wx_audio_module* context
id const char* get_device_infoid
device_type wx_audio_device_type_t get_number_of_devices 的 device_type
device_out struct wx_audio_device** 返回对应的设备实例。详见后续 wx_audio_device 类型说明

返回值

wx_error_t SDK 根据此返回值,判断得到的设备实例是否有效

错误码 说明
WXERROR_OK 成功

# 2.5 wx_audio_device

属性 类型 说明
common wx_device 设备类型的公共基类。
metadata wx_metadata 对于设备的描述信息。

struct wx_audio_device 本身的功能不多,主要是对于设备的描述。真正需要重点关注的是它的两个拓展类型:wx_audio_device_inwx_audio_device_out

# 2.5.1 wx_audio_device_in

对于输入设备(如:麦克风)的抽象。这个类型的关键是需要提供 open_input_stream 函数实现,运行时 SDK 将调用此函数,创建音频输入流对象 wx_audio_stream_in。SDK 使用 wx_audio_stream_in 对象的实例进一步控制音频采集。

麦克风设备在 VoIP 通话拨通时被创建,VoIP 通话结束时销毁。

属性 类型 说明
device wx_audio_device 基类。
open_input_stream 函数指针 SDK 使用这个函数指针打开/使用麦克风设备。
# open_input_stream 的参数
参数 类型 说明
dev wx_audio_device_in * context
config wx_audio_config * SDK 希望的麦克风配置。
listener wx_audio_stream_in_listener * SDK 监听麦克风事件的回调函数。开发者需要在合适的时机正确地调用这些函数。
user_data void * SDK 所依赖的其他 context 信息。调用麦克风事件回调函数时需要带上这个指针。
stream_out wx_audio_stream_in ** 返回新创建的音频输入流对象。定义如下。
# wx_audio_stream_in
参数 类型 说明
common wx_audio_stream * context
pause 函数指针 SDK 调用此函数以暂停音频数据输入。
resume 函数指针 SDK 调用此函数以恢复音频数据输入。
# wx_audio_stream_in_listener
参数 类型 说明
common wx_struct 基类
data 函数指针 系统调用此函数向 SDK 提供麦克风采集到的音频数据。
error 函数指针 系统通过调用此函数告知 SDK 麦克风采集音频数据出错。

注意事项:

  1. SDK 目前仅采集 PCM 格式的音频数据,远期可能增加其他音频格式。
  2. config 目前以采样率 16000、采样长度 20ms、16bit 为默认配置,可能会动态调整。如果设备不支持这些音频配置,设备厂商应当自行对 PCM 数据进行变换。
  3. data 回调可以理解为非阻塞的,即与网络无关。
  4. data 回调提供的一帧音频数据,需要根据 config 设置的参数提供。举例来说:PCM 采样率 16000、采样格式 16Bit、采样长度 20ms 的单通道音频数据,包含 16000 / 1000 * 20 * 1 * (16 / 8) 字节的数据(采样率 / 1000 * 采样长度 * 通道数 * 采样格式 / 8Bit)。

# 2.5.2 wx_audio_device_out 类型

对于扬声器设备的抽象。这个类型的关键是提供 open_output_stream 函数实现,运行时 SDK 将调用此函数,创建音频输出流对象 wx_audio_stream_out。SDK 使用 wx_audio_stream_out 对象的实例进一步控制音频播放。

扬声器设备在 VoIP 通话开始拨打时被创建,先播放铃声,在 VoIP 通话开始时开始播放语音,VoIP 通话结束时销毁。

属性 类型 说明
device wx_audio_device 基类。
open_output_stream 函数指针 SDK 使用这个函数指针打开/使用扬声器设备。
# open_output_stream 的参数:
参数 类型 说明
dev wx_audio_device_out * context
config wx_audio_config * SDK 希望的扬声器配置。
listener wx_audio_stream_out_listener * SDK 监听扬声器事件的回调函数。应在合适的时机正确地调用这些函数。
user_data void * SDK 所依赖的其他 context 信息。调用扬声器事件回调函数时需要带上这个指针。
stream_out wx_audio_stream_out ** 返回新创建的音频输出流对象。定义如下。
# wx_audio_stream_out 类型
参数 类型 说明
common wx_audio_stream * context
pause 函数指针 SDK 调用此函数以暂停音频数据播放。
resume 函数指针 SDK 调用此函数以恢复音频数据播放。
flush 函数指针 SDK 调用此函数要求音频播放缓存,立刻播放缓存内的音频数据。
# wx_audio_stream_out_listener 类型
参数 类型 说明
common wx_struct 基类
data 函数指针 系统通过调用此函数向 SDK 拉取待播放(铃声或收到的语音流)的音频数据。
error 函数指针 系统通过调用此函数通知 SDK 音频播放出错。

注意事项:

  1. SDK 目前仅提供 PCM 格式的音频数据,远期可能增加其他音频格式。
  2. config 目前以采样率 16000、采样长度 20ms、16bit 为默认配置,可能会动态调整。如果设备不支持这些音频配置,设备厂商应当自行对 PCM 数据进行变换。
  3. data 回调可以理解为非阻塞的,即与网络无关。
  4. data 回调传入的 buffer 需要足够大,能存下 config 设置的一帧音频数据。举例来说:PCM 采样率 16000、采样格式 16Bit、采样长度 20ms 的单通道音频数据,包含 16000 / 1000 _ 20 _ 1 _ (16 / 8) 字节的数据(采样率 / 1000 _ 采样长度 _ 通道数 _ 采样格式 / 8Bit)。

# 3. 签名算法模块

头文件:wmpf/crypto.h

SDK 依赖系统内置的签名算法,我们提供了 OpenSSL、MbedTLS、WolfSSL 的 Demo 实现,存放在 example 目录中。如果使用上述 crypto 实现,通常可以直接使用 example 的代码实现,否则请参考 example 实现进行适配。

Demo 实现:

  • example/crypto_mbedtls.c
  • example/crypto_openssl.c
  • example/crypto_wolfssl.c

# 4. (可选)摄像头模块

头文件:wmpf/hardware/camera.h

摄像头模块,需要配置一个 wx_camera_module 类型的实例。该类型主要是需要你提供如下几个函数指针,用来利用设备提供的摄像头设备对象生成设备发送到手机的视频流

运行时,SDK 将顺序调用这 3 个函数,完成对摄像头设备的配置。

# 4.1 get_number_of_devices

获取摄像头设备的数量。

wx_error_t (*get_number_of_devices)(struct wx_camera_module* module,
                                    size_t* num_devices_out);

参数

属性 类型 说明
module struct wx_camera_module* context
num_devices_out size_t* 返回对应类型的摄像头设备的数量

返回值

wx_error_t SDK 根据此返回值,判断得到的设备数量是否有效

错误码 说明
WXERROR_OK 成功
WXERROR_INVALID_ARGUMENT num_devices_out 为空

# 4.2 get_device_info

查询指定摄像头设备的详细信息。

wx_error_t (*get_device_info)(struct wx_camera_module* module,
                              size_t index,
                              struct wx_camera_device_info* device_info);

参数

属性 类型 说明
module struct wx_camera_module* context
index size_t 设备列表中指定的设备。取值范围[0, num_devices_out)
device_info struct wx_camera_device_info* SDK 会传入此 device_info,需要填充此结构体的内容。

返回值

wx_error_t SDK 根据此返回值,判断得到的设备详情是否有效

错误码 说明
WXERROR_OK 请求到的设备详情有效。

# 4.3 open

调用指定的摄像头设备。

wx_error_t (*open)(struct wx_camera_module* module,
                   const char* id,
                   struct wx_camera_device** device_out);

参数

属性 类型 说明
module struct wx_camera_module* context
id char * get_device_info 查到的设备 ID,或者宏 WX_CAMERA_DEVICE_PRIMARY 表示任意有效的设备。
device_out struct wx_camera_device ** 返回对应的设备实例。

返回值

wx_error_t SDK 根据此返回值,判断得到的设备实例是否有效

错误码 说明
WXERROR_OK 成功

# 4.4 wx_camera_device

对于摄像头设备的抽象。这个类型的关键是需要提供 open_stream 函数实现,运行时 SDK 将调用此函数,创建视频输入流对象 wx_camera_stream。SDK 使用 wx_camera_stream 对象的实例进一步控制视频采集。

属性 类型 说明
common wx_device 设备类型的公共基类。
metadata wx_metadata 对于设备的描述信息。
open_stream 函数指针 SDK 使用这个函数指针打开/使用摄像头设备。

open_stream 的参数:

参数 类型 说明
dev wx_camera_device * context
config wx_camera_stream_config * SDK 需要的摄像头配置,包括数据流类型。
listener wx_camera_stream_listener * SDK 监听摄像头事件的回调函数。应在合适的时机正确地调用这些函数。
user_data void * SDK 所依赖的其他 context 信息。调用摄像头事件回调函数时需要带上这个指针。
stream_out wx_camera_stream ** 返回新创建的视频输入流对象。定义如下。

# wx_camera_stream 类型

参数 类型 说明
common wx_struct 基类
update 函数指针 SDK 调用此函数以更新摄像头录制参数。
make_i_frame 函数指针 SDK 调用此函数以请求立刻收到一个 H264/H265 I 帧。

# wx_camera_stream_listener 类型

参数 类型 说明
common wx_struct 基类
data 函数指针 系统调用此函数向 SDK 提供摄像头采集到的视频数据。
error 函数指针 系统通过调用此函数告知 SDK 摄像头采集视频数据出错。

注意事项:

  1. SDK 目前仅采集 H264/H265 格式的视频数据。
  2. data 回调可以理解为非阻塞的,即与网络无关。
  3. 设备需要定时(建议 1 秒,最长不得超过 5 秒)提供 PPS、SPS、I 帧。
  4. 设备传入的 rotation 仅在 Linux SDK 0xD5000084 及以上版本、微信客户端 8.0.41 及以上版本生效,对于更旧的微信版本,需要在小程序侧调用 VoIP 插件的 setUIConfig 设置旋转角度。

# 5. (可选)视频模块

头文件:wmpf/hardware/video.h

摄像头模块,需要配置一个 wx_video_module 类型的实例。

运行时,SDK 将调用 create_output_stream 函数创建视频输出流,将接收到的远端(手机)摄像头录制的视频通过流对象输出。

# 5.1 create_output_stream

创建一个视频输出流。

wx_error_t (*create_output_stream)(struct wx_video_module* module,
                                   const struct wx_video_stream_config* config,
                                   struct wx_video_stream** stream);

参数

属性 类型 说明
module struct wx_video_module* context
config const struct wx_video_stream_config* 视频输出流参数
stream struct wx_video_stream** 返回视频输出流对象

返回值

wx_error_t SDK 根据此返回值,判断视频输出流是否有效

错误码 说明
WXERROR_OK 成功

# 5.2 wx_video_stream

参数 类型 说明
common wx_struct 基类
write 函数指针 SDK 调用此函数以写入视频输出流。
close 函数指针 SDK 调用此函数以关闭视频输出流。