讯飞与腾讯云:Android 实时语音识别服务对比选择

news2024/10/16 11:16:29

         在 移动端 接入实时语音识别方面,讯飞和腾讯云都是优秀的选择,但各有其特点和优势。以下是对两者的详细比较:

一、讯飞语音识别

1.1 讯飞实时语音识别介绍

1.1.1 功能特点

         1.支持多种语言识别,满足不同语种用户的需求。(普通话/英语免费,其他语音可试用半年。试用到期后需单独购买,价格为:2万/个/年)

        2.提供丰富的API接口,不太方便 Android 开发者接入。

1.1.2 优势

        1.讯飞在语音识别领域有较高的知名度和市场占有率。

        2.提供了详细的开发文档和示例代码,方便开发者快速上手。

        3.支持定制化开发,可以根据用户需求进行个性化定制。

1.2 接入流程

1.2.1 注册账号并创建应用

        注册讯飞开放平台账号,创建应用并获得AppID。

1.2.2 实时语音转写API文档

        实时语音转写(Real-time ASR)基于深度全序列卷积神经网络框架,通过 WebSocket 协议,建立应用与语言转写核心引擎的长连接,开发者可实现将连续的音频流内容,实时识别返回对应的文字流内容。
        支持的音频格式: 采样率为16K,采样深度为16bit的pcm_s16le音频

1.2.3 接入要求

内容说明
请求协议ws[s] (为提高安全性,强烈推荐wss)
请求地址ws[s]: //rtasr.xfyun.cn/v1/ws?{请求参数}
注:服务器IP不固定,为保证您的接口稳定,请勿通过指定IP的方式调用接口,使用域名方式调用
接口鉴权签名机制,详见数字签名
字符编码UTF-8
响应格式统一采用JSON格式
开发语言任意,只要可以向讯飞云服务发起WebSocket请求的均可
音频属性采样率16k、位长16bit、单声道
音频格式pcm
数据发送建议音频流每40ms发送1280字节
语言种类中文普通话、中英混合识别、英文,小语种以及中文方言可以到控制台-实时语音转写-方言/语种处添加试用或购买

        Demo 中不包含Android SDK,感觉有一些麻烦,该方案暂时保留,去腾讯云语音识别看看。

        讯飞官方文档:实时语音转写 API 文档 | 讯飞

二、腾讯云实时语音识别

2.1 腾讯云实时语音识别介绍

2.1.1 功能特点

        腾讯云语音识别(ASR)基于深度学习技术,具备较高的语音识别准确性。

        提供实时语音识别和离线语音识别两种类型,满足不同场景需求。

        支持多种语种和方言识别,如中文、英文、粤语等。

2.1.2 优势

        腾讯云作为国内领先的云服务提供商,拥有强大的技术实力和丰富的应用场景。

        提供了丰富的语音识别和语音合成产品,可以满足开发者多样化的需求。

        提供了可视化控制台和详尽的 SDK 和 API 文档,方便开发者进行配置和管理。

2.2 接入流程

2.2.1 注册腾讯云账号

        注册腾讯云账号(需要个人实名认证/企业认证),并在控制台中创建语音识别应用。

2.2.2 获取相关的凭证信息

        获取相关的凭证信息(如SecretId和SecretKey),用于后续的API调用。

2.2.3 下载SDK等相关资料

        直接下载SDK,SDK中包含简易可运行的Demo。

2.2.4 导入SDK和添加其他依赖

        添加录音文件识别 SDK aar,将 asr-realtime-release.aar 放在 libs 目录下,在 App 的 build.gradle 文件中添加。

implementation(name: 'asr-realtime-release', ext: 'aar') implementation 'com.squareup.okhttp3:okhttp:4.2.2' 

2.2.5 添加用户权限

        在工程 AndroidManifest.xml 文件中添加如下权限,在实际项目中还需要动态申请权限。

< uses-permission android:name="android.permission.INTERNET"/>
<!--获取手机录音机使用权限,听写、识别、语义理解需要用到此权限 --> <uses-permission android:name="android.permission.RECORD_AUDIO"/>
<!--读取网络信息状态 --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

        注意:如需在打包或者生成APK的时候进行混淆,请在proguard.cfg中添加如下代码:

-keepclasseswithmembernames class * { # 保持 native 方法不被混淆

native <methods>;

}

-keep public class com.tencent.aai.*

-keep public class com.qq.wx.voice.*

