当前位置: 首页 > news >正文

【音视频|ALSA】基于alsa-lib开发ALSA应用层程序--附带源码

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭基于alsa-lib开发ALSA应用层程序🍭
😎金句分享😎:🍭盖士人读书,第一要有志,第二要有识,第三要有恒。有志则断不甘为下流,有识则知学问无尽,不敢以一得自足,如河伯之观海,如井蛙之窥天,皆无识者也。有恒则断无不成之事,此三者缺一不可。 ——《曾国藩家书》🍭

【音视频|ALSA】ALSA是什么?ALSA框架详细介绍
【音视频|ALSA】SS528开发板编译Linux内核ALSA驱动、移植alsa-lib、采集与播放usb耳机声音

目录

  • 一、ALSA应用层开发基础知识
  • 二、alsa-lib常用函数
  • 三、编写ALSA应用层程序
    • 3.1 alsa播放程序开发--alsa-playback.c
    • 3.2 alsa录制音频程序开发--alsa-capture.c
  • 四、XRUN( underrun和overrun)
  • 五、总结


在这里插入图片描述

一、ALSA应用层开发基础知识

  • sample:样本,采样点。数字音频最小单位,其大小与位宽有关,一般为8bit(1个字节)、16bit(2个字节);
  • channel:声道,一般单声道(mono)和立体声(stereo),还有一些多声道如5.1声道。
  • frame:帧,一个完整的声音单元,即单次采样的所有声道的数据。frame=sample*channel
    例如:48Khz、16位的立体声PCM流的1帧是4个字节。
  • sample rate:采样率,即每秒的采样次数。如果采样率为48kHz,则说明一秒采样48000帧。
  • period size:周期大小,是每次硬件中断之间的帧数。
  • buffer size:缓冲区大小,必须大于一个周期的大小。一般为周期大小的2倍。单位也是帧数。

在这里插入图片描述

例子:
结合上面的知识点,这里以48kHz、16bit的立体声音频流举例:

  • 16bit则每个样本为2个字节,
  • 立体声表示有2个声道,
  • 48kHz 表示每秒有48000个音频帧。

由此可以计算出每秒钟传输的数据大小:2 * 2 * 48000=192000字节;

现在如果ALSA每秒钟产生一个硬件中断,在每秒结束时,我们需要准备好192000字节;
如果它每半秒中断一次,对于同一个流,我们需要在每次中断时准备好192000/2 = 96000字节;
如果每100毫秒发生一次中断,我们需要在每次中断时准备好192000*(0.1/1) = 19200字节。

我们可以通过设置周期大小(以帧为单位)来控制PCM中断的产生时间。
如果我们将48kHz、16bit的立体声音频流的period size设置为4800帧(也就是480022=19200字节),则每19200字节就会产生一个中断,也就是100ms。
相应地,buffer size至少应为2*period_size = 2*4800= 9600帧(960022 = 38400字节)。

实际编程中,可能需要计算一个周期的总字节数period bytes,就是等于period size乘以每一帧的大小。同样的,buffer的总字节数buffer bytes等于buffer size乘以一帧大小。

如果已知音频的采样率、通道数、位宽、周期数,则buffer sizebuffer timeperiod sizeperiod time 这四个值可以相互推断出来:
以48000Hz采样率、2声道、16bit、4周期来举例,这样的音频流一秒钟的帧数是48000帧,如果buffer size是48000,则buffer time刚好就是一秒;如果buffer time是500ms,则buffer size是24000帧。
period size=buffer size/周期数period time=buffer time/周期数

在这里插入图片描述

二、alsa-lib常用函数

alsa-lib的函数声明在pcm.h,总共可以分为16个模块:

  • PCM Interface
  • Stream Information
  • Hardware Parameters
  • Software Parameters
  • Access Mask Functions
  • Format Mask Functions
  • Subformat Mask Functions
  • Status Functions
  • Description Functions
  • Debug Functions
  • Direct Access (MMAP) Functions
  • Helper Functions
  • Hook Extension
  • Scope Plugin Extension
  • Simple setup functions
  • Deprecated Functions

可以在官方文档查看对应的模块函数说明:
https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html
在这里插入图片描述

