写在前面

本文转载自mrcp-plugin-with-freeswitch,多谢大佬wangkaisine总结出的经验!

由于本地已部署好FreeSWITCH 1.6.15 ,所以安装FreeSWITCH步骤未实操。

不过可以看出当时FreeSWITCH版本为1.6,可以支持音频呼叫和tts等功能,截止到目前FreeSWITCH release版本已更新至1.10 。

因为个人使用FreeSWITCH版本为项目需要,不过还是建议大家使用最新release版本进行验证。

部署中遇到的问题

按照下面的步骤已经成功搭建一套FreeSWITCH与科大讯飞进行TTS和ASR的通信,但是搭建过程中也遇到了文中没有提到的问题,现罗列如下:

  1. 进行TTS测试时,听到的一直是"Welcome to unimrcp"
    解决方案:需要修改unimrcp/conf下的unimrcpserver.xml,如下:
     <engine id="Demo-Synth-1" name="demosynth" enable="false"/><engine id="XFyun-Synth-1" name="xfyunsynth" enable="true"/><engine id="Demo-Recog-1" name="demorecog" enable="false"/><engine id="XFyun-Recog-1" name="xfyunrecog" enable="true"/>

将默认的Demo改为集成的XFyun既可。
2. 连接讯飞SDK失败
解决方案:需要修改MRCP-Plugin-Demo/unimrcp-1.5.0目录下所有的appid字段,改为你在讯飞平台申请的APPID。直接grep -R "appid" ./*既可,把你看到的appid=xxxxxxx,改成自己的APPID。
重新make && make install。
3. 按照文中给出的lua脚本和grammar进行ASR测试,发现Demo会崩溃,未解决,原因仍在查找中。崩溃信息如下:

[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `./unimrcpserver -o 3'.
Program terminated with signal 11, Segmentation fault.
#0  0x00007fb353de6901 in __strlen_sse2_pminub () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install expat-2.1.0-10.el7_3.x86_64 glibc-2.17-260.el7_6.4.x86_64 keyutils-libs-1.5.8-3.el7.x86_64 krb5-libs-1.15.1-8.el7.x86_64 libcom_err-1.42.9-11.el7.x86_64 libselinux-2.5-14.1.el7.x86_64 nss-softokn-freebl-3.36.0-5.el7_5.x86_64 openssl-libs-1.0.2k-16.el7.x86_64 pcre-8.32-17.el7.x86_64 zlib-1.2.7-18.el7.x86_64
(gdb) bt
#0  0x00007fb353de6901 in __strlen_sse2_pminub () from /lib64/libc.so.6
#1  0x00007fb35565c400 in apr_pstrcat (a=0x7fb338001a68) at strings/apr_strings.c:137
#2  0x00007fb3519df952 in xfyun_recog_stream_recog (recog_channel=0x7fb338002870, voice_data=0x7fb338003858, voice_len=160) at src/xfyun_recog_engine.c:574
#3  0x00007fb3519dfa4d in xfyun_recog_stream_write (stream=0x7fb338002948, frame=0x7fb338003838) at src/xfyun_recog_engine.c:600
#4  0x00007fb355d1fca2 in mpf_bridge_process (object=0x7fb338003800) at src/mpf_bridge.c:53
#5  0x00007fb355d231d7 in mpf_context_process (context=0x7fb338002088) at src/mpf_context.c:438
#6  0x00007fb355d22527 in mpf_context_factory_process (factory=0xf6e220) at src/mpf_context.c:105
#7  0x00007fb355d2570a in mpf_engine_main (scheduler=0xf6e280, obj=0xf6e060) at src/mpf_engine.c:411
#8  0x00007fb355d27ed0 in timer_thread_proc (thread=0xfa04d8, data=0xf6e280) at src/mpf_scheduler.c:212
#9  0x00007fb355678a43 in dummy_worker (opaque=0xfa04d8) at threadproc/unix/thread.c:142
#10 0x00007fb35434edd5 in start_thread () from /lib64/libpthread.so.0
#11 0x00007fb353d75ead in clone () from /lib64/libc.so.6
(gdb) up
#1  0x00007fb35565c400 in apr_pstrcat (a=0x7fb338001a68) at strings/apr_strings.c:137
137         apr_size_t cplen = strlen(cp);
(gdb) p *cp
Cannot access memory at address 0x1c7

应该是内存访问越界的问题,但是还没有抽出时间去解决,留着日后看。

主要目的

使用FreeSWITCH接受用户手机呼叫,通过UniMRCP Server集成讯飞开放平台(xfyun)插件将用户语音进行语音识别(ASR),并根据自定义业务逻辑调用语音合成(TTS),构建简单的端到端语音呼叫中心。

总体结构图如下所示

# 构建步骤

第一步 安装编译FreeSWITCH

本次示例的FreeSWITCH在MacOS High Sierra 10.13.4系统版本中进行源码编译安装,未使用软件包安装,具体安装步骤可见 官网安装介绍 ,其他平台如Linux(Ubuntu、CentOS)应均能安装成功。

以下给出源码编译安装的步骤:

1.下载 FreeSWITCH源码:

cd /usr/local/src
git clone -b v1.6 https://freeswitch.org/stash/scm/fs/freeswitch.git freeswitch

当时FreeSWITCH版本只到1.6,不过截止到目前

2.安装依赖库

brew install autoconf
brew install automake
brew install libtool
brew install pkg-config
brew install speexdsp
brew install speex
brew install libldns-dev
brew install OpenSSL
brew install pcre
brew install pkgconfig sqlite3
brew install lua
brew install opus
brew install libsndfile

注:其他系统平台请自行确认依赖库内容,可能的搜索结果:Ubuntu/CentOS FreeSWITCH 安装依赖。 在ubuntu下:libtool not found。

3.编译安装

cd freeswitch/
# 先执行 bootstrap.sh,生成configure文件
./bootstrap.sh
./configure --prefix=/usr/local/freeswitch
make
make install
make cd-sounds-install
make cd-moh-install

4.运行

cd /usr/local/freeswitch/bin
./freeswitch

即可启动应用。

注:安装过程中可能出现的问题 configure中的错误。

FreeSWITCH默认配置1000-1019(20个)用户,默认密码1234,您可以提前跳转到“第四步 测试与验证” 的验证步骤,登录并拨打5000,可以听到默认IVR的示例语音菜单指引。

第二步 配置编译UniMRCP Server

本次示例的UniMRCP Server在CentOS 7中进行源码编译安装,感谢由Github用户cotinyang提供的已经写好的集成讯飞SDK的UniMRCP Server源码。

1.下载 UniMRCP Server Plugin Demo 源码:

cd /opt
git clone https://github.com/cotinyang/MRCP-Plugin-Demo.git MRCP-Plugin-Demo

2.编译准备环境

cd MRCP-Plugin-Demo/unimrcp-deps-1.5.0
## 编译可能出现错误, 注释掉:107 ~ 109, getopt的set,其中存在不识别的option
## 编译生成apr, apr-util, target path: ./libs
./build-dep-libs.sh

注:1.过程中需要输入两次y,并确认;2.另外,我们为该Demo工程Fork了一个自己维护的工程,地址为https://github.com/wangkaisine/MRCP-Plugin-Demo 您也可以使用这个地址的源码。

3.编译安装unimrcp

cd unimrcp-1.5.0
./bootstrap
## 如果不能自动检测apr,apr-util,请在configure中增加 option:--with-apr=/path/apr --with-apr-util=/path/apr-util/
## apr, apr-util由./build-dep-libs.sh 生成
./configure
make
make install

即可在/usr/local/中看到安装好的unimrcp。

4.测试运行

cd /usr/local/unimrcp/bin
./unimrcpserver -o 3

可以使用client进行验证

cd /usr/local/unimrcp/bin
./unimrcpclient
>help
usage:- run [app_name] [profile_name] (run demo application)app_name is one of 'synth', 'recog', 'bypass', 'discover'profile_name is one of 'uni2', 'uni1', ...examples: run synthrun recogrun synth uni1run recog uni1- loglevel [level] (set loglevel, one of 0,1...7)- quit, exit

输入help回车,给出了使用方法,输入run recog运行语音识别测试,run synth进行语音合成测试。

第三步 集成讯飞开放平台SDK

1.讯飞开发平台SDK下载

由于从讯飞开放平台下载的SDK包和用户以及用户创建的应用相关联,因此需要将third-party/xfyun中的文件和文件夹全部删除,重新下载解压属于自己的SDK,目录与源代码基本一致。

您需要注册并登录 讯飞开放平台 ,进入控制台页面,并创建应用;

在“我的应用”界面获得你的APPID,并为该应用“添加新服务”,选择需要的“语音听写”和”在线语音合成“服务(本示例需要);

点击右侧“SDK下载”,在跳转页面中确认“选择应用”已经选中了您创建的应用,“选择您需要的AI能力”选中上述两项服务,并点击“SDK下载”等待SDK生成与完成下载。

将下载的zip包,解压并替换MRCP-Plugin-Demo/unimrcp-1.5.0/plugins/third-party/xfyun/下的所有文件及文件夹。

注:创建应用页面中的应用平台选择“Linux”。

2.plugin编写与编译

本步骤将告诉您如何编写unimrcp的插件代码,即现在MRCP-Plugin-Demo/unimrcp-1.5.0/plugins文件夹下xfyun_recog、xfyun_xynth文件夹下的文件及其相关配置是如何得到的,如果您当前还不关注此细节,可以跳过本步骤至第四步。

实际上,上述MRCP-Plugin-Demo代码是在 Unimrcp官网 下载 Unimrcp 1.5.0 和 Unimrcp Deps 1.5.0 并在此基础上添加的plugin代码。

首先编辑configure.ac文件,会在后面的Makefile中使用到的宏定义。XFyun recognizer plugin的添加如下:

dnl XFyun recognizer plugin.
UNI_PLUGIN_ENABLED(xfyunrecog)AM_CONDITIONAL([XFYUNRECOG_PLUGIN],[test "${enable_xfyunrecog_plugin}" = "yes"])...plugins/xfyun-recog/Makefile...echo XFyun recognizer plugin....... : $enable_xfyunrecog_plugin

注:其中 ··· 是该文件中的其它默认配置,请找到对应位置填写。

对应地,XFyun synthesizer plugin的添加如下:

dnl XFyun synthesizer plugin.
UNI_PLUGIN_ENABLED(xfyunsynth)AM_CONDITIONAL([XFYUNSYNTH_PLUGIN],[test "${enable_xfyunsynth_plugin}" = "yes"])···plugins/xfyun-synth/Makefile···echo XFyun synthesizer plugin...... : $enable_xfyunsynth_plugin

新增源码与目录

在 plugins 目录下,新建 xfyun-recog 目录,并在该目录下新建 src 目录,可以将 demo_recog_engine.c 拷贝到该目录下改名为 xfyun_recog_engine.c,将xfyun_recog_engine.c文件进行修改(已知一个修改的部分:将appid修改成你自己下载sdk的appid,不然会报错:QISRAudioWrite failed! error code:10407),xfyun-synth目录下对应创建并修改。

在xfyun-recog文件夹下新建Makefile.am文件,内容如下:

AM_CPPFLAGS                = $(UNIMRCP_PLUGIN_INCLUDES)plugin_LTLIBRARIES         = xfyunrecog.laxfyunrecog_la_SOURCES       = src/xfyun_recog_engine.c
xfyunrecog_la_LDFLAGS       = $(UNIMRCP_PLUGIN_OPTS) \-L$(top_srcdir)/plugins/third-party/xfyun/libs/x64 \-lmsc -ldl -lpthread -lrt -lstdc++
xfyunrecog_ladir            = $(libdir)
xfyunrecog_la_DATA          = $(top_srcdir)/plugins/third-party/xfyun/libs/x64/libmsc.soinclude $(top_srcdir)/build/rules/uniplugin.amUNIMRCP_PLUGIN_INCLUDES     += -I$(top_srcdir)/plugins/third-party/xfyun/include

对应地,在fyun-synth文件夹下新建Makefile.am文件夹,内容如下:

AM_CPPFLAGS                = $(UNIMRCP_PLUGIN_INCLUDES)plugin_LTLIBRARIES         = xfyunsynth.laxfyunsynth_la_SOURCES       = src/xfyun_synth_engine.c
xfyunsynth_la_LDFLAGS       = $(UNIMRCP_PLUGIN_OPTS) \-L$(top_srcdir)/plugins/third-party/xfyun/libs/x64 \-lmsc -ldl -lpthread -lrt
xfyunsynth_ladir            = $(libdir)include $(top_srcdir)/build/rules/uniplugin.amUNIMRCP_PLUGIN_INCLUDES     += -I$(top_srcdir)/plugins/third-party/xfyun/include

修改plugins文件夹下Makefile.am文件,xfyun-recog添加内容如下:

if XFYUNRECOG_PLUGIN
SUBDIRS               += xfyun-recog
endif

对应地,xfyun-synth添加内容如下:

if XFYUNRECOG_PLUGIN
SUBDIRS               += xfyun-synth
endif

修改conf/unimrcpserver.xml文件,从默认启用demo engine改为启用我们的两个engine。

xfyun-recog修改如下:

<engine id="Demo-Recog-1" name="demorecog" enable="false"/>
<engine id="XFyun-Recog-1" name="xfyunrecog" enable="true"/>

对应地,xfyun-synth修改如下:

<engine id="Demo-Synth-1" name="demorecog" enable="false"/>
<engine id="XFyun-Synth-1" name="xfyunsynth" enable="true"/>

同时,如果您已经准备好将UniMRCP Server和FreeSWITCH对接,您应该在conf/unimrcpserver.xml中配置好server的ip地址,即当前unimrcp安装的子网访问地址。

重新编译安装unimrcp(第二步 3)。

当你启动时出现如下问题时:

  1. Failed to Load DSO: /usr/local/unimrcp/lib/libmsc.so: undefined symbol: _ZTVN10__cxxabiv117__class_type_infoE

fix:-lstdc++

  1. ./unimrcpserver: error while loading shared libraries: libsofia-sip-ua.so.0: cannot open shared object file: No such file or directory

fix:

在etc/ld.so.conf 内容增加: /usr/local/lib
ldconfig 将ld.so.conf读入cache

第四步 配置与验证

配置

配置FreeSWITCH

我们需要将处理用户语音呼入的FreeSWITCH与向xfyun engine发请求的unimrcp server两者连接起来。

1.配置unimrcp模块并自动加载;

# 编辑/usr/local/src/freeswitch/modules.conf文件,找到要安装的模块,去掉前面的注释符号#
cd /usr/local/src/freeswitch
vim modules.conf
#asr_tts/mod_unimrcp
asr_tts/mod_unimrcp# 执行make mod_xxx-install命令,这样就编译相应模块,并把编译后的动态库安装的/usr/local/freeswitch/mod目录下
make mod_unimrcp-install# 编辑/usr/local/freeswitch/conf/autoload_configs/modules.conf.xml,去掉注释符号,如果没有发现对应模块,则添加
<load module="mod_unimrcp"/>

2.设置profile文件与conf文件;

在/usr/local/freeswitch/conf/mrcp_profiles目录新建unimrcpserver-mrcp-v2.xml配置文件:

<include><!-- UniMRCP Server MRCPv2 --><!-- 后面我们使用该配置文件,均使用 name 作为唯一标识,而不是文件名 --><profile name="unimrcpserver-mrcp2" version="2"><!-- MRCP 服务器地址 --><param name="server-ip" value="192.168.1.23"/><!-- MRCP SIP 端口号 --><param name="server-port" value="8060"/><param name="resource-location" value=""/><!-- FreeSWITCH IP、端口以及 SIP 传输方式 --><param name="client-ip" value="192.168.1.24" /><param name="client-port" value="5069"/><param name="sip-transport" value="udp"/><param name="speechsynth" value="speechsynthesizer"/><param name="speechrecog" value="speechrecognizer"/><!--param name="rtp-ext-ip" value="auto"/--><param name="rtp-ip" value="192.168.1.24"/><param name="rtp-port-min" value="4000"/><param name="rtp-port-max" value="5000"/><param name="codecs" value="PCMU PCMA L16/96/8000"/><!-- Add any default MRCP params for SPEAK requests here --><synthparams></synthparams><!-- Add any default MRCP params for RECOGNIZE requests here --><recogparams><!--param name="start-input-timers" value="false"/--></recogparams></profile>
</include>

配置/usr/local/freeswitch/conf/autoload_configs/unimrcp.conf.xml文件:

<configuration name="unimrcp.conf" description="UniMRCP Client"><settings><!-- UniMRCP profile to use for TTS --><param name="default-tts-profile" value="unimrcpserver-mrcp2"/><!-- UniMRCP profile to use for ASR --><param name="default-asr-profile" value="unimrcpserver-mrcp2"/><!-- UniMRCP logging level to appear in freeswitch.log.  Options are:EMERGENCY|ALERT|CRITICAL|ERROR|WARNING|NOTICE|INFO|DEBUG --><param name="log-level" value="DEBUG"/><!-- Enable events for profile creation, open, and close --><param name="enable-profile-events" value="false"/><param name="max-connection-count" value="100"/><param name="offer-new-connection" value="1"/><param name="request-timeout" value="3000"/></settings><profiles><X-PRE-PROCESS cmd="include" data="../mrcp_profiles/*.xml"/></profiles></configuration>

注:1.unimrcpserver-mrcp-v2.xml中server-ip为unimrcpserver启动的主机ip;2.client-ip和rtp-ip为FreeSWITCH启动的主机,client-port仕FreeSWITCH作为客户端访问unimrcpserver的端口,手机作为客户端访问的FreeSWITCH端口默认为5060,两者不同;3.unimrcpserver-mrcp-v2.xml中的profile name应和unimrcp.conf.xml中的default-tts-profile与default-ars-profile的value一致(有些文档的分析中称mrcp_profiles中的xml文件名也必须和这两者一致,实际上是非必须的)。

Attenion: unimrcpserver 和 freeswitch 部署在同一个网段很重要,最好部署测试的时候在同一台物理机器上进行

3.配置IVR与脚本。

在/usr/local/freeswitch/conf/dialplan/default.xml里新增如下配置:

<extension name="unimrcp"><condition field="destination_number" expression="^5001$"><action application="answer"/><action application="lua" data="names.lua"/></condition>
</extension>

在/usr/local/freeswitch/scripts目录下新增names.lua脚本:

session:answer()--freeswitch.consoleLog("INFO", "Called extension is '".. argv[1]"'\n")
welcome = "ivr/ivr-welcome_to_freeswitch.wav"
menu = "ivr/ivr-this_ivr_will_let_you_test_features.wav"
--
grammar = "hello"
no_input_timeout = 80000
recognition_timeout = 80000
confidence_threshold = 0.2
--
session:streamFile(welcome)
--freeswitch.consoleLog("INFO", "Prompt file is \n")tryagain = 1while (tryagain == 1) do--session:execute("play_and_detect_speech",menu .. "detect:unimrcp {start-input-timers=false,no-input-timeout=" .. no_input_timeout .. ",recognition-timeout=" .. recognition_timeout .. "}" .. grammar)xml = session:getVariable('detect_speech_result')--if (xml == nil) thenfreeswitch.consoleLog("CRIT","Result is 'nil'\n")tryagain = 0elsefreeswitch.consoleLog("CRIT","Result is '" .. xml .. "'\n")tryagain = 0end
end---- put logic to forward call here--session:sleep(250)session:set_tts_params("unimrcp", "xiaofang");session:speak("今天天气不错啊");session:hangup()

我们需要在/usr/local/freeswitch/grammar目录新增hello.gram语法文件,可以为空语法文件须满足语音识别语法规范1.0标准(简称 SRGS1.0),该语法文件 ASR 引擎在进行识别时可以使用。

<?xml version="1.0" encoding="utf-8" ?>
<grammar version="1.0" xml:lang="zh-cn" root="Menu" tag-format="semantics/1.0"xmlns=http://www.w3.org/2001/06/grammarxmlns:sapi="http://schemas.microsoft.com/Speech/2002/06/SRGSExtensions"><!- 这些都是必不可少的--><rule id="city" scope="public"><one-of>     <!-- 匹配其中一个短语--><item>北京</item><item>上海</item></one-of></rule><rule id="cross" scope="public"><one-of><item>到</item><item>至</item><item>飞往</item></one-of></rule><rule id="Menu" scope="public"><item><ruleref uri="#date"/>         <!--指定关联的其他规则的节点--><tag>out.date = reles.latest();</tag></item><item repeat="0-1">从</item>    <!--显示1次或0次--><item><ruleref uri="#city"/><tag>out.city = rulels.latest();</tag></item><item><ruleref uri="#cross"/><tag>out.cross = rulels.latest();</tag></item><item><ruleref uri="#city"/><tag>out.city = rulels.latest();</tag></item></rule>
</grammar>

注:lua脚本中,”play_and_detect_speech” 调用了 ASR 服务,”speak” 调用了 TTS 服务。配置启动中遇到问题。

验证

下载测试工具:Adore SIP Client

在App Store(其他手机系统请到对应应用市场)中搜索“Adore SIP Client”,并下载。

其中SIP IP是FreeSWITCH服务开启的主机IP与port(默认为5060),USER NAME如上所述可选1000-1019,PASSWORD默认为1234。点击"Login"(请确保手机连接的网络与FreeSWITCH在同一个子网内),并拨打5001进行语言测试验证(如果您是从第一步跳转过来的,请拨打5000)。

其他相关资料

FreeSWITCH主页:https://freeswitch.com/

Unimrcp主页:http://www.unimrcp.org/

Apache APR:https://apr.apache.org/

讯飞SDK包导入方式:https://doc.xfyun.cn/msc_linux/SDK%E5%8C%85%E5%AF%BC%E5%85%A5.html

构建MRCP服务器,使得FreeSWITCH基于mod_unimrcp与科大讯飞进行tts和asr通信相关推荐

  1. linux安装基于PHP的web软件,Linux下Web服务器应用之基于LAMP构建phpwind论坛

    Linux下Web服务器应用之 基于LAMP构建phpwind论坛 v什么是LAMP Ü目前最为成熟的一种企业网站应用模式,可提供动态Web站点应用及开发环境 v构成组件 ÜLinux.Apache. ...

  2. ktor框架用到了netty吗_教你如何构建异步服务器和客户端的 Kotlin 框架 Ktor

    Ktor 是一个使用 Kotlin 以最小的成本快速创建 Web 应用程序的框架. Ktor 是一个用于在连接系统(connected systems)中构建异步服务器和客户端的 Kotlin 框架. ...

  3. 构建静态服务器_为静态网站构建无服务器联系表

    构建静态服务器 介绍 (Introduction) A few years ago AWS launched static hosting service S3, which was a paradi ...

  4. aws lambda使用_如何使用AWS Lambda和S3构建无服务器URL缩短器

    aws lambda使用 by Daniel Ireson 丹尼尔·埃里森(Daniel Ireson) 如何使用AWS Lambda和S3构建无服务器URL缩短器 (How to build a S ...

  5. 5分钟Serverless实践 | 构建无服务器的敏感词过滤后端系统

    前言 在上一篇"5分钟Serverless实践"系列文章中,我们介绍了什么是Serverless,以及如何构建一个无服务器的图片鉴黄Web应用,本文将延续这个话题,以敏感词过滤为例 ...

  6. 用Apache构建WEB服务器

    用Apache构建WEB服务器 作者:level Apache源于NCSAhttpd服务器,经过多次修改,成为世界上最流行的Web服务器软件之一.Apache取自"a patchy serv ...

  7. 从包中构建瓦片服务器

    SWITCH2OSM 切换到OPENSTREETMAP 丰富的数据 OpenStreetMap数据丰富而详细,包含与实地人相关的大量数据 - 收集的数据. 功能包括: 道路,铁路,水路等 餐厅,商店, ...

  8. Netty构建游戏服务器(一)--基本概念与原理

    一,Netty是什么 1,Netty是由 JBOSS 提供的一个 java开源 框架. 2,Netty是JAR包,一般使用ALL-IN-ONE的JAR包就可以开发了. 3,Netty不需要运行在Tom ...

  9. Centos 通过 Nginx 和 vsftpd 构建图片服务器

    1.Nginx 简介 nginx_百度百科 Nginx (engine x) 是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器.Nginx是由伊戈尔·赛索耶夫为俄罗斯 ...

  10. 虚拟服务器hydra,使用hydra构建六大服务器及混合服务器

    构建六大服务器及混合服务器 ------------- [github.com/micro-plat/hydra](https://github.com/micro-plat/hydra) 本示例通过 ...

最新文章

  1. redux-thunk使用教程
  2. 操作系统实验报告12:线程2
  3. Python基础语法学习(字符串)
  4. 怎么通过media foundation将图像数据写入虚拟摄像头_[Camera]摄像头镜像
  5. apache spark_Apache Spark Job的剖析
  6. Leedcode1-求树的最小高度
  7. SpringCloud工作笔记084---SpringCloud项目中,关于防止表单提交_使用redis+Aspect面向切面实现
  8. 使用celery执行Django串行异步任务
  9. 廖雪峰python教程-福利 | 廖雪峰官方Python教程,拿走不谢!
  10. 关于芯片或者功率模块热相关计算
  11. 解扩matlab,(完整版)BPSK调制的MATLAB仿真
  12. AXI FULL协议学习与仿真
  13. 电大计算机教学自我测评,电大计算机自我鉴定.doc
  14. matlab函数sim,MATLAB 中sim函数
  15. 阅读 SICP 感想(0. 关于前言和序言)
  16. Unity3d坦克大战联网
  17. android pie新功能,Android Pie:3个隐藏功能 | MOS86
  18. python课程设计——单项选择标准化考试
  19. MySQL 8.0 初学与基础项目实践
  20. flash的读写擦除

热门文章

  1. API MISUSE: <CBCentralManager: 0x000000000> can only accept this command while in the powered on
  2. 射灯安装方法图解_射灯安装图解
  3. 电脑应用程序分身双开及多开(能记住账号和密码)
  4. JAVA有没有moba游戏_你了解MOBA么?——MOBA游戏类型介绍(上)
  5. Firefox中fetch请求后直接调用location.reload(),返回NS_BINDING_ABORTED错误
  6. (9)LICEcap——PC端动图创建工具
  7. arm mali 天梯图_手机最新CPU天梯图 2018年12月手机最新处理器排名表
  8. 长尾理论 推荐系统长尾理论
  9. Linux搭建小型服务器——文件共享以及邮件服务器
  10. PHP 计算当前时间是这一年的第几周