2.2.6 初始化腾讯云SDK

    private void initAAIClient() {
        int appId = xxxxx;
        int projectId = 0; //此参数固定为0;
        String secretId = "xxxx";
        String secretKey = "xxx";
        try {
            /**直接鉴权**/
            // 1. 签名鉴权类,sdk中给出了一个本地的鉴权类,您也可以自行实现CredentialProvider接口,在您的服务器上实现鉴权签名
            if (aaiClient == null) {
                aaiClient = new AAIClient(SparkMessageTencentActivity.this, appId, projectId, secretId, new LocalCredentialProvider(secretKey));
            }
    }

2.2.7 初始化语音识别请求

        AudioRecognizeRequest.Builder builder = new AudioRecognizeRequest.Builder();
        final AudioRecognizeRequest audioRecognizeRequest = builder
                //设置数据源,数据源要求实现PcmAudioDataSource接口,您可以自己实现此接口来定制您的自定义数据源,例如从第三方推流中获
                .pcmAudioDataSource(new AudioRecordDataSource(false))// 使用SDK内置录音器作为数据源,false:不保存音频
                .setEngineModelType("16k_zh") // 设置引擎参数("16k_zh" 通用引擎,支持中文普通话+英文)
                .setFilterDirty(0)  // 0 :默认状态 不过滤脏话 1:过滤脏话
                .setFilterModal(0) // 0 :默认状态 不过滤语气词  1:过滤部分语气词 2:严格过滤
                .setFilterPunc(0) // 0 :默认状态 不过滤句末的句号 1:滤句末的句号
                .setConvert_num_mode(1) //1:默认状态 根据场景智能转换为阿拉伯数字;0:全部转为中文数字。
                .setNeedvad(1) //0:关闭 vad,1:默认状态 开启 vad。语音时长超过一分钟需要开启,如果对实时性要求较高,并且时间较短的输入,建议关闭
                // .setHotWordId("")//热词 id。用于调用对应的热词表,如果在调用语音识别服务时,不进行单独的热词 id 设置,自动生效默认热词;如果进行了单独的热词 id 设置,那么将生效单独设置的热词 id。
                //.setCustomizationId("")//自学习模型 id。如果设置了该参数,那么将生效对应的自学习模型
                .build();

2.2.8 初始化语音识别结果监听器

    final AudioRecognizeResultListener audioRecognizeResultlistener = new AudioRecognizeResultListener() {
        /**
         * 返回分片的识别结果
         * @param request 相应的请求
         * @param result 识别结果
         * @param seq 该分片所在句子的序号 (0, 1, 2...)
         *   此为中间态结果,会被持续修正
         */
        @Override
        public void onSliceSuccess(AudioRecognizeRequest request, AudioRecognizeResult result, int seq) {
            Log.d(TAG, "分片on slice success..");
            Log.d(TAG, "分片slice seq =" + seq + "voiceid =" + result.getVoiceId() + "result = " + result.getText() + "startTime =" + result.getStartTime() + "endTime = " + result.getEndTime());
            Log.d(TAG, "分片on slice success..   ResultJson =" + result.getResultJson());//后端返回的未解析的json文本,您可以自行解析获取更多信息
            //主线程更新UI 实时识别结果
            handlerMain.post(() -> binding.tvVoiceFlowText.setText(result.getText()));
        }

        /**
         * 返回语音流的识别结果
         * @param request 相应的请求
         * @param result 识别结果
         * @param seq 该句子的序号 (1, 2, 3...)
         *     此为稳定态结果,可做为识别结果用与业务
         */
        @Override
        public void onSegmentSuccess(AudioRecognizeRequest request, AudioRecognizeResult result, int seq) {
            Log.d(TAG, "语音流on segment success");
            Log.d(TAG, "语音流segment seq =" + seq + "voiceid =" + result.getVoiceId() + "result = " + result.getText() + "startTime =" + result.getStartTime() + "endTime = " + result.getEndTime());
            Log.d(TAG, "语音流on segment success..   ResultJson =" + result.getResultJson());//后端返回的未解析的json文本,您可以自行解析获取更多信息
        }

        /**
         * 识别结束回调,返回所有的识别结果
         * @param request 相应的请求
         * @param result 识别结果,sdk内会把所有的onSegmentSuccess结果合并返回,如果业务不需要,可以只使用onSegmentSuccess返回的结果
         *    注意:仅收到onStopRecord回调时,表明本次语音流录音任务已经停止,但识别任务还未停止,需要等待后端返回最终识别结果,
         *               如果此时立即启动下一次录音,结果上一次结果仍会返回,可以调用cancelAudioRecognize取消上一次识别任务
         *         当收到 onSuccess 或者  onFailure时,表明本次语音流识别完毕,可以进行下一次识别;
         */
        @Override
        public void onSuccess(AudioRecognizeRequest request, String result) {
//            handler.post(() -> {
//                start.setEnabled(true);
//            });
            Log.d(TAG, "识别结束, onSuccess..");
            Log.d(TAG, "识别结束, result = " + result);
            //最终识别结果,主线程更新UI
            handlerMain.post(() -> sendInputText(result));

        }

        /**
         * 识别失败
         * @param request 相应的请求
         * @param clientException 客户端异常
         * @param serverException 服务端异常
         * @param response   服务端返回的json字符串(如果有)
         *    注意:仅收到onStopRecord回调时,表明本次语音流录音任务已经停止,但识别任务还未停止,需要等待后端返回最终识别结果,
         *               如果此时立即启动下一次录音,结果上一次结果仍会返回,可以调用cancelAudioRecognize取消上一次识别任务
         *         当收到 onSuccess 或者  onFailure时,表明本次语音流识别完毕,可以进行下一次识别;
         */
        @Override
        public void onFailure(AudioRecognizeRequest request, final ClientException clientException, final ServerException serverException, String response) {
            if (response != null) {
                Log.d(TAG, "onFailure response.. :" + response);
            }
            if (clientException != null) {
                Log.d(TAG, "onFailure..:" + clientException);
            }
            if (serverException != null) {
                Log.d(TAG, "onFailure..:" + serverException);
            }
            //识别失败处理,主线程更新UI
            handlerMain.post(() -> {
                setUIInputView();
            });
        }
    };

2.2.9 识别配置及识别状态监听器

    // 4、自定义识别配置
    final AudioRecognizeConfiguration audioRecognizeConfiguration = new AudioRecognizeConfiguration.Builder()
            //分片默认40ms,可设置40-5000,如果您不了解此参数不建议更改
            //.sliceTime(40)
            // 是否使能静音检测,
            .setSilentDetectTimeOut(false)
            // 静音检测超时停止录音可设置>2000ms,setSilentDetectTimeOut为true有效,超过指定时间没有说话将关闭识别;需要大于等于sliceTime,实际时间为sliceTime的倍数,如果小于sliceTime,则按sliceTime的时间为准
            .audioFlowSilenceTimeOut(5000)
            // 音量回调时间,需要大于等于sliceTime,实际时间为sliceTime的倍数,如果小于sliceTime,则按sliceTime的时间为准
            .minVolumeCallbackTime(80)
            .build();

    /**
     * 识别状态监听器
     */
    final AudioRecognizeStateListener audioRecognizeStateListener = new AudioRecognizeStateListener() {

        float minVoiceDb = Float.MAX_VALUE;
        float maxVoiceDb = Float.MIN_VALUE;

        /**
         * 开始录音
         * @param request
         */
        @Override
        public void onStartRecord(AudioRecognizeRequest request) {
            voiceStatType = 1;
            minVoiceDb = Float.MAX_VALUE;
            maxVoiceDb = Float.MIN_VALUE;
            Log.d(TAG, "onStartRecord..");
            handlerMain.post(() -> {
                voiceBuffer.setLength(0);
                binding.tvVoiceFlowText.setText("");
                binding.llPupSoundRecording.setVisibility(View.VISIBLE);
                binding.ivSoundRecordingAnimation.setVisibility(View.VISIBLE);
                voiceStatType = 1;
                setUIVoiceView();
                if (animationDrawable != null) {
                    animationDrawable.start();
                }

            });
        }

        /**
         * 结束录音
         * @param request
         */
        @Override
        public void onStopRecord(AudioRecognizeRequest request) {
            Log.d(TAG, "onStopRecord..");
            handlerMain.post(() -> {
                Log.e(TAG, "ivStopSoundRecording:" + voiceStr);
                try {
                    binding.llPupSoundRecording.setVisibility(View.GONE);
                    binding.ivSoundRecordingAnimation.setVisibility(View.GONE);
                    if (animationDrawable != null) {
                        animationDrawable.stop();
                    }
                    voiceStatType = 9;
                    setUIVoiceView();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });

        }

        /**
         * 返回音频流,
         * 用于返回宿主层做录音缓存业务。
         * 由于方法跑在sdk线程上,这里多用于文件操作,宿主需要新开一条线程专门用于实现业务逻辑
         * @param audioDatas
         */
        @Override
        public void onNextAudioData(final short[] audioDatas, final int readBufferLength) {
            Log.d(TAG, "onNextAudioData..");
        }

        /**
         * 静音检测回调
         * 当设置AudioRecognizeConfiguration  setSilentDetectTimeOut为true时,如触发静音超时,将触发此回调
         * 当setSilentDetectTimeOutAutoStop 为true时,触发此回调的同时会停止本次识别,相当于手动调用了 aaiClient.stopAudioRecognize()
         */
        @Override
        public void onSilentDetectTimeOut() {
            Log.d(TAG, "onSilentDetectTimeOut: ");
            //您的业务逻辑
        }

        /**
         * 音量变化时回调。该方法已废弃
         *
         * 建议使用 {@link #onVoiceDb(float db)}
         *
         * @deprecated 建议使用 {@link #onVoiceDb(float db)}.
         */
        @Override
        public void onVoiceVolume(AudioRecognizeRequest request, final int volume) {
            Log.d(TAG, "onVoiceVolume..");
        }

        /**
         * 音量变化时回调。
         */
        @Override
        public void onVoiceDb(float volumeDb) {
            Log.d(TAG, "onVoiceDb: " + volumeDb);
            handlerMain.post(new Runnable() {
                @Override
                public void run() {
                    if (volumeDb > maxVoiceDb) {
                        maxVoiceDb = volumeDb;
                    }
                    if (volumeDb < minVoiceDb) {
                        minVoiceDb = volumeDb;
                    }
                    if (minVoiceDb != Float.MAX_VALUE && maxVoiceDb != Float.MIN_VALUE) {
//                        voiceDb.setText(getString(R.string.voice_db) + volumeDb
//                                + "(" + minVoiceDb + " ~ " + maxVoiceDb + ")");
                    }
                }
            });
        }
    };

2.2.10 启动语音识别

        new Thread(() -> {
            Log.d(TAG, "startAudioRecognize..");
            if (aaiClient != null) {
                aaiClient.startAudioRecognize(audioRecognizeRequest,
                        audioRecognizeResultlistener,
                        audioRecognizeStateListener,
                        audioRecognizeConfiguration);
            }
            Log.d(TAG, "startAudioRecognize..222");
        }).start();

2.2.11 停止语音识别

if (aaiClient != null) {
    aaiClient.stopAudioRecognize();
}

2.2.12 取消实时语音识别

if (aaiClient != null) {
    //取消语音识别,丢弃当前任务,丢弃最终结果
    boolean taskExist = aaiClient.cancelAudioRecognize();
}

        腾讯云语音识别:实时语音识别-腾讯云

三、选择建议(腾讯云)

        讯飞免费额度:实时语音转写(一年50小时,支持中英文)。

        接入方式:仅支持API接入。

        腾讯云免费额度:实时语音识别(每月5小时)。

        接入方式:支持 Android SDK 相当友好。      ​

        综上所述,讯飞在语音识别领域有较高的知名度和市场占有率,拥有是优秀的Android语音识别解决方案。所以我选择腾讯云

相关推荐

讯飞与腾讯云:Android 语音识别服务对比选择-CSDN博客文章浏览阅读1.9k次,点赞87次,收藏84次。讯飞与腾讯云在Android语音识别领域均表现出色,各具特色。讯飞提供全面的语音识别功能,支持多种语言和离线识别,拥有高知名度和市场占有率,适合高度定制化需求。腾讯云则基于深度学习技术,提供高准确性的语音识别,支持多种语种和方言,且作为领先的云服务提供商,拥有丰富的语音识别和语音合成产品,适合快速接入并希望利用其他云服务的开发者。两者均提供详细的开发文档和API接口,但开发者在选择时应根据自身需求、成本因素和用户评价进行综合考虑,以确保选择最具性价比的方案。https://shuaici.blog.csdn.net/article/details/142849015Android SDK 遇到的坑之讯飞语音合成-CSDN博客文章浏览阅读1.9k次,点赞50次,收藏36次。loadLibrary msc error:java.lang.UnsatisfiedLinkError: dlopen failed: library "libmsc.so" not found组件未安装.(错误码:21002)_组件未安装.(错误码:21002)https://shuaici.blog.csdn.net/article/details/141169429Android SDK 遇到的坑之 AIUI(星火大模型)-CSDN博客文章浏览阅读3.4k次,点赞92次,收藏66次。需要给桌面机器人(医康养)应用做语音指引/控制/健康咨询等功能。AIUI常见错误:唤醒无效;错误码:600103;错误码:600022。_星火aiuihttps://shuaici.blog.csdn.net/article/details/141430041

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2216271.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kafka之消费者组与消费者

消费者&#xff08;Consumer&#xff09;在Kafka的体系结构中是用来负责订阅Kafka中的主题&#xff08;Topic&#xff09;&#xff0c;并从订阅的主题中拉取消息后进行处理。 与其他消息中间件不同&#xff0c;Kafka引入一个逻辑概念——消费组&#xff08;Consumer Group&…

使用excel.js(layui-excel)进行layui多级表头导出,根据单元格内容设置背景颜色,并将导出函数添加到toolbar

本段是菜狗子的碎碎念&#xff0c;解决办法请直接从第二段开始看。layui多级表头的导出&#xff0c;弄了两天才搞定&#xff0c;中途一度想放弃&#xff0c;还好坚持下来了。一开始用的是layui的toolbar里自带的那个导出&#xff0c;但是多级表头没有正常导出&#xff0c;单元格…

FPGA学习(6)-基础语法参数化设计阻塞与非阻塞

目录 1.两种参数化不改变源文件&#xff0c;只改仿真文件的值 2.参数化设计实现模块的重用 2.1不用参数化方法 2.1.1源文件 2.1.2仿真文件 2.1.3仿真波形及实验 2.2 用参数方法 2.2.1调用之前写的led灯闪烁模块&#xff0c;在本源函数中&#xff0c;例化4次调用之前的模…

【pyspark学习从入门到精通7】DataFrames_2

目录 创建 DataFrames 生成我们自己的 JSON 数据 创建 DataFrame 创建临时表 简单的 DataFrame 查询 DataFrame API 查询 SQL 查询 创建 DataFrames 通常&#xff0c;您会通过使用 SparkSession&#xff08;或在 PySpark shell 中调用 spark&#xff09;导入数据来创建 …

SpinalHDL之错误集(一)

本文作为SpinalHDL学习笔记第七十六篇&#xff0c;作为错误集使用&#xff0c;类似高中生的错题集&#xff0c;记录使用SpinalHDL过程中遇到的问题&#xff0c;小到语法错误、版本兼容问题&#xff0c;大到SpinalHDL库函数错误等等&#xff0c;持续更新。 SpinalHDL学习笔记总…

记录 ruoyi-vue-plus在linux 部署遇到的问题

整理 linux 文件不要放在 /, 根目录下&#xff0c;要放在 home 文件夹下。docker 启动mysql 容器&#xff0c;映射的 my.cnf 文件不能设置太高权限&#xff0c;权限太高有安全问题&#xff0c;无法读取。 linux 使用注意事项 docker 文件夹 部署在home文件夹下 总结学习到的…

Asp.Net Core 发布 IIS、docker、Azure、文件夹、AAS、ASF、AWM等

发布 微软资料 微软资料 在 IIS 工作进程 (w3wp.exe) 内托管 ASP.NET Core 应用&#xff0c;称为进程内托管模型。 将 Web 请求转发到运行 Kestrel 服务器的后端 ASP.NET Core 应用&#xff0c;称为进程外托管模型。 发布到IIS 》》》Asp.net 之前 》》》 Asp.net Core …

JavaScript 网页设计案例:使用 Canvas 实现趣味打气球小游戏

JavaScript 网页设计案例&#xff1a;使用 Canvas 实现趣味打气球小游戏 在网页设计中&#xff0c;交互性和趣味性是吸引用户的重要因素。借助 JavaScript 和 HTML5 的 canvas 元素&#xff0c;我们可以轻松实现各种动画效果&#xff0c;今天将带你打造一个有趣的 打气球小游戏…

Vxe vue vxe-table 分享实现打印表格以及同时打印两张表

Vxe vue vxe-table 分享实现打印表格以及同时打印两张表 vxe-table 默认情况下支持单表打印。 在有些情况下&#xff0c;页面上同时有几张表&#xff0c;这时需要一次性打印出来。可以利用 Vxe 自带的分页打印功能&#xff0c;实现多张表同时打印。 效果 点击打印后自动调起预…

Redis --- 第四讲 --- 常用数据结构 --- set、zset

一、set类型的基本介绍 谈到一个术语&#xff0c;这个术语很可能有多种含义。Set一个含义是集合&#xff0c;一个含义是设置。 集合就是把一些有关联数据放到一起。 1、集合中的元素是无序的&#xff01; 2、集合中的元素是不能重复的。 和list类似&#xff0c;集合中的每…

数据治理为何如此简单?

欢迎来文末免费获取数据治理相关PPT和文档 引言 随着大数据技术的迅速发展&#xff0c;企业积累的数据量呈现爆炸式增长。有效的数据管理已经成为企业提高决策效率、增强竞争优势的重要手段。在这样的背景下&#xff0c;数据治理逐渐成为企业数据管理中不可或缺的一环。它不仅…

15分钟学Go 第1天:Go语言简介与特点

Go语言简介与特点 1. Go语言概述 Go语言&#xff08;又称Golang&#xff09;是由谷歌于2007年开发并在2009年正式发布的一种开源编程语言。它旨在简单、高效地进行软件开发&#xff0c;尤其适合于网络编程和分布式系统。 1.1 发展背景 多核处理器&#xff1a;随着计算机硬件…

MFC扩展库BCGControlBar Pro v35.1新版亮点:改进网格控件性能

BCGControlBar库拥有500多个经过全面设计、测试和充分记录的MFC扩展类。 我们的组件可以轻松地集成到您的应用程序中&#xff0c;并为您节省数百个开发和调试时间。 BCGControlBar专业版 v35.1已全新发布了&#xff0c;这个版本改进网格控件的性能、增强工具栏编辑器功能等。 …

hadoop集群搭建-克隆虚拟机,安装jdk,hadoop

2.2 hadoop运行环境的搭建 2.2.1 环境准备 1&#xff09;安装模板虚拟机&#xff0c;IP地址 192.168.10.100&#xff0c;主机名hadoop100&#xff0c;内存41GB&#xff0c;硬盘50GB 2&#xff09;虚拟机配置 首先测试虚拟机是否可以正常上网&#xff0c;测试方法ping www.b…

HarmonyOS Next模拟器异常问题及解决方法

1、问题1&#xff1a;Failed to get the device apiVersion. 解决方法&#xff1a;关闭模拟器清除用户数据重启

centos7.9调整磁盘分区大小

在安装centos7.9时我们一般采用默认分区设置&#xff0c;使用LVM来管理磁盘空间&#xff0c;根分区只有50GB&#xff0c;其余的所有可用空间都分配在/home分区下。可是centos7中大多数的应用软件都是安装在根分区的&#xff0c;在使用过程中经常会出现明明系统还有很大的磁盘空…

CSS 选择器简单回顾

引言 当我们探讨网页设计和开发时, CSS(层叠样式表) 无疑是一个不可或缺的技术, 它使我们能够精确控制网页的外观和布局, 为用户创造出独特的视觉体验、以及良好的交互体验!! 而一个完整的 CSS 规则则是由两个主要部分组成: 选择器和声明块 那么今天我们就来盘点下常见的几种选…

jmeter使用csv数据

背景 使用jmeter对系统进行压测。测试数据存储在了csv中&#xff0c;多线程压测的时候&#xff0c;csv中的一条数据不能多个线程同时使用&#xff0c;数据全部使用过后&#xff0c;需要终止压测。 功能点 从csv读取数据后&#xff0c;完成接口数据拼接。多线程依次从csv文件…

蓝牙HCI的log分析方法

一 前言: Bluetooth HCI log 的最主要功能是用于分析蓝牙设备之间的交互行为是否符合预期,以及是否符合 蓝牙规范之规定。 基本上,在手机应用平台上,除了蓝牙功能无法打开以及蓝牙引起的 system crash 问题之外,蓝牙相 关的问题,均可以通过分析 HCI log 来定位问题。 具…

MacOS Sublime Text 解决中乱码

1. 安装Package Control 官方安装指南 手动安装 通过以此点击菜单 Sublime Text > Preferences > Browse Packages 打开Packages目录找到Packages的同级目录Installed Packages下载PackageControl.sublime-package并保存到Installed Packages中在菜单 Sublime Text &g…