下表介绍一些常用的函数:

函数说明
snd_pcm_open根据pcm设备名字打开一个pcm设备
snd_pcm_hw_params_malloc使用标准malloc分配无效的snd_pcm_hw_params_t
snd_pcm_hw_params_any用PCM的完整配置空间填充参数。
snd_pcm_hw_params_set_access将配置空间限制为仅包含一种访问类型。
snd_pcm_hw_params_set_format将配置空间限制为仅包含一种格式。
snd_pcm_hw_params_set_channels将配置空间限制为仅包含一个通道计数。
snd_pcm_hw_params_set_rate_near将配置空间限制为具有最接近目标的速率。
snd_pcm_hw_params_get_buffer_time_max从配置空间中提取最大缓冲时间。
snd_pcm_stream获取PCM句柄的流
snd_pcm_hw_params_set_buffer_time_near限制配置空间以使缓冲时间最接近目标。
snd_pcm_hw_params_set_period_time_near限制配置空间以使周期时间最接近目标。
snd_pcm_hw_params安装从配置空间中选择的一个PCM硬件配置,并调用snd_pcm_prepare。
snd_pcm_nonblock设置非阻塞模式
snd_pcm_hw_params_get_period_size从配置空间中提取周期大小。
snd_pcm_hw_params_get_buffer_size从配置空间中提取周期大小。
snd_pcm_format_physical_width返回存储PCM样本所需的位。

更多函数说明参考:
https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m___h_w___params.html
https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html
在这里插入图片描述

三、编写ALSA应用层程序

这小节介绍简单的ALSA应用程序开发流程,以及给出例子源码。

在编写代码前,可以先使用cat /proc/asound/card0/stream0查看ALSA设备支持的参数:

# cat /proc/asound/card0/stream0 
Rapoo Gaming Headset at usb-10300000.xhci_0-1.1, full speed : USB AudioPlayback:Status: StopInterface 1Altset 1Format: S16_LEChannels: 2Endpoint: 1 OUT (ADAPTIVE)Rates: 48000, 44100Capture:Status: StopInterface 2Altset 1Format: S16_LEChannels: 1Endpoint: 2 IN (ASYNC)Rates: 48000, 44100

Playback:播放设备
Capture:录音设备
Interface:接口序号
Format:格式
Channels:通道数
Rates:支持的采样率

3.1 alsa播放程序开发–alsa-playback.c

开发流程:

  • 1、打开设备:调用 snd_pcm_open,指定类型为SND_PCM_STREAM_PLAYBACK,以及设备名称,打开设备;
  • 2、设置硬件参数
    设置存取方式、格式、通道数、采样率、缓冲时间、周期时间,最后将参数写入设备;
    如果有一些参数不清楚怎么设置,可以使用命令cat /proc/asound/card0/stream0查看支持的参数:
  • 3、播放音频
    每次往alsa驱动写入一个周期大小的字节,不足一周期的要填0;
  • 4、释放资源,关闭设备

下面是一个非常简单的ALSA播放音频的代码,复制后保存为alsa-playback.c,使用命令aarch64-mix210-linux-gcc alsa-playback.c -I /usr/lib/alsa-lib-1.2.10/include/ -L /usr/lib/alsa-lib-1.2.10/lib/ -l asound -lpthread -ldl -lm -o alsa-playback 已编译通过。

48000Hz-16bit-2ch-ChengDu.pcm 文件下载:https://download.csdn.net/download/wkd_007/88421282

