【音视频|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 size
、buffer time
、period size
、period 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 size
、period size
去调整;overrun
:录制音频的时候, 接口 snd_pcm_readi 返回 -EPIPE, 为 overrun(超载)
alsa驱动一直往buffer里面写,但应用程序却读取的很慢,例如:驱动写了1026帧,而应用层只读取了1024帧。需要加快读取速度。或者调整buffer size
、period 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
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁
相关文章:
![](https://img-blog.csdnimg.cn/b9a9a3c469ff43c8a799e60c2e9c532b.gif#pic_center)
【音视频|ALSA】基于alsa-lib开发ALSA应用层程序--附带源码
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…...
![](https://img-blog.csdnimg.cn/024c21a8374947a48b5767116775a999.png)
嵌入式养成计划-43----QT QMainWindow中常用类的使用--ui界面文件--资源文件的添加--信号与槽
一百零九、QMainWindow中常用类的使用 109.1 菜单栏 QMenuBar 菜单栏 QMenuBar 最多只能有一个 109.2 工具栏 QToolBar 工具栏 QToolBar 可以有多个 109.3 状态栏QStatusBar 状态栏 QStatusBar 最多只能有一个 109.4 浮动窗口QDockWidget 浮动窗口 可以有多个 109.5 代…...
![](https://www.ngui.cc/images/no-images.jpg)
【Yarn】清除Yarn的缓存,更新Yarn本身、更新项目的依赖项
要清除Yarn的缓存,可以运行以下命令: yarn cache clean这将清除Yarn的缓存目录。 要更新Yarn本身,可以运行以下命令: yarn self-update这将下载并安装最新版本的Yarn。 如果要更新项目的依赖项,可以运行以下命令&a…...
![](https://www.ngui.cc/images/no-images.jpg)
点云从入门到精通技术详解100篇-雨雾环境下多传感器融合SLAM方法(续)
目录 4 基于球面投影的激光视觉融合里程计 4.1 引言 4.2 视觉惯性里程计 4.2.1特征点提取与匹配...
![](https://www.ngui.cc/images/no-images.jpg)
解决GET请求入参@NotNull验证不生效问题
一、问题 get请求NotNull验证不生效 二、解决方案 两个步骤: 在该方法的controller类上加Validated;在参数面前加NotNull; 三、其他注解 //被注释的元素必须为null Null //被注释的元素不能为null NotNull //被注释的元素必须为true Ass…...
![](https://img-blog.csdnimg.cn/4a3d2dc909d846f3ade748eb38789629.png#pic_center)
《golang设计模式》第三部分·行为型模式-01-责任链模式(Chain of Responsibility)
文章目录 1 概念1.1 角色1.2 类图 2. 代码示例2.1 设计2.2 代码2.3 类图 1 概念 责任链(Chain of Responsibility)是指将客户端请求处理的不同职责对象组成请求处理链。 客户端只需要将请求交付到该链上,而不需要关心链上含有哪些对象。请求…...
![](https://img-blog.csdnimg.cn/9c004d29752c4ed3aa03117fda615a61.png)
环境变量【使用命令行参数引出环境变量】
前提:命令行参数 大家在写C/C程序的时候肯定见过下面这种情况: main函数里面携带的参数,平常写代码过程中很少用到这两个参数,接下来我们就研究一下 我们也不知道 指针数组argv里面到底保存的是什么,也不知道这个a…...
![](https://img-blog.csdnimg.cn/ee6246a97e76456ea2a96231b3fde401.png)
【Java 进阶篇】JavaScript BOM History 详解
当用户浏览网页时,可以使用JavaScript的BOM (Browser Object Model)中的History对象来访问浏览器的历史记录。这个对象允许您在不更改页面的情况下导航到不同的历史记录项,或者查看有关用户访问过的页面的信息。 在本篇博客中,我们将围绕Jav…...
![](https://img-blog.csdnimg.cn/e8d88ea3d6ae4ea8af86359785258466.png)
【计算机网络】https协议
文章目录 1 :peach:基本概念:peach:1.1 :apple:什么是HTTPS?:apple:1.2 :apple:什么是加密?:apple:1.3 :apple:常见的加密方式:apple:1.3.1 :lemon:对称加密:lemon:1.3.2 :lemon:⾮对称加密:lemon: 1.4 :lemon:数据指纹:lemon: 2 :peach:HTTPS的⼯作过程…...
![](https://img-blog.csdnimg.cn/9fe035533f174b828ded7fb672e45dfe.png)
React之受控组件和非受控组件以及高阶组件
一、受控组件 受控组件,简单来讲,就是受我们控制的组件,组件的状态全程响应外部数据 举个简单的例子: class TestComponent extends React.Component {constructor (props) {super(props);this.state { username: lindaidai }…...
![](https://img-blog.csdnimg.cn/img_convert/6f9cee7e33cc1064306fe6a0994a7a9e.jpeg)
中国移动集采120万部,助推国产5G赶超iPhone15
近期媒体纷纷传出消息指中国移动将大规模集采,预计将采购国产5G手机120万台,加上另外两家运营商的集采数量,估计集采数量可能达到300万部,如此将有助于它在国内高端手机市场赶超苹果。 国产5G手机在8月底突然上市,获益…...
![](https://img-blog.csdnimg.cn/e1ab2811ca2d45a79a5f71674cde12ff.png)
华为云HECS服务器下docker可视化(portainer)
一、docker安装 华为云HECS安装docker-CSDN博客 二、portainer安装 portainer地址:Portainer: Docker and Kubernetes Management Platform 当前portainer分CE(开源版) 和 BE(商业版),用CE即可 1 创建…...
![](https://img-blog.csdnimg.cn/e5ade96bd11149ed8c8fe2b90bbd4faa.png)
postman发送soap报文示例
一、soap简介 soap是一种基于XML的协议 二、postman发送soap请求 1、发送post请求,url: https://www.dataaccess.com/webservicesserver/NumberConversion.wso 2、headers设置,添加Content-Type,值为text/xml 添加SOAP…...
![](https://img-blog.csdnimg.cn/6832125cb64b446baeab040939f0ae62.png)
力扣-python-两数之和
题解: class Solution(object):def twoSum(self, nums, target):# 遍历列表for i in range(len(nums)):# 计算需要找到的下一个目标数字res target-nums[i]# 遍历剩下的元素,查找是否存在该数字if res in nums[i1:]:# 若存在,返回答案。这里…...
![](https://img-blog.csdnimg.cn/18b6f18730bf4f5dbf764bc405a1aea6.jpeg)
算水质TDS加温度补偿
先上图,就图里这款水质检测,用树莓派3/4的话,要配个温度检测作为温度校正,以及一个adc 元器件。我选ds18b20和ads1115。 再把模拟数据计算过程放一下: 温度检测元器件在农历钟那里提过,就是同款。此处先测个…...
![](https://img-blog.csdnimg.cn/f403fd9986e2451593e1149d640d1252.png)
wps/word 如何让表格的标题和表格名称文本(表1-1 xxx)跨页显示(已解决)
第一步: 打开wps 创建一个跨页的表格表格,如下图 第二步 大家都知道 表格标题跨页 就是1)在菜单表格工具 点击重复标题 或者 2)表格属性--》行--》在各页顶端以标题行形式出现,详细如下图。 1) 第一…...
![](https://img-blog.csdnimg.cn/a24e92fcc20647688d7799a8a6c8fb0a.png)
攻防世界web篇-PHP2
直接点击进入到http网页中,会得到这样一个界面 这里,我最开始使用了burp什么包也没有抓到,然后接着又用nikto进行探测,得到的只有两个目录,当时两个目录打开后,一个是fond界面,一个是这个网页的…...
![](https://www.ngui.cc/images/no-images.jpg)
Kotlin中的步长
步长是 Kotlin 中用于迭代区间或集合时控制迭代步进的概念。在 Kotlin 中,我们可以使用 step 关键字来指定迭代时的步长。 在 Kotlin 中,有多种方式可以定义一个区间(Range)。我们将通过以下示例代码来展示不同类型的区间以及如何…...
![](https://www.ngui.cc/images/no-images.jpg)
3. 无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。示例 2: 输入: s "bbbbb" 输出: 1 解释: 因为无…...
![](https://img-blog.csdnimg.cn/9343cdd5e65840d8b5eab73380cc8c56.png#pic_center)
通过SPI传输BMI160数据到nrf528xx
目录 主控和外设之间的联系关键示例可能的bug 主控和外设之间的联系 在完成代码之前,我们手里会有两份代码,一份是nrf528xx的SDK,一份是BMI160传感器的SDK,怎么利用SDK完成我们的需求呢?首先我们要搞明白,…...
![](https://img-blog.csdnimg.cn/bb00b8ed20ef41a49c701e88b990d84c.png)
MAYA教程之建模基础命令介绍
基础命令 视图相关操作 旋转视图 : ALT 鼠标左键平移视图 : ALT 鼠标中键缩放视图 : 滚动鼠标滚轮 或者 ALT 鼠标右键切换视图 : 空格键回到模型 : F 视图状态 选择状态 : Q移动状态 : W旋转状态 : E缩放状态 : R 视图显示 正常显示 : 1正常圆滑同时显示 : 2圆滑显示 …...
![](https://img-blog.csdnimg.cn/cfa9123d8e29495ab2f92c6b08261989.png)
文档外发控制与安全:实现高效协作与数据安全的关键
随着企业数据量的不断增加,文档外发成为了一个不可避免的需求。然而,很多企业在文档外发过程中存在着很多问题,如数据泄露、信息误用等。因此,如何保证文档外发的安全性和高效性成为了企业亟待解决的问题。飞驰云联Ftrans的文件收…...
![](https://img-blog.csdnimg.cn/f46209fae92848fda741ad495470d74f.jpeg)
在线课堂知识系统源码系统+前端+后端完整搭建教程
大家好啊,今天罗峰来给大家分享一款在线课堂知识系统源码系统。这款系统的功能十分强大。可以使用手机随时随地地学习,有专业的导师答疑解惑。支持视频,音频,图文章节。以下是部分核心代码图: 系统特色功能一览&#x…...
![](https://img-blog.csdnimg.cn/2793eecd970d4cd09afd08c9339fda11.png)
CSS之布局系列--顶部导航栏二级菜单居中展示
原文网址:CSS之布局系列--顶部导航栏二级菜单居中展示_IT利刃出鞘的博客-CSDN博客 简介 本文介绍CSS将顶部导航栏居中展示并支持二级菜单下拉展示的方法。 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-…...
![](https://img-blog.csdnimg.cn/img_convert/978d924261cdcbed308c50d09470e418.png)
算法通关村第九关黄金挑战——透彻理解二叉树中序遍历的应用
大家好,我是怒码少年小码。 上一篇讲了二分查找,今天我们看看它的难度扩展。 有序数组转为二叉搜索树 LeetCode 108:给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。 高…...
![](https://img-blog.csdnimg.cn/6e0a4ed04bb14e4f9da3abda0202f155.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Ie05ZG95bCP5a2m5pyf,size_12,color_FFFFFF,t_70,g_se,x_16)
【算法设计与分析zxd】第7章 贪心法
贪心算法的设计技术 • 每一步的判断都是一个当前最优的抉择,这个抉择计算设计的好坏,决定了算法的成败。 • 多步判断过程,最终的判断序列对应于问题的最优解 • 适用于 能够 由 局部最优达到全局最优的优化问题 【比如 求最短哈密顿回路的…...
![](https://img-blog.csdnimg.cn/eea2ff8e240e40ab8cbda62ac7583248.jpeg)
CCF CSP认证 历年题目自练Day35
题目一 试题编号: 202305-1 试题名称: 重复局面 时间限制: 1.0s 内存限制: 512.0MB 问题描述: 题目背景 国际象棋在对局时,同一局面连续或间断出现3次或3次以上,可由任意一方提出和棋。 问题…...
![](https://www.ngui.cc/images/no-images.jpg)
应用crash时发送广播及信息
一、环境 高通865 Android 10 二、情景 应用崩溃时,将奔溃信息以广播的形式发送 二、代码位置 frameworks/base/core/java/com/android/internal/os/RuntimeInit.java private static class KillApplicationHandler implements Thread.UncaughtExceptionHandle…...
![](https://www.ngui.cc/images/no-images.jpg)
【亲测可用】图像目标识别入门-利用笔记本电脑摄像头识别人脸标记出来采用深度学习模型实现
更高的精度和准确性,可以考虑使用基于深度学习的人脸检测和识别方法,例如基于人脸特征的人脸检测器和具有高识别率的人脸识别模型。下面是使用基于深度学习的人脸检测和识别方法的代码示例: 首先,安装必要的库和模型:…...
![](https://img-blog.csdnimg.cn/569d0840799c48078a75cfad35f72313.png)
数字孪生技术:煤矿运输的未来革命
煤矿是我国能源工业的重要支柱,然而,煤矿运输过程中一直存在着诸多问题,如安全隐患、能源浪费、效率低下等,这不仅对煤矿行业的可持续发展构成威胁,也对环境造成负面影响。因此,数字孪生技术应运而生&#…...
![](/images/no-images.jpg)
wordpress显示代码框/seo推广主要做什么的
这篇文章主要为大家详细介绍了SQL Server 使用命令调用SSIS包的简单示例,具有一定的参考价值,可以用来参考一下。感兴趣的小伙伴,下面一起跟随512笔记的小编两巴掌来看看吧!具体操作步骤如下:1.首先,当然是…...
![](https://static.oschina.net/uploads/img/201712/06113603_MycX.png)
浦东建设交通委网站/企业营销型网站建设
为什么80%的码农都做不了架构师?>>> Oracle数据库查询高效分页 由于网页渲染速度的影响,在C/S程序中那种一个Grid包含几千、上万行的数据基本上在网页是无法展现的,因此一般采用分页的形式显示(也可能采用Visual Srol…...
![](/images/no-images.jpg)
连云港网站制作公司哪家好/网络推广的细节
《嵌入式系统原理及接口技术》复习题及答案自己整理的,保证质量。一、单项选择题1、 下面关于哈佛结构描述正确的是( A )。A、程序存储空间与数据存储空间分离C、程序存储空间与数据存储空间合并 B、存储空间与IO空间分离 D、存储空间与IO空间合并2、 下面哪一种工作模式不属于…...
![](/images/no-images.jpg)
泰州网站建设方案推广/电商网站订烟
质数又称素数。指在一个大于1的自然数中,除了1和此整数自身外,没法被其他自然数整除的数。或在所有比1大的整数中,除了1和它本身以外,不再有别的因数,这种整数叫做质数或素数。 换句话说,只有两个正因数(1和自己)的自然…...
![](https://img-blog.csdnimg.cn/20200208113704315.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxOTg1Mjkz,size_16,color_FFFFFF,t_70)
公司做了网站怎么做推广/查权重工具
selenium安装 winR,输入cmd,进入命令行,然后输入 pip install seleniumwebdriver的配置 这里我们安装chrome的webdriver使用 首先查看你的谷歌浏览器的版本chrome://version/ 例如: 然后参照版本,我们下载对应的谷…...
![](https://img2018.cnblogs.com/blog/354272/201812/354272-20181212183310153-1406276603.jpg)
泰州整站优化/今日热榜
引言 Bleve是Golang实现的一个全文检索库,类似Lucene之于Java。在这里通过阅读其代码,来学习如何使用及定制检索功能。也是为了通过阅读代码,学习在具体环境下Golang的一些使用方式。代码的路径在github上https://github.com/blevesearch/ble…...