webrtc 3A移植以及实时处理
文章目录
- 前言
- 一、交叉编译
- 1.Pulse Audio webrtc-audio-processing
- 2.交叉编译
- 二、基于alsa进行实时3A处理
- 1.demo源码
- 2.注意项
- 3.效果展示
- 总结
前言
由于工作需要,硬件3A中的AEC效果实在太差,后面使用SpeexDSP的软3A,效果依旧不是很好,猜测是内部时延估计和时延补偿做的并不是很好,于是采用了webrtc的3A算法,这里记录一下3A移植过程。
|版本声明:山河君,未经博主允许,禁止转载
一、交叉编译
1.Pulse Audio webrtc-audio-processing
在linux下,webrtc 3A是比较好移植的,原因是Pulse Audio是支持webrtc 3A插件的,也就是说,不需要我们自己翻墙下载配置webrtc的环境以及编译链路,Pulse Audio已经帮我们做好了这一步,剩下的就是交叉编译的工作。
对应的gitlab地址:Pulse Audio webrtc-audio-processing
2.交叉编译
先选择好版本,截至到当前博客时间,最新版本是1.3.1,网上之前也有介绍的,基本都是0.3版本的
1.0版本和1.0之前的版本最大的区别就是编译器的不同,之前是通过脚本配置,1.0后都是使用meson 进行配置,所以需要下载meson 以及ninja(用于编译webrtc)
meson和代码下载之后,就需要配置交叉编译链路,meson对应交叉编译器环境需要我们自己写meson配置文件,在源文件目录下,打开cross_file.txt,内容如下:
[binaries]
c = '/usr/bin/aarch64-linux-gnu-gcc'
cpp = '/usr/bin/aarch64-linux-gnu-g++'
ar = '/usr/bin/aarch64-linux-gnu-ar'
strip = '/usr/bin/aarch64-linux-gnu-strip'
pkgconfig = '/usr/bin/aarch64-linux-gnu-pkg-config'[host_machine]
system = 'linux'
cpu_family = 'aarch64'
cpu = 'armv8-a'
endian = 'little'[paths]
prefix = '/home/aaron/workplace/webrtc-audio-processing/build'
在源文件目录下创建编译缓存目录以及安装目录
meson . build -Dprefix=$PWD/install --cross-file=cross_file.txt
ninja -C build
ninja -C build install
最后在install目录下可以看到编译好的文件
二、基于alsa进行实时3A处理
1.demo源码
编译好的完整demo下载:demo下载,如果没有积分的话就自己编译,这里只是少了demo的脚本
#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>
#include <pthread.h>
#include <errno.h>
#include <mutex>
#include "modules/audio_processing/include/audio_processing.h"constexpr int sample_rate_hz = 16000; // 假设采样率为16kHz
constexpr size_t num_channels = 1; // 假设单声道
constexpr size_t frame_size = sample_rate_hz / 100; // 10ms 帧大小#define CHANNELS 2
#define SAMPLE_RATE 16000
#define PERIOD_SIZE 160
#define BUFFER_SIZE (PERIOD_SIZE * 2)
bool gRun = true;typedef struct
{snd_pcm_t *playback_handle;FILE *pcm_file;int8_t m_pPlayoutBuffer[PERIOD_SIZE * 2 * 2];int m_nPlayoutBufferSizeIn20MS = PERIOD_SIZE * 2 * 2;int m_nPlayoutFramesLeft = 0;snd_pcm_t *capture_handle;FILE *pcm_out_file;int8_t m_pRecordBuffer[PERIOD_SIZE * 2 * 2];int m_nRecordBufferSizeIn20MS = PERIOD_SIZE * 2 * 2;int m_nRecordingFramesLeft = PERIOD_SIZE;FILE *pcm_3a_file;FILE *pcm_ref_file;int8_t m_pRefBuffer[PERIOD_SIZE * 2];int8_t m_p3ABuffer[PERIOD_SIZE * 2]; // in byteint8_t m_pNearBuffer[PERIOD_SIZE * 2]; // in bytertc::scoped_refptr<webrtc::AudioProcessing> apm;
} audio_data_t;void monoTurnStereo(const int16_t *pSrc, int16_t *pDts, size_t size)
{for (int j = 0; j < size; j++){pDts[2 * j] = pSrc[j];pDts[2 * j + 1] = pSrc[j];}
}void stereoTurnMono(const unsigned char *pSrc, unsigned char *pDts, size_t size)
{int nLeftCount = 0;for (size_t i = 0; i < size; i += 4){pDts[nLeftCount] = pSrc[i];pDts[nLeftCount + 1] = pSrc[i + 1];nLeftCount += 2;}
}int32_t errorRecovery(int32_t nRet, snd_pcm_t *pDeviceHandle)
{int st = snd_pcm_state(pDeviceHandle);printf("Trying to recover from %s error: %s nRet:(%d) (state:%d)\n",((snd_pcm_stream(pDeviceHandle) ==SND_PCM_STREAM_CAPTURE)? "capture": "playout"),snd_strerror(nRet),nRet,st);int res = snd_pcm_recover(pDeviceHandle, nRet, 1);if (0 == res){printf("Recovery - snd_pcm_recover OK\n");if ((nRet == -EPIPE || nRet == -ESTRPIPE) &&snd_pcm_stream(pDeviceHandle) == SND_PCM_STREAM_CAPTURE){// For capture streams we also have to repeat the explicit start()// to get data flowing again.int nRet = snd_pcm_start(pDeviceHandle);if (nRet != 0){printf("Recovery - snd_pcm_start error: %d\n", nRet);return -1;}}if ((nRet == -EPIPE || nRet == -ESTRPIPE) &&snd_pcm_stream(pDeviceHandle) == SND_PCM_STREAM_PLAYBACK){// For capture streams we also have to repeat the explicit start() to get// data flowing again.snd_pcm_state_t state = snd_pcm_state(pDeviceHandle);if (state != SND_PCM_STATE_PREPARED){snd_pcm_prepare(pDeviceHandle);}int nRet = snd_pcm_start(pDeviceHandle);if (nRet != 0){printf("Recovery - snd_pcm_start error: %s\n", snd_strerror(nRet));return -1;}}return -EPIPE == nRet ? 1 : 0;}else{printf("Unrecoverable alsa stream error: %d\n", res);}return res;
}void *playback_thread(void *arg)
{printf("playback_thread\n");audio_data_t *data = (audio_data_t *)arg;const int policy = SCHED_FIFO;const int min_prio = sched_get_priority_min(policy);const int max_prio = sched_get_priority_max(policy);sched_param param;const int top_prio = max_prio - 1;const int low_prio = min_prio + 1;param.sched_priority = top_prio;pthread_setschedparam(pthread_self(), policy, ¶m);while (gRun){int nRet;snd_pcm_sframes_t sndFrames;snd_pcm_sframes_t sndAvailFrames;sndAvailFrames = snd_pcm_avail_update(data->playback_handle);if (sndAvailFrames < 0){printf("playout snd_pcm_avail_update error: %s\n", snd_strerror(sndAvailFrames));errorRecovery(sndAvailFrames, data->playback_handle);continue;}else if (sndAvailFrames == 0){nRet = snd_pcm_wait(data->playback_handle, 2);// if (nRet == 0)// printf("playout snd_pcm_wait timeout\n");continue;}if (data->m_nPlayoutFramesLeft <= 0){size_t frames = fread(data->m_pRefBuffer, 2, PERIOD_SIZE, data->pcm_file);if (frames == 0 || frames != PERIOD_SIZE){ // 文件播放完毕,重新开始fseek(data->pcm_file, 0, SEEK_SET);continue;}monoTurnStereo((int16_t *)data->m_pRefBuffer, (int16_t *)data->m_pPlayoutBuffer, PERIOD_SIZE);data->m_nPlayoutFramesLeft = frames;}if ((uint32_t)(sndAvailFrames) > data->m_nPlayoutFramesLeft){sndAvailFrames = (uint32_t)data->m_nPlayoutFramesLeft;}int size = snd_pcm_frames_to_bytes(data->playback_handle, data->m_nPlayoutFramesLeft);sndFrames = snd_pcm_writei(data->playback_handle, &data->m_pPlayoutBuffer[data->m_nPlayoutBufferSizeIn20MS - size], sndAvailFrames);if (sndFrames < 0){printf("playout snd_pcm_writei error: %s\n", snd_strerror(sndFrames));data->m_nPlayoutFramesLeft = 0;errorRecovery(sndFrames, data->playback_handle);continue;}else{fwrite(&data->m_pRefBuffer[PERIOD_SIZE * 2 - data->m_nPlayoutFramesLeft * 2], 1, sndFrames * 2, data->pcm_ref_file);data->m_nPlayoutFramesLeft -= sndFrames;}}return NULL;
}void *capture_thread(void *arg)
{printf("capture_thread\n");audio_data_t *data = (audio_data_t *)arg;const int policy = SCHED_FIFO;const int min_prio = sched_get_priority_min(policy);const int max_prio = sched_get_priority_max(policy);sched_param param;const int top_prio = max_prio - 1;const int low_prio = min_prio + 1;param.sched_priority = top_prio;pthread_setschedparam(pthread_self(), policy, ¶m);while (gRun){int nRet;snd_pcm_sframes_t sndFrames;snd_pcm_sframes_t sndAvailFrames;int8_t buffer[data->m_nRecordBufferSizeIn20MS];sndAvailFrames = snd_pcm_avail_update(data->capture_handle);if (sndAvailFrames < 0){printf("capture snd_pcm_avail_update error: %s\n", snd_strerror(sndAvailFrames));errorRecovery(sndAvailFrames, data->capture_handle);continue;}else if (sndAvailFrames == 0){continue;}if ((uint32_t)(sndAvailFrames) > data->m_nRecordingFramesLeft)sndAvailFrames = data->m_nRecordingFramesLeft;sndFrames = snd_pcm_readi(data->capture_handle, buffer, sndAvailFrames);if (sndFrames < 0){printf("capture snd_pcm_readi error: %s\n", snd_strerror(sndFrames));errorRecovery(sndFrames, data->capture_handle);continue;}else if (sndFrames > 0){int nLeftSize = snd_pcm_frames_to_bytes(data->capture_handle, data->m_nRecordingFramesLeft);int size = snd_pcm_frames_to_bytes(data->capture_handle, sndFrames);memcpy(&data->m_pRecordBuffer[data->m_nRecordBufferSizeIn20MS - nLeftSize], buffer, size);data->m_nRecordingFramesLeft -= sndFrames;}if (!data->m_nRecordingFramesLeft){data->m_nRecordingFramesLeft = PERIOD_SIZE;stereoTurnMono((unsigned char *)data->m_pRecordBuffer, (unsigned char *)data->m_pNearBuffer, PERIOD_SIZE * 2 * 2);fwrite(data->m_pNearBuffer, 1, PERIOD_SIZE * 2, data->pcm_out_file);webrtc::StreamConfig stream_config(sample_rate_hz, num_channels);if (data->apm->ProcessReverseStream((int16_t *)data->m_pRefBuffer, stream_config, stream_config, (int16_t *)data->m_pRefBuffer) != webrtc::AudioProcessing::kNoError){printf("ProcessReverseStream fail\n");}if (data->apm->ProcessStream((int16_t *)data->m_pNearBuffer, stream_config, stream_config, (int16_t *)data->m_p3ABuffer) != webrtc::AudioProcessing::kNoError){printf("ProcessStream fail\n");}fwrite(data->m_p3ABuffer, 1, PERIOD_SIZE * 2, data->pcm_3a_file);}}return NULL;
}int setup_pcm_device(snd_pcm_t **handle, const char *device, snd_pcm_stream_t stream)
{snd_pcm_hw_params_t *params;int err;if ((err = snd_pcm_open(handle, device, stream, SND_PCM_NONBLOCK)) < 0){printf("无法打开 PCM 设备 %s: %s\n", device, snd_strerror(err));return err;}snd_pcm_hw_params_alloca(¶ms);snd_pcm_hw_params_any(*handle, params);snd_pcm_hw_params_set_access(*handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);snd_pcm_hw_params_set_format(*handle, params, SND_PCM_FORMAT_S16_LE);snd_pcm_hw_params_set_channels(*handle, params, CHANNELS);snd_pcm_hw_params_set_rate(*handle, params, SAMPLE_RATE, 0);snd_pcm_hw_params_set_period_size(*handle, params, PERIOD_SIZE, 0);snd_pcm_hw_params_set_buffer_size(*handle, params, PERIOD_SIZE * 4);if ((err = snd_pcm_hw_params(*handle, params)) < 0){printf("设置 PCM 参数失败: %s\n", snd_strerror(err));snd_pcm_close(*handle);return err;}return 0;
}int main(int argc, char *argv[])
{audio_data_t data;if ((data.pcm_file = fopen("./far.pcm", "rb")) == NULL ||(data.pcm_3a_file = fopen("./3a.pcm", "wb")) == NULL ||(data.pcm_out_file = fopen("./near.pcm", "wb")) == NULL ||(data.pcm_ref_file = fopen("./ref.pcm", "wb")) == NULL){printf("fail to open file\n");return -1;}// 3adata.apm = webrtc::AudioProcessingBuilder().Create();webrtc::AudioProcessing::Config config;// 噪声抑制配置config.noise_suppression.enabled = true;config.noise_suppression.level = webrtc::AudioProcessing::Config::NoiseSuppression::Level::kHigh;// 增益控制配置config.gain_controller1.enabled = true;config.gain_controller1.mode = webrtc::AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;config.gain_controller1.target_level_dbfs = 3; // 目标输出电平// 回声抑制配置config.echo_canceller.enabled = true;config.echo_canceller.mobile_mode = false; // 如果是移动设备可以设置为 true// 语音活动检测(可选)config.voice_detection.enabled = true;// 应用配置data.apm->ApplyConfig(config);//if (setup_pcm_device(&data.playback_handle, "hw:0,0", SND_PCM_STREAM_PLAYBACK) < 0){fclose(data.pcm_file);return -1;}if (setup_pcm_device(&data.capture_handle, "hw:0,0", SND_PCM_STREAM_CAPTURE) < 0){snd_pcm_close(data.playback_handle);fclose(data.pcm_file);return -1;}pthread_t play_thread, record_thread;pthread_create(&play_thread, NULL, playback_thread, &data);int nRet = snd_pcm_prepare(data.playback_handle);if (nRet < 0){printf("playout snd_pcm_prepare failed (%s)\n", snd_strerror(nRet));}pthread_create(&record_thread, NULL, capture_thread, &data);nRet = snd_pcm_prepare(data.capture_handle);if (nRet < 0){printf("capture snd_pcm_prepare failed:%s \n", snd_strerror(nRet));}nRet = snd_pcm_start(data.capture_handle);if (nRet < 0){printf("capture snd_pcm_start err:%s\n", snd_strerror(nRet));nRet = snd_pcm_start(data.capture_handle);if (nRet < 0){printf("capture snd_pcm_start 2nd try err:%s\n", snd_strerror(nRet));return false;}}getchar();gRun = false;pthread_join(play_thread, NULL);pthread_join(record_thread, NULL);snd_pcm_close(data.playback_handle);snd_pcm_close(data.capture_handle);fclose(data.pcm_file);fclose(data.pcm_out_file);fclose(data.pcm_3a_file);fclose(data.pcm_ref_file);printf("end................... \n");return 0;
}
2.注意项
- webrtc audio processing是基于10ms为一帧进行处理的
- 当前版本中可以设置3A配置等级,具体3A参数调参请参考我另一篇文章音频3A一——webrtc源码3A的启用方法和具体流程
- 对于资源消耗,如果没有对资源特别要求,或者其他特殊情况,尽量不要追求类似于WebRtcAec_Process,WebRtcAgc_Process这种方式单独使用3A的某一个模块,而是通过audio_processing进行处理
- 对于时延,如果有固定时延,应该对于AEC进行设置
3.效果展示
远端参考信号
近端采集信号
回声消除后的信号
总结
webrtc不愧是音视频领域的顶尖,值得我们学习的东西太多了。实际上demo里对于设备的读写,也是从webrtc中摘录出来的。
如果对您有所帮助,请帮忙点个赞吧!
相关文章:
webrtc 3A移植以及实时处理
文章目录 前言一、交叉编译1.Pulse Audio webrtc-audio-processing2.交叉编译 二、基于alsa进行实时3A处理1.demo源码2.注意项3.效果展示 总结 前言 由于工作需要,硬件3A中的AEC效果实在太差,后面使用SpeexDSP的软3A,效果依旧不是很好&#…...
Android so库的编译
在没弄明白so库编译的关系前,直接看网上博主的博文,常常会觉得云里雾里的,为什么一会儿通过Android工程cmake编译,一会儿又通过NDK命令去编译。两者编译的so库有什么区别? android版第三方库编译总体思路: 对于新手小白来说搞明白上面的总体思路图很有必…...
Reachy 2,专为AI与机器人实验室打造的卓越开源双臂移动操作平台!
近期,花粉机器人(POLLEN ROBOTICS)隆重推出Reachy 2仿生机器人——下一代开源操作平台,为AI与机器人实验室带来理想的双臂移动操作科研平台! Reachy 2的仿生性: 》拥有两个基于Maxon无刷电机的仿生7自由度…...
Jest 测试异步函数
异步编程的发展历史 异步函数,就不用我描述了,JS是单线程的,所以没有办法处理异步问题,但是可以通过其他的机制实现 回调函数 例如,我们写一个定时器,在函数fetchData中,有一个延时处理的函数,但是,你有不能等他,如果他是一年呢? 所以,我们给他一个回调函数,来等他执行完返回处…...
linux安全管理-防火墙配置
1. 开启系统防火墙 1、检查内容 检查操作系统是否开启防火墙; 2、配置要求 操作系统开启防火墙; 3、配置方法 systemctl status firewalld ##查看系统防火墙运行状态 systemctl start firewalld ##启动防火墙 systemctl restart firewalld ##重启防火墙…...
Blender 运行python脚本
Blender 运行python脚本 步骤 1:打开 Blender 首先,打开 Blender 软件。你可以从官方网站 [blender.org]( 下载最新的 Blender 版本,并按照安装向导进行安装。 步骤 2:打开“文本编辑器”面板 在 Blender 的默认布局中ÿ…...
Three.js CSS2D/CSS3D渲染器
在Three.js开发过程中,有时需要将 HTML 元素与 Three.js 渲染的 3D 场景相结合,这就需要用到 CSS2DRenderer 和 CSS3DRenderer。本文将详细介绍这两种渲染器的原理及其应用 一、CSS2DRenderer 渲染器 概述 CSS2DRenderer 渲染器用于在 3D 场景中渲染纯…...
centos7 yum install 失败,mirrorlist.centos.org连接不上
由于centos7停止支持,导致mirrorlist.centos.orgdns解析都是失效啦,yum命令没法安装程序. 换一个镜像源就好 sudo cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak sudo curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/…...
BGP协议路由黑洞
一、实验环境 1、分公司与运营商AS自治系统内运行IGP路由协议OSPF、RIP或静态路由,AS自治系统内通过IBGP路由协议建立BGP邻居关系。 2、公司AS自治系统与运营商AS自治系统间运行EBGP路由协议。 3、通过loopback建立IBGP与EBGP邻居关系,发挥loopback建立…...
学习ASP.NET Core的身份认证(基于Session的身份认证1)
ASP.NET Core使用Session也可以实现身份认证,关于Session的介绍请见参考文献5。基于Session的身份认证大致原理就是用户验证成功后将用户信息保存到Session中,然后在其它控制器中从Session中获取用户信息,用户退出时清空Session数据。百度基于…...
《Docker Registry(镜像仓库)详解》
一、引言 在容器化技术日益普及的今天,Docker 已成为众多开发者和企业的首选工具。而 Docker Registry(镜像仓库)作为 Docker 生态系统中的重要组成部分,负责存储和分发 Docker 镜像。本文将深入探讨 Docker Registry 的概念、功能…...
Mybatis
1 什么是MyBatis MyBatis是一个优秀的持久层框架,它对JDBC操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、 结果集检索等JDBC繁杂的过程代码 。…...
uniapp学习(010-3 实现H5和安卓打包上线)
零基础入门uniapp Vue3组合式API版本到咸虾米壁纸项目实战,开发打包微信小程序、抖音小程序、H5、安卓APP客户端等 总时长 23:40:00 共116P 此文章包含第114p-116p的内容 文章目录 H5配置文件设置开始打包上传代码 安卓设置模拟器启动设置基础配置设置图标启动界面…...
IPGuard与Ping32结合,提供企业级数据加密与防泄密解决方案,全面保障敏感数据安全
随着数字化转型的深入推进,企业面临着日益复杂的安全挑战。如何在确保数据流通的同时,保障企业的核心资产不被泄露,是每个企业必须面对的难题。为此,Ping32与IPGuard联合推出了一套全面的企业级数据加密与防泄密解决方案ÿ…...
爬虫与反爬-旋转验证码突破方案(知名短视频、TK海外版 及 某东等等)
概述:文本对旋转验证码进行了突破及讲述了实现原理,代码使用纯算法 OpenCV,使用代价较小同时不用安装一大堆AI训练相关的模组,方便且能够快速上手 当前亲自验证了能够支持的网站:国内知名短视频平台、海外版 以及 某东…...
霍夫变换:原理剖析与 OpenCV 应用实例
简介:本文围绕霍夫变换相关内容展开,先是讲解霍夫变换基本原理,包含从 xy 坐标系到 kb 坐标系及极坐标系的映射等。接着介绍了 cv2.HoughLines、cv2.HoughLinesP 概率霍夫变换、cv2.HoughCircles 霍夫圆变换的函数用法、参数含义、与常规霍夫…...
虚拟机之间复制文件
在防火墙关闭的前提下,您可以通过几种不同的方法将文件从一个虚拟机复制到另一个虚拟机。这里,我们假设您想要从 IP 地址为 192.168.4.5 的虚拟机上的 /tmp 文件夹复制文件到当前虚拟机(192.168.4.6)的 /tmp 文件夹下。以下是几种…...
漏洞管理与补丁管理详解:系统安全的基石
文章目录 漏洞管理与补丁管理详解:系统安全的基石什么是漏洞管理?什么是补丁管理?漏洞管理与补丁管理的联系与区别实施漏洞管理与补丁管理的最佳实践 漏洞管理与补丁管理详解:系统安全的基石 在网络安全的防护体系中,…...
ArrayList与LinkedList的区别是什么?
ArrayList与LinkedList是Java集合框架中实现List接口的两种常见类,它们各自具有独特的数据结构和特点,适用于不同的应用场景。 一、底层数据结构 ArrayList和LinkedList的底层数据结构是它们之间最本质的区别。 ArrayList: ArrayList是基于…...
《Java-数组》
《Java-数组》 1.数组介绍 概念:数组是一种容器,用来存储同种数据类型的多个值。注意:数组容器在存储数据的时候,需要结合隐式转换考虑; 2.数组的定义和初始化 2.1数组定义 定义格式1(常用)…...
Docker 实战:搭建本地 Registry 私有镜像仓库及批量导入脚本
前言:在我之前的博客中,我分享了 Harbor 仓库搭建的详细操作步骤。然而,在实际的生产环境中,并非每个 Docker 环境都需要部署一个规模庞大的 Harbor 仓库。有时,一个轻量级的本地 Registry 私有镜像仓库会更为便捷。本…...
MySQL 启动失败问题分析与解决方案:`mysqld.service failed to run ‘start-pre‘ task`
目录 前言1. 问题背景2. 错误分析2.1 错误信息详解2.2 可能原因 3. 问题排查与解决方案3.1 检查 MySQL 错误日志3.2 验证 MySQL 配置文件3.3 检查文件和目录权限3.4 手动启动 MySQL 服务3.5 修复 systemd 配置文件3.6 验证依赖环境 4. 进一步优化与自动化处理结语 前言 在日常…...
java-分而治之算法
分而治之(Divide and Conquer)算法是一种解决问题的策略,它将一个复杂的问题分解成若干个相同或相似的子问题,递归地解决这些子问题,然后将它们的解合并以解决原始问题。这种算法通常用于排序、搜索、数学计算等领域。…...
透明化教育管理:看板如何提升班级整体效率
随着教育信息化的不断推进,传统的教学和班级管理方式逐渐暴露出时间紧、任务繁、多任务并行等问题。看板管理,作为一种高效的可视化工具,正在成为教师管理教学、提升班级协作与互动的重要利器。通过透明化、系统化的管理方式,看板…...
UDP客户端服务器通信
在这篇博客中,我们将探索 UDP(用户数据报协议) 通信,简要地说,UDP 是一种无连接、快速但不可靠的通信协议,适用于需要快速数据传输但对丢包容忍的场景,比如视频流和在线游戏。就像《我是如此相信…...
helm手动部署Kafka集群
1、到指定node节点创建pv需挂载的目录,若有分布式存储可忽略 mkdir -p /data/kafka-data-0 mkdir -p /data/kafka-data-1 mkdir -p /data/kafka-data-2 mkdir -p /data/kafka-zookeeper-data-0 2、创建pvc ---apiVersion: v1kind: PersistentVolumemetadata:n…...
vue3 ajax获取json数组排序举例
使用axios获取接口数据 可以在代码中安装axios包,并写入到package.json文件: npm install axios -S接口调用代码举例如下: const fetchScore async () > {try {const res await axios.get(http://127.0.0.1:8000/score/${userInput.v…...
c/c++ 用easyx图形库写一个射击游戏
#include <graphics.h> #include <conio.h> #include <stdlib.h> #include <time.h>// 定义游戏窗口的大小 #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600// 定义玩家和目标的尺寸 #define PLAYER_SIZE 50 #define TARGET_SIZE 20// 玩家的结构…...
大数据新视界 -- 大数据大厂之 Hive 数据安全:权限管理体系的深度解读(上)(15/ 30)
💖💖💖亲爱的朋友们,热烈欢迎你们来到 青云交的博客!能与你们在此邂逅,我满心欢喜,深感无比荣幸。在这个瞬息万变的时代,我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…...
gitee:创建仓库,存入本地文件至仓库
一、git下载 git:下载与安装-CSDN博客https://blog.csdn.net/weixin_46001736/article/details/144107485?sharetypeblogdetail&sharerId144107485&sharereferPC&sharesourceweixin_46001736&spm1011.2480.3001.8118 二、创建仓库 1、主页面->右上角新增…...
联想品牌的电脑 Bios 快捷键是什么?如何进入 Bios 设置?
在某些情况下,您可能需要通过U盘来安装操作系统或进行系统修复。对于联想电脑用户来说,了解如何设置U盘作为启动设备是非常有用的技能之一。本文简鹿办公将指导您如何使用联想电脑的 U 盘启动快捷键来实现这一目标。 联想笔记本 对于大多数联想笔记本电…...
微信小程序用户登录页面制作教程
微信小程序用户登录页面制作教程 前言 在微信小程序的开发过程中,用户登录是一个至关重要的功能。通过用户登录,我们可以为用户提供个性化的体验,保护用户数据,并实现更复杂的业务逻辑。本文将为您详细讲解如何制作一个用户登录页面,包括设计思路、代码示例以及实现细节…...
Flink细粒度的资源管理
Apache Flink致力于为所有应用程序自动导出合理的默认资源需求。对于希望根据其特定场景微调其资源消耗的用户,Flink提供了细粒度的资源管理。这里我们就来看下细粒度的资源管理如何使用。(注意该功能目前仅对DataStream API有用) 1. 适用场景 使用细粒度的资源管理的可能…...
Jenkins环境搭建及简单介绍
一、jenkins介绍 1、持续集成(CI) Continuous integration 持续集成 团队开发成员每天都有集成他们的工作,通过每个成员每天至少集成一次,也就意味着一天有可 能多次集成。在工作中我们引入持续集成,通过持续集成自动…...
如何还原 HTTP 请求日志中的 URL 编码参数?详解 %40 到 @
在记录HTTP请求的日志中出现了这样的情况: 2024-11-20 11:12:49 INFO network_request gz_login 96 Body: countryAbbrCN&countryCode86&email1222405567%40qq.com&password12354e50456db124f9f34e2789308733&type1 出现这种情况的原因是&#x…...
box-im学习
box-im gitee代码 box-im 语雀文档 box-im 在线体验 部署说明 需要启动下列服务 ## ## 1、启动minio ## MINIO_ROOT_USERminioadmin MINIO_ROOT_PASSWORDxxx nohup /boxim/minio/minio server /boxim/minio/data --console-address ":9001" --address "…...
faiss库中ivf-sq(ScalarQuantizer,标量量化)代码解读-6
调试 经过gdb调试获取的调用栈内容如下,链接: 步骤函数名称文件位置说明1faiss::IndexFlatCodes::add/faiss/IndexFlatCodes.cpp:24在 add 方法中,检查是否已经训练完成,准备添加向量到索引中。2std::vector<unsigned char&g…...
flutter开发环境—Windows
一、简介 我们使用最新版的flutter版本安装。 参考链接 名称地址官方网站https://flutter.dev/官方中文网站文档 | Flutter 中文文档 - Flutter 中文开发者网站 - Flutter软件下载路径https://docs.flutter.dev/release/archive?tabwindows 二、操作流程 2.1 下载软件 点…...
【计网】自定义序列化反序列化(二) —— 实现网络版计算器【上】
🌎 实现网络版计算器【上】 文章目录: 实现网络版计算器【上】 自定义协议 制定自定义协议 Jsoncpp序列化反序列化 Json::Value类 Jsoncpp序列化 Jsoncpp反序列化 自定义协议序列化反序列化 …...
Harbor安装、HTTPS配置、修改端口后不可访问?
Harbor安装、HTTPS配置、修改端口后不可访问? 大家好,我是秋意零。今天分享Harbor相关内容,安装部分可完全参考官方文档,写的也比较详细。 安装Harbor 官方文档:https://goharbor.io/docs/2.12.0/install-config/ …...
React中高阶组件HOC详解
高阶组件(Higher-Order Component,简称 HOC)是 React 中的一种设计模式,用于复用组件逻辑。它本质上是一个函数,接收一个组件作为参数,并返回一个新的组件。 1. HOC 的定义 HOC 是一个函数,类…...
网络原理(一)—— http
什么是 http http 是一个应用层协议,全称为“超文本传输协议”。 http 自 1991 年诞生,目前已经发展为最主流使用的一种应用层协议。 HTTP 往往基于传输层的 TCP 协议实现的,例如 http1.0,http1.0,http2.0 http3 是…...
redis学习面试
1、数据类型 string 增删改查 set key valueget keydel kstrlen k 加减 incr articleincrby article 3decr articledecyby article 取v中特定位置数据 getrange name 0 -1getrange name 0 1setrange name 0 x 设置过期时间 setex pro 10 华为 等价于 set pro 华为expire pro…...
前端工程化18-邂逅Promise(待更新)
6、邂逅Promise 6.1、函数对象与实例对象 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>准备_函数对象与实例对象</title> </head> <body><script>/* 函数对象、实例对象…...
Linux(ubuntu)系统的一些基本操作和命令(持续更新)
操作: Ctrl Alt T(打开命令终端) Ctrl Shift (放大命令终端窗口) Ctrl c(退出当前在终端运行的程序) 在命令终端窗口按Tab键可以补全要写的命令 命令: pwd(查…...
IDEA Mac快捷键(自查询使用)
Editing(编辑) Control Space 基本的代码补全(补全任何类、方法、变量)Control Shift Space 智能代码补全(过滤器方法列表和变量的预期类型)Command Shift Enter 自动结束代码,行末自动添…...
认识redis 及 Ubuntu安装redis
文章目录 一. redis概念二. redis应用场景二. redis的特性四. 使用Ubuntu安装redis 一. redis概念 redis 是在内存中存储数据的中间件, 用在分布式系统 redis是客户端服务器结构的程序, 客户端服务器之间通过网络来通信 二. redis应用场景 redis可用作数据库 类似MySQL, 但…...
6.结果处理组件之ResponseHandler
前言 feign发送完请求后, 拿到返回结果, 那么这个返回结果肯定是需要经过框架进一步处理然后再返回到调用者的, 其中ResponseHandler就是用来处理这个返回结果的, 这也是符合正常思维的处理方式, 例如springmvc部分在调用在controller端点前后都会增加扩展点。 从图中可以看得…...
【C#】调用外部应用
以WINFORM应用程序为例,在C#应用程序中调用PYTHON程序(Matplotlib绘制图形程序),将调用PYTHON程序生成的窗口程序嵌入在WINFORM窗口中 窗口程序类 using System; using System.Collections.Generic; using System.Data; using S…...
JavaWeb--JDBC
JDBC(Java Database Connectivity,Java数据库连接)是一种Java API,可以让Java程序连接到数据库并进行数据的操作。它是Java平台的一部分,由Sun Microsystems(现为Oracle Corporation的一部分)开…...