// alsa-playback.c
// aarch64-mix210-linux-gcc alsa-playback.c -I /usr/lib/alsa-lib-1.2.10/include/ -L /usr/lib/alsa-lib-1.2.10/lib/ -l asound -lpthread -ldl -lm -o alsa-playback/*
* snd_pcm_hw_params_alloca 申请的内存在函数返回后会自动释放,不需要手动释放。这个函数会在栈上分配一块内存,函数返回后,栈上的内存会自动被回收。
*/
#include <stdio.h>
#include <alsa/asoundlib.h>#define PCM_NAME	"hw:0,0"
#define PLAYBACK_FILE "48000Hz-16bit-2ch-ChengDu.pcm"snd_pcm_hw_params_t *hw_params;
static unsigned int rate = 48000;           /* stream rate */int set_hw_params(snd_pcm_t *handle, int format, int channels, snd_pcm_uframes_t *period_frames)
{int err = -1;// 分配硬件参数空间,调用 alloca 在栈分配内存,函数结束后自动释放,不需要调用 snd_pcm_hw_params_freesnd_pcm_hw_params_alloca(&hw_params);//1、以默认值填充硬件参数if ((err = snd_pcm_hw_params_any(handle, hw_params)) < 0) {return err;}//2、 Restrict a configuration space to contain only real hardware rates.if ((err = snd_pcm_hw_params_set_rate_resample(handle, hw_params, 0)) < 0) {return err;}//3、设置存取方式为交叉存储if ((err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {return err;}//4、设置格式,S16_LE等if ((err = snd_pcm_hw_params_set_format(handle, hw_params, format)) < 0) {return err;}//5、设置通道if ((err = snd_pcm_hw_params_set_channels(handle, hw_params, channels)) < 0) {return err;}//6、大致设置采样率unsigned int rrate;rrate =rate;if ((err = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rrate, NULL)) < 0) 	   {return err;}//7、设置缓冲时间unsigned int buffer_time, period_time;// 先获取缓存时间if((err = snd_pcm_hw_params_get_buffer_time_max(hw_params, &buffer_time, 0))<0){return err;}if (buffer_time > 500000){buffer_time = 500000; // 500ms读取完整个buffer,结合下面代码一个周期就是 buffer_time/4=125ms,每个周期会产生一个中断printf("[%s %d] buffer_time=%d, irq=%d\n",__FILE__,__LINE__,buffer_time, buffer_time/4);}// 设置缓冲时间if ((err = snd_pcm_hw_params_set_buffer_time_near(handle, hw_params, &buffer_time, 0)) < 0) {return err;}// 8、设置周期时间,也就是中断时间period_time = buffer_time / 4;if ((err = snd_pcm_hw_params_set_period_time_near(handle, hw_params, &period_time, 0)) < 0) {return err;}// 9、将参数写入设备if ((err = snd_pcm_hw_params(handle, hw_params)) < 0){return err;}snd_pcm_uframes_t buffer_frames;snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_frames);if(period_frames != NULL) {//获取一个周期有多少帧数据if((err =snd_pcm_hw_params_get_period_size(hw_params, period_frames, 0)) < 0){printf("cannot get period size (%s)\n", snd_strerror(err));return err;}}if(err = (snd_pcm_nonblock(handle, 1) < 0)){return err;}// 10、释放 snd_pcm_hw_params_malloc 分配的内存//snd_pcm_hw_params_free(hw_params);return 0;
}int main()
{int err = -1;snd_pcm_t *playback_handle;snd_pcm_uframes_t period_frames; // 一周期的帧数// 1、打开设备if((err = snd_pcm_open(&playback_handle, PCM_NAME, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {printf("cannot snd_pcm_open (%s)\n",snd_strerror(err));return -1;}// 2、设置硬件参数set_hw_params(playback_handle, SND_PCM_FORMAT_S16_LE, 2, &period_frames);// 3、播放音频// 3.1 打开pcm文件int fd = open(PLAYBACK_FILE,O_RDONLY,0644);if(fd < 0){printf("open %s error!!!\n",PLAYBACK_FILE);return -1;}// 3.2 获取一周期的字节数const int period_bytes = snd_pcm_frames_to_bytes(playback_handle,period_frames);char *playback_buf = malloc(period_bytes);// 3.3 循环播放音频int readframes = 0;while(readframes = read(fd, playback_buf, period_bytes)) {//解决最后一个周期数据问题if(readframes < period_bytes) {memset(playback_buf+readframes, 0, period_bytes-readframes);}//向PCM写入数据,播放err = snd_pcm_writei(playback_handle, playback_buf, period_frames);if(err == -EPIPE) {snd_pcm_prepare(playback_handle);fprintf(stderr, "<<< snd_pcm_writei --> Buffer Underrun >>> \n");err = snd_pcm_writei(playback_handle, playback_buf, period_frames);if(err != period_frames) {printf("write to audio interface failede err:%d (period_frames:%d)\n",err,period_frames);break;}}else if(err != period_frames) {printf("write to audio interface failede err:%d (period_frames:%d)\n",err,period_frames);break;}//printf("process:playback wrote %d frames\n",period_frames);//usleep(100*1000);usleep(130*1000); //测试用,超过 125ms,会报错 Underrun}// 4.释放资源,关闭设备free(playback_buf);close(fd);snd_pcm_close(playback_handle);return 0;
}

3.2 alsa录制音频程序开发–alsa-capture.c

开发流程:

  • 1、打开设备:调用 snd_pcm_open,指定类型为SND_PCM_STREAM_CAPTURE,以及设备名称,打开设备;
  • 2、设置硬件参数
    设置存取方式、格式、通道数、采样率、缓冲时间、周期时间,最后将参数写入设备;
    如果有一些参数不清楚怎么设置,可以使用命令cat /proc/asound/card0/stream0查看支持的参数:
  • 3、读取音频
    每次从alsa驱动读取一个周期大小的字节;
  • 4、释放资源,关闭设备
// alsa-capture.c
// aarch64-mix210-linux-gcc alsa-capture.c -I /usr/lib/alsa-lib-1.2.10/include/ -L /usr/lib/alsa-lib-1.2.10/lib/ -l asound -lpthread -ldl -lm -o alsa-capture/*
* snd_pcm_hw_params_alloca 申请的内存在函数返回后会自动释放,不需要手动释放。这个函数会在栈上分配一块内存,函数返回后,栈上的内存会自动被回收。
*/
#include <stdio.h>
#include <alsa/asoundlib.h>#define PCM_NAME	"hw:0,0"
#define CAPTURE_FILE "alsa-capture.pcm"snd_pcm_hw_params_t *hw_params;
static unsigned int rate = 48000;           /* stream rate */int set_hw_params(snd_pcm_t *handle, int format, int channels, snd_pcm_uframes_t *period_frames)
{int err = -1;// 分配硬件参数空间,调用 alloca 在栈分配内存,函数结束后自动释放,不需要调用 snd_pcm_hw_params_freesnd_pcm_hw_params_alloca(&hw_params);//1、以默认值填充硬件参数if ((err = snd_pcm_hw_params_any(handle, hw_params)) < 0) {return err;}//2、 Restrict a configuration space to contain only real hardware rates.if ((err = snd_pcm_hw_params_set_rate_resample(handle, hw_params, 0)) < 0) {return err;}//3、设置存取方式为交叉存储if ((err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {return err;}//4、设置格式,S16_LE等if ((err = snd_pcm_hw_params_set_format(handle, hw_params, format)) < 0) {return err;}//5、设置通道if ((err = snd_pcm_hw_params_set_channels(handle, hw_params, channels)) < 0) {return err;}//6、大致设置采样率unsigned int rrate;rrate =rate;if ((err = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rrate, NULL)) < 0) 	   {return err;}//7、设置缓冲时间unsigned int buffer_time, period_time;// 先获取缓存时间if((err = snd_pcm_hw_params_get_buffer_time_max(hw_params, &buffer_time, 0))<0){return err;}if (buffer_time > 500000){buffer_time = 500000; // 500ms写完整个buffer,结合下面代码一个周期就是 buffer_time/4=125ms,每个周期会产生一个中断printf("[%s %d] buffer_time=%d, irq=%d\n",__FILE__,__LINE__,buffer_time, buffer_time/4);}// 设置缓冲时间if ((err = snd_pcm_hw_params_set_buffer_time_near(handle, hw_params, &buffer_time, 0)) < 0) {return err;}// 8、设置周期时间,也就是中断时间period_time = buffer_time / 4;if ((err = snd_pcm_hw_params_set_period_time_near(handle, hw_params, &period_time, 0)) < 0) {return err;}// 9、将参数写入设备if ((err = snd_pcm_hw_params(handle, hw_params)) < 0){return err;}snd_pcm_uframes_t buffer_frames;snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_frames);if(period_frames != NULL) {//获取一个周期有多少帧数据if((err =snd_pcm_hw_params_get_period_size(hw_params, period_frames, 0)) < 0){printf("cannot get period size (%s)\n", snd_strerror(err));return err;}}if(err = (snd_pcm_nonblock(handle, 1) < 0)){return err;}// 10、释放 snd_pcm_hw_params_malloc 分配的内存//snd_pcm_hw_params_free(hw_params);return 0;
}int main()
{int err = -1;snd_pcm_t *capture_handle;snd_pcm_uframes_t period_frames; // 一周期的帧数// 1、打开设备if((err = snd_pcm_open(&capture_handle, PCM_NAME, SND_PCM_STREAM_CAPTURE, 0)) < 0) {printf("cannot snd_pcm_open (%s)\n",snd_strerror(err));return -1;}// 2、设置硬件参数set_hw_params(capture_handle, SND_PCM_FORMAT_S16_LE, 1, &period_frames);// 3、获取音频// 3.1 打开录制文件int fd = open(CAPTURE_FILE,O_RDWR | O_TRUNC | O_CREAT,0644);if(fd < 0){printf("open %s error!!!\n",CAPTURE_FILE);return -1;}// 3.2 获取一周期的字节数const int period_bytes = snd_pcm_frames_to_bytes(capture_handle,period_frames);char *capture_buf = malloc(period_bytes);int count = 100; // 捕获100个周期int readframes = 0;while(count--) {//向PCM读一周期数据memset(capture_buf,0,period_bytes);if((readframes = snd_pcm_readi(capture_handle, capture_buf, period_frames)) < 0) {if(readframes == -EPIPE)printf("read from audio interface failed (%d), overrun, Need to read faster\n",readframes);elseprintf("read from audio interface failed (%d)\n",readframes);break;}printf("--process:capture read %d frames\n",readframes);write(fd,capture_buf,snd_pcm_frames_to_bytes(capture_handle,readframes));usleep(100*1000); //usleep(130*1000); //测试用,超过 125ms,会报错 overrun}// 4、释放资源,关闭设备free(capture_buf);close(fd);snd_pcm_close(capture_handle);return 0;
}

在这里插入图片描述

四、XRUN( underrun和overrun)

在 ALSA 数据传输中,最容易出现的错误是 underrun 和 overrun。

  • underrun:pcm 播放的时候,接口 snd_pcm_writei 返回 -EPIPE,为 underrun(不足)
    出现这问题原因是应用准备的音频数据不够,比如,驱动需要播放需要 1026 帧数据,但应用只准备好了 1024 帧。可以根据采样率和buffer sizeperiod size去调整;
  • overrun:录制音频的时候, 接口 snd_pcm_readi 返回 -EPIPE, 为 overrun(超载)
    alsa驱动一直往buffer里面写,但应用程序却读取的很慢,例如:驱动写了1026帧,而应用层只读取了1024帧。需要加快读取速度。或者调整buffer sizeperiod size

在这里插入图片描述

五、总结

文章介绍了alsa的基础知识,以及基于alsa-lib开发ALSA应用层程序的开发流程和alsa开发过程钟常见的报错,提供了简单的alsa应用层代码。


参考资料:
ALSA官网资料——FramesPeriods:https://alsa-project.org/main/index.php/FramesPeriods
【Linux&音频】Alsa音频编程【精华】:https://blog.csdn.net/u012183924/article/details/53407668
ALSA 音频数据传输 underrun 和 overrun:https://blog.csdn.net/qq_38350702/article/details/111995039
Linux应用开发【第八章】ALSA应用开发:https://blog.csdn.net/thisway_diy/article/details/121809633

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

相关文章:

【音视频|ALSA】基于alsa-lib开发ALSA应用层程序--附带源码

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…...

嵌入式养成计划-43----QT QMainWindow中常用类的使用--ui界面文件--资源文件的添加--信号与槽

一百零九、QMainWindow中常用类的使用 109.1 菜单栏 QMenuBar 菜单栏 QMenuBar 最多只能有一个 109.2 工具栏 QToolBar 工具栏 QToolBar 可以有多个 109.3 状态栏QStatusBar 状态栏 QStatusBar 最多只能有一个 109.4 浮动窗口QDockWidget 浮动窗口 可以有多个 109.5 代…...

【Yarn】清除Yarn的缓存,更新Yarn本身、更新项目的依赖项

要清除Yarn的缓存&#xff0c;可以运行以下命令&#xff1a; yarn cache clean这将清除Yarn的缓存目录。 要更新Yarn本身&#xff0c;可以运行以下命令&#xff1a; yarn self-update这将下载并安装最新版本的Yarn。 如果要更新项目的依赖项&#xff0c;可以运行以下命令&a…...

点云从入门到精通技术详解100篇-雨雾环境下多传感器融合SLAM方法(续)

目录 4 基于球面投影的激光视觉融合里程计 4.1 引言 4.2 视觉惯性里程计 4.2.1特征点提取与匹配...

解决GET请求入参@NotNull验证不生效问题

一、问题 get请求NotNull验证不生效 二、解决方案 两个步骤&#xff1a; 在该方法的controller类上加Validated&#xff1b;在参数面前加NotNull&#xff1b; 三、其他注解 //被注释的元素必须为null Null //被注释的元素不能为null NotNull //被注释的元素必须为true Ass…...

《golang设计模式》第三部分·行为型模式-01-责任链模式(Chain of Responsibility)

文章目录 1 概念1.1 角色1.2 类图 2. 代码示例2.1 设计2.2 代码2.3 类图 1 概念 责任链&#xff08;Chain of Responsibility&#xff09;是指将客户端请求处理的不同职责对象组成请求处理链。 客户端只需要将请求交付到该链上&#xff0c;而不需要关心链上含有哪些对象。请求…...

环境变量【使用命令行参数引出环境变量】

前提&#xff1a;命令行参数 大家在写C/C程序的时候肯定见过下面这种情况&#xff1a; main函数里面携带的参数&#xff0c;平常写代码过程中很少用到这两个参数&#xff0c;接下来我们就研究一下 我们也不知道 指针数组argv里面到底保存的是什么&#xff0c;也不知道这个a…...

【Java 进阶篇】JavaScript BOM History 详解

当用户浏览网页时&#xff0c;可以使用JavaScript的BOM (Browser Object Model)中的History对象来访问浏览器的历史记录。这个对象允许您在不更改页面的情况下导航到不同的历史记录项&#xff0c;或者查看有关用户访问过的页面的信息。 在本篇博客中&#xff0c;我们将围绕Jav…...

【计算机网络】https协议

文章目录 1 :peach:基本概念:peach:1.1 :apple:什么是HTTPS&#xff1f;:apple:1.2 :apple:什么是加密&#xff1f;:apple:1.3 :apple:常见的加密方式:apple:1.3.1 :lemon:对称加密:lemon:1.3.2 :lemon:⾮对称加密:lemon: 1.4 :lemon:数据指纹:lemon: 2 :peach:HTTPS的⼯作过程…...

React之受控组件和非受控组件以及高阶组件

一、受控组件 受控组件&#xff0c;简单来讲&#xff0c;就是受我们控制的组件&#xff0c;组件的状态全程响应外部数据 举个简单的例子&#xff1a; class TestComponent extends React.Component {constructor (props) {super(props);this.state { username: lindaidai }…...

中国移动集采120万部,助推国产5G赶超iPhone15

近期媒体纷纷传出消息指中国移动将大规模集采&#xff0c;预计将采购国产5G手机120万台&#xff0c;加上另外两家运营商的集采数量&#xff0c;估计集采数量可能达到300万部&#xff0c;如此将有助于它在国内高端手机市场赶超苹果。 国产5G手机在8月底突然上市&#xff0c;获益…...

华为云HECS服务器下docker可视化(portainer)

一、docker安装 华为云HECS安装docker-CSDN博客 二、portainer安装 portainer地址&#xff1a;Portainer: Docker and Kubernetes Management Platform 当前portainer分CE&#xff08;开源版&#xff09; 和 BE&#xff08;商业版&#xff09;&#xff0c;用CE即可 1 创建…...

postman发送soap报文示例

一、soap简介 soap是一种基于XML的协议 二、postman发送soap请求 1、发送post请求&#xff0c;url&#xff1a;​​​ https://www.dataaccess.com/webservicesserver/NumberConversion.wso 2、headers设置&#xff0c;添加Content-Type&#xff0c;值为text/xml 添加SOAP…...

力扣-python-两数之和

题解&#xff1a; class Solution(object):def twoSum(self, nums, target):# 遍历列表for i in range(len(nums)):# 计算需要找到的下一个目标数字res target-nums[i]# 遍历剩下的元素&#xff0c;查找是否存在该数字if res in nums[i1:]:# 若存在&#xff0c;返回答案。这里…...

算水质TDS加温度补偿

先上图&#xff0c;就图里这款水质检测&#xff0c;用树莓派3/4的话&#xff0c;要配个温度检测作为温度校正&#xff0c;以及一个adc 元器件。我选ds18b20和ads1115。 再把模拟数据计算过程放一下&#xff1a; 温度检测元器件在农历钟那里提过&#xff0c;就是同款。此处先测个…...

wps/word 如何让表格的标题和表格名称文本(表1-1 xxx)跨页显示(已解决)

第一步&#xff1a; 打开wps 创建一个跨页的表格表格&#xff0c;如下图 第二步 大家都知道 表格标题跨页 就是1&#xff09;在菜单表格工具 点击重复标题 或者 2&#xff09;表格属性--》行--》在各页顶端以标题行形式出现&#xff0c;详细如下图。 1&#xff09; 第一…...

攻防世界web篇-PHP2

直接点击进入到http网页中&#xff0c;会得到这样一个界面 这里&#xff0c;我最开始使用了burp什么包也没有抓到&#xff0c;然后接着又用nikto进行探测&#xff0c;得到的只有两个目录&#xff0c;当时两个目录打开后&#xff0c;一个是fond界面&#xff0c;一个是这个网页的…...

Kotlin中的步长

步长是 Kotlin 中用于迭代区间或集合时控制迭代步进的概念。在 Kotlin 中&#xff0c;我们可以使用 step 关键字来指定迭代时的步长。 在 Kotlin 中&#xff0c;有多种方式可以定义一个区间&#xff08;Range&#xff09;。我们将通过以下示例代码来展示不同类型的区间以及如何…...

3. 无重复字符的最长子串

给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc"&#xff0c;所以其长度为 3。示例 2: 输入: s "bbbbb" 输出: 1 解释: 因为无…...

通过SPI传输BMI160数据到nrf528xx

目录 主控和外设之间的联系关键示例可能的bug 主控和外设之间的联系 在完成代码之前&#xff0c;我们手里会有两份代码&#xff0c;一份是nrf528xx的SDK&#xff0c;一份是BMI160传感器的SDK&#xff0c;怎么利用SDK完成我们的需求呢&#xff1f;首先我们要搞明白&#xff0c;…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper&#xff08;简称 DM&#xff09;是 Linux 内核中的一套通用块设备映射框架&#xff0c;为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程&#xff0c;并配以详细的…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

Vue ③-生命周期 || 脚手架

生命周期 思考&#xff1a;什么时候可以发送初始化渲染请求&#xff1f;&#xff08;越早越好&#xff09; 什么时候可以开始操作dom&#xff1f;&#xff08;至少dom得渲染出来&#xff09; Vue生命周期&#xff1a; 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理

在城市的某个角落&#xff0c;一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延&#xff0c;滚滚浓烟弥漫开来&#xff0c;周围群众的生命财产安全受到严重威胁。就在这千钧一发之际&#xff0c;消防救援队伍迅速行动&#xff0c;而豪越科技消防一体化安全管控平台构建的消防“…...

针对药品仓库的效期管理问题,如何利用WMS系统“破局”

案例&#xff1a; 某医药分销企业&#xff0c;主要经营各类药品的批发与零售。由于药品的特殊性&#xff0c;效期管理至关重要&#xff0c;但该企业一直面临效期问题的困扰。在未使用WMS系统之前&#xff0c;其药品入库、存储、出库等环节的效期管理主要依赖人工记录与检查。库…...