調(diào)研l(wèi)inux庫(kù)alsa

一.聲音參數(shù)基本概念:

聲音是連續(xù)模擬量,計(jì)算機(jī)將它離散化之后用數(shù)字表示,就有了以下幾個(gè)名詞術(shù)語(yǔ)。

樣本長(zhǎng)度(sample)樣本是記錄音頻數(shù)據(jù)最基本的單位,計(jì)算機(jī)對(duì)每個(gè)通道采樣量化時(shí)數(shù)字比特位數(shù),常見的有8位和16位。

通道數(shù)(channel)該參數(shù)為1表示單聲道,2則是立體聲。

(frame)幀記錄了一個(gè)聲音單元,其長(zhǎng)度為樣本長(zhǎng)度與通道數(shù)的乘積,一段音頻數(shù)據(jù)就是由苦干幀組成的。

采樣率(rate)每秒鐘采樣次數(shù),該次數(shù)是針對(duì)幀而言,常用的采樣率如8KHz的人聲,44.1KHz的mp3音樂, 96Khz的藍(lán)光音頻。

周期(period)音頻設(shè)備一次處理所需要的楨數(shù),對(duì)于音頻設(shè)備的數(shù)據(jù)訪問以及音頻數(shù)據(jù)的存儲(chǔ),都是以此為單位。

交錯(cuò)模式(interleaved)是一種音頻數(shù)據(jù)的記錄方式

在交錯(cuò)模式下,數(shù)據(jù)以連續(xù)楨的形式存放,即首先記錄完楨1的左聲道樣本和右聲道樣本(假設(shè)為立體聲格式),再開始楨2的記錄。

而在非交錯(cuò)模式下,首先記錄的是一個(gè)周期內(nèi)所有楨的左聲道樣本,再記錄右聲道樣本,數(shù)據(jù)是以連續(xù)通道的方式存儲(chǔ)。

不過多數(shù)情況下,我們只需要使用交錯(cuò)模式就可以了。

period(周期):硬件中中斷間的間隔時(shí)間。它表示輸入延時(shí)。

比特率(Bits

Per Second):比特率表示每秒的比特?cái)?shù),比特率=采樣率×通道數(shù)×樣本長(zhǎng)度

二.ALSA介紹

1.ALSA簡(jiǎn)介

ALSA表示高級(jí)Linux聲音體系結(jié)構(gòu)(Advanced Linux Sound Architecture)。ALSA是一個(gè)完全開放源代碼的音頻驅(qū)動(dòng)程序集,除了像OSS那樣提供了一組內(nèi)核驅(qū)動(dòng)程序模塊之外,ALSA還專門為簡(jiǎn)化應(yīng)用程序的編寫提供了相應(yīng)的函數(shù)庫(kù),與OSS提供的基于ioctl的原始編程接口相比,ALSA函數(shù)庫(kù)使用起來(lái)要更加方便一些。利用該函數(shù)庫(kù),開發(fā)人員可以方便快捷的開發(fā)出自己的應(yīng)用程序,細(xì)節(jié)則留給函數(shù)庫(kù)內(nèi)部處理。當(dāng)然ALSA也提供了類似于OSS的系統(tǒng)接口,不過ALSA的開發(fā)者建議應(yīng)用程序開發(fā)者使用音頻函數(shù)庫(kù)而不是驅(qū)動(dòng)程序的API。

2.ALSA版本支持

Linux內(nèi)核2.5在開發(fā)過程中,ALSA被合并到了官方的源碼樹中。在發(fā)布內(nèi)核2.6后,ALSA已經(jīng)內(nèi)建在穩(wěn)定的內(nèi)核版本中并將廣泛地使用。在內(nèi)核設(shè)備驅(qū)動(dòng)層,ALSA提供了alsa-driver,同時(shí)在應(yīng)用層,ALSA為我們提供了alsa-lib,應(yīng)用程序只要調(diào)用alsa-lib提供的API,即可以完成對(duì)底層音頻硬件的控制。

3.ALSA基礎(chǔ)

ALSA由許多聲卡的聲卡驅(qū)動(dòng)程序組成,同時(shí)它也提供一個(gè)稱為libasound的API庫(kù)。應(yīng)用程序開發(fā)者應(yīng)該使用libasound而不是內(nèi)核中的ALSA接口。因?yàn)閘ibasound提供最高級(jí)并且編程方便的編程接口。并且提供一個(gè)設(shè)備邏輯命名功能,這樣開發(fā)者甚至不需要知道類似設(shè)備文件這樣的低層接口。

用戶空間的alsa-lib對(duì)應(yīng)用程序提供統(tǒng)一的API接口,這樣可以隱藏了驅(qū)動(dòng)層的實(shí)現(xiàn)細(xì)節(jié),簡(jiǎn)化了應(yīng)用程序的實(shí)現(xiàn)難度。內(nèi)核空間中,alsa-soc其實(shí)是對(duì)alsa-driver的進(jìn)一步封裝,他針對(duì)嵌入式設(shè)備提供了一些列增強(qiáng)的功能。

4.ALSA體系結(jié)構(gòu):

ALSA API可以分解成以下幾個(gè)主要的接口:

1控制接口:提供管理聲卡注冊(cè)和請(qǐng)求可用設(shè)備的通用功能

2 PCM接口:管理數(shù)字音頻回放(playback)和錄音(capture)的接口。它是開發(fā)數(shù)字音頻程序最常用到的接口。

3 Raw MIDI接口:支持MIDI(Musical Instrument Digital Interface),標(biāo)準(zhǔn)的電子樂器。這些API提供對(duì)聲卡上MIDI總線的訪問。這個(gè)原始接口基于MIDI事件工作,由程序員負(fù)責(zé)管理協(xié)議以及時(shí)間處理。

4定時(shí)器(Timer)接口:為同步音頻事件提供對(duì)聲卡上時(shí)間處理硬件的訪問。

5時(shí)序器(Sequencer)接口

6混音器(Mixer)接口設(shè)備命名API庫(kù)使用邏輯設(shè)備名而不是設(shè)備文件。

5.偽代碼

一個(gè)典型的聲音程序使用PCM的程序通常類似下面的偽代碼:

1.打開回放或錄音接口

2.設(shè)置硬件參數(shù)(訪問模式,數(shù)據(jù)格式,信道數(shù),采樣率,等等)

2.while有數(shù)據(jù)要被處理:讀PCM數(shù)據(jù)(錄音)或?qū)慞CM數(shù)據(jù)(回放)

3.關(guān)閉接口

三.ALSA編譯安裝

1.ALSA相關(guān)庫(kù)下載

官方主頁(yè)http://www.alsa-project.org/

主要跟編程相關(guān)是

·alsa-lib. ALSA應(yīng)用庫(kù)(最常用)

·ftp://ftp.alsa-project.org/pub/lib/alsa-lib-1.0.22.tar.bz2

·alsa-driver一些常見芯片的ALSA驅(qū)動(dòng)代碼,一般內(nèi)核會(huì)集成.

·ftp://ftp.alsa-project.org/pub/driver/alsa-driver-1.0.22.1.tar.bz2

·alsa-firmware一些DSP或ASIC的專用的微碼(運(yùn)在芯片之上,啟動(dòng)時(shí)由LINUX裝入到硬件中).

·ftp://ftp.alsa-project.org/pub/firmware/alsa-firmware-1.0.20.tar.bz2

·alsa-utils一般ALSA小的測(cè)試工具.如aplay/arecord播放和錄音小程序.

·ftp://ftp.alsa-project.org/pub/utils/alsa-utils-1.0.22.tar.bz2

·alsa-oss用alsa接口模擬舊的oss接口.

·ftp://ftp.alsa-project.org/pub/oss-lib/alsa-oss-1.0.17.tar.bz2

其中alsa-driver,alsa-firwware是內(nèi)核開發(fā)者所接觸的東西,對(duì)于已經(jīng)正常運(yùn)行硬件,通常意味著這一部分已經(jīng)整合到內(nèi)核當(dāng)中,無(wú)需修改.

而alsa-utils主要是測(cè)試一些小工具.

因此對(duì)于一個(gè)應(yīng)用程序開發(fā)者,或者嵌入式應(yīng)用開發(fā)者,接觸到主要是alsa-lib編譯出來(lái)的庫(kù)libasound.

2.ALSA驅(qū)動(dòng)測(cè)試

cat

/proc/asound/devices驅(qū)動(dòng)測(cè)試

ls -l/dev/snd設(shè)備測(cè)試

aplay –h工具alsa-utils測(cè)試

3.嵌入式linuxALSA移植

·ALSA driver移植

·ALSA lib移植.

解壓tar xvjf alsa-lib-1.0.22.tar.bz2

cd alsa-lib-1.0.22

生成Makefile

./configure --host=arm-linux? --prefix=$PWD/../../output/arm-linux --enable-static --enable-shared?? --disable-python? --with-configdir=/usr/local/share? --with-plugindir=/usr/local/lib/alsa_lib

在這里要注意--with--configdir的選項(xiàng).它將影響include/config.h中的ALSA_CONFIG_DIR目錄.

它默認(rèn)是你的--prefix目錄.這樣在嵌入式交叉編譯將是一個(gè)桌面機(jī)的路徑,在libasoud.so運(yùn)行.會(huì)提示,如果出來(lái)這個(gè)提示,一般都是ALSA_CONFIG_DIR路徑錯(cuò)誤造成的.

ALSA? lib pcm.c:2145:(snd_pcm_open_noupdate) Unknown PCM default

aplay:? main:546:?audio open error: No such file or directory

--with-plugindir也是同樣道理了.它是設(shè)為ALSA_PLUGIN_DIR宏.

編譯make

安裝make install

開發(fā)板發(fā)布注意:

在開發(fā)板上發(fā)布alsa庫(kù).除了libasound.so庫(kù)以外,必須還要把a(bǔ)lsa.conf發(fā)布到板上--with-configdir所指向目錄下的alsa目錄,否則還是會(huì)報(bào)"audio open error: No such file ordirectory".

這個(gè)文件可以在make install后在你安裝目錄下的share找到alsa目錄,把這個(gè)目錄整個(gè)拷貝到開發(fā)板即可.

·ALSA utils移植

解壓:tar xvjf alsa-utils-1.0.22.tar.bz2

cdalsa-utils-1.0.22

生成Makefile

./configure --host=arm-linux? --prefix=$PWD/../../output/arm-linux --enable-static? --enable-shared??? --with-configdir=/usr/local/share? --with-libiconv-prefix=$PWD/../../output/arm-linux? CFLAGS="-I$PWD/../../output/arm-linux/include"? LDFLAGS="-L$PWD/../../output/arm-linux/lib -lasound -liconv"?? --disable-alsamixer --disable-xmlto

注意這里L(fēng)DFLAGS是必須,否則會(huì)找不到libasound.另外alsamixer是一個(gè)ncurses程序,基本上在嵌入式終端上很難移植.所以這里取消掉.--disable-xmlto也是因?yàn)檎也坏綆?kù).

編譯make

安裝make install

四.ALSA錄音demo

#include

#include

#include

main (int argc, char *argv[])

{

int i;

int err;

short buf[128];

snd_pcm_t *capture_handle; // PCM設(shè)備句柄

snd_pcm_hw_params_t *hw_params;//硬件信息和PCM流配置

//1.打開PCM,最后一個(gè)參數(shù)0為標(biāo)準(zhǔn)配置

if ((err = snd_pcm_open (&capture_handle,argv[1], SND_PCM_STREAM_CAPTURE, 0)) < 0) {

fprintf (stderr, "cannot open audiodevice %s (%s)\n",

argv[1],

snd_strerror (err));

exit (1);

}

//2.分配snd_pcm_hw_params_t結(jié)構(gòu)體

if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) {

fprintf (stderr, "cannot allocatehardware parameter structure (%s)\n",

snd_strerror (err));

exit (1);

}

//3.初始化hw_paraws

if ((err = snd_pcm_hw_params_any (capture_handle,hw_params)) < 0) {

fprintf (stderr, "cannot initializehardware parameter structure (%s)\n",

snd_strerror (err));

exit (1);

}

//4.初始化訪問權(quán)限

if ((err = snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {

fprintf (stderr, "cannot set accesstype (%s)\n",

snd_strerror (err));

exit (1);

}

//5.初始化采樣格式SND_PCM_FORMAT_U8,16位

if ((err = snd_pcm_hw_params_set_format(capture_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) {

fprintf (stderr, "cannot set sampleformat (%s)\n",

snd_strerror (err));

exit (1);

}

1.//6.設(shè)置采樣率,如果硬件不支持我們?cè)O(shè)置的采樣率,將使用最接近的

2.//val?=?44100,有些錄音采樣頻率固定為8KHz

if ((err = snd_pcm_hw_params_set_rate_near(capture_handle, hw_params, 44100, 0)) < 0) {

fprintf (stderr, "cannot set samplerate (%s)\n",

snd_strerror (err));

exit (1);

}

//7.設(shè)置通道數(shù)量

if ((err = snd_pcm_hw_params_set_channels(capture_handle, hw_params, 2)) < 0) {

fprintf (stderr, "cannot set channelcount (%s)\n",

snd_strerror (err));

exit (1);

}

//8.設(shè)置hw_params

if ((err = snd_pcm_hw_params (capture_handle,hw_params)) < 0) {

fprintf (stderr, "cannot setparameters (%s)\n",

snd_strerror (err));

exit (1);

}

//釋放硬件參數(shù)設(shè)置

snd_pcm_hw_params_free (hw_params);

//如果發(fā)生xrun故障,從該故障中恢復(fù)過來(lái)

if ((err = snd_pcm_prepare (capture_handle)) <0) {

fprintf (stderr, "cannot prepareaudio interface for use (%s)\n",

snd_strerror (err));

exit (1);

}

//從聲卡中讀取數(shù)據(jù),寫入到標(biāo)準(zhǔn)輸出設(shè)備

for (i = 0; i < 10; ++i) {

if ((err = snd_pcm_readi (capture_handle,buf, 128)) != 128) {

fprintf (stderr, "read fromaudio interface failed (%s)\n",

snd_strerror (err));

exit (1);

}

}

//10.關(guān)閉PCM設(shè)備句柄

snd_pcm_close (capture_handle);

exit (0);

}

/*

This example reads from the default PCMdevice

and writes to standard output for 5 secondsof data.

*/

/* Use thenewer ALSA ALI */

#defineALSA_PCM_NEW_HW_PARAMS_API

#include

#include

#include

intmain()

{

long loops;

int rc;

int size;

snd_pcm_t *handle;

snd_pcm_hw_params_t *params;

unsigned int val;

int dir;

snd_pcm_uframes_t frames;

char *buffer;

rc = snd_pcm_open(&handle,"default", SND_PCM_STREAM_CAPTURE, 0);

if (rc < 0) {

fprintf(stderr,

"unable to open pcm device:%s\n",

snd_strerror(rc));

exit(1);

}

/* Allocate a hardware parameters object.*/

snd_pcm_hw_params_alloca(?ms);

/* Fill it in with default values. */

snd_pcm_hw_params_any(handle, params);

/* Set the desired hardware parameters.*/

/* Interleaved mode */

snd_pcm_hw_params_set_access(handle,params,

SND_PCM_ACCESS_RW_INTERLEAVED);

/* Signed 16-bit little-endian format*/

snd_pcm_hw_params_set_format(handle,params,

SND_PCM_FORMAT_S16_LE);

/* Two channels (stereo) */

snd_pcm_hw_params_set_channels(handle,params, 1);

/* 44100 bits/second sampling rate (CDquality) */

val = 16000;

snd_pcm_hw_params_set_rate_near(handle,params,

&val,&dir);

/* Set period size to 32 frames. */

frames = 32;

snd_pcm_hw_params_set_period_size_near(handle,

params,&frames, &dir);

/* Write the parameters to the driver*/

rc = snd_pcm_hw_params(handle,params);

if (rc < 0) {

fprintf(stderr,

"unable to set hw parameters:%s\n",

snd_strerror(rc));

exit(1);

}

/* Use a buffer large enough to hold oneperiod */

snd_pcm_hw_params_get_period_size(params,

&frames, &dir);

size = frames*2; /* 2 bytes/sample, 2channels */

buffer = (char *) malloc(size);

/* We want to loop for 5 seconds */

snd_pcm_hw_params_get_period_time(params,

&val, &dir);

loops = 5000000 / val;

while (loops > 0) {

loops--;

rc = snd_pcm_readi(handle, buffer,frames);

if (rc == -EPIPE) {

/* EPIPE means overrun */

fprintf(stderr, "overrunoccurred\n");

snd_pcm_prepare(handle);//重新準(zhǔn)備好接受,恢復(fù)正常接受數(shù)據(jù)

} else if (rc < 0) {

fprintf(stderr,

"error from read:%s\n",

snd_strerror(rc));

} else if (rc != (int)frames) {

fprintf(stderr, "short read,read %d frames\n", rc);

}

rc = write(1, buffer, size);

if (rc != size)

fprintf(stderr,

"short write: wrote %dbytes\n", rc);

}

snd_pcm_drain(handle);//把所有掛起沒有傳輸完的聲音樣本傳輸完全

snd_pcm_close(handle);

free(buffer);

return 0;

}

打開PCM設(shè)備、設(shè)置硬件參數(shù)。我們使用由ALSA自己選擇的周期大小,申請(qǐng)?jiān)摯笮〉木彌_區(qū)來(lái)存儲(chǔ)樣本。然后我們找出周期時(shí)間,這樣我們就能計(jì)算出本程序?yàn)榱四軌虿シ?秒鐘,需要多少個(gè)周期。

在處理數(shù)據(jù)的循環(huán)中,我們從標(biāo)準(zhǔn)輸入中讀入數(shù)據(jù),并往緩沖區(qū)中填充一個(gè)周期的樣本。然后檢查并處理錯(cuò)誤,這些錯(cuò)誤可能是由到達(dá)文件結(jié)尾,或讀取的數(shù)據(jù)長(zhǎng)度與我期望的數(shù)據(jù)長(zhǎng)度不一致導(dǎo)致的。

我們調(diào)用snd_pcm_writei來(lái)發(fā)送數(shù)據(jù)。它操作起來(lái)很像內(nèi)核的寫系統(tǒng)調(diào)用,只是這里的大小參數(shù)是以幀來(lái)計(jì)算的。我們檢查其返回代碼值。返回值為EPIPE表明發(fā)生了underrun,使得PCM音頻流進(jìn)入到XRUN狀態(tài)并停止處理數(shù)據(jù)。從該狀態(tài)中恢復(fù)過來(lái)的標(biāo)準(zhǔn)方法是調(diào)用snd_pcm_prepare函數(shù),把PCM流置于PREPARED狀態(tài),這樣下次我們向該P(yáng)CM流中數(shù)據(jù)時(shí),它就能重新開始處理數(shù)據(jù)。如果我們得到的錯(cuò)誤碼不是EPIPE,我們把錯(cuò)誤碼打印出來(lái),然后繼續(xù)。最后,如果寫入的幀數(shù)不是我們期望的,則打印出錯(cuò)誤消息。這個(gè)程序一直循環(huán),直到5秒鐘的幀全部傳輸完,或者輸入流讀到文件結(jié)尾。然后我們調(diào)用snd_pcm_drain把所有掛起沒有傳輸完的聲音樣本傳輸完全,最后關(guān)閉該音頻流,釋放之前動(dòng)態(tài)分配的緩沖區(qū),退出。

1.rc?=?snd_pcm_readi(handle,?buffer,?frames);

2.if?(rc?==?-EPIPE)?{

3./*?EPIPE?means?overrun?*/

4.fprintf(stderr,?"overrun?occurred\n");

5.snd_pcm_prepare(handle);

6.}?else?if?(rc<?0)?{

7.fprintf(stderr,

8."error?from?read:?%s\n",

9.snd_strerror(rc));

10.}?else?if?(rc?!=?(int)frames)?{

11.fprintf(stderr,?"short?read,?read?%d?frames\n",?rc);

12.}

snd_pcm結(jié)構(gòu)用于表征一個(gè)PCM類型的snd_device.

struct snd_pcm {

struct snd_card *card; /*指向所屬的card設(shè)備*/

int device; /* device number */

struct snd_pcm_str streams[2]; /*播放和錄制兩個(gè)數(shù)據(jù)流*/

wait_queue_head_t open_wait; /*打開pcm設(shè)備時(shí)等待打開一個(gè)可獲得的substream */

}

應(yīng)用程序緩存區(qū)的大小可以通過ALSA庫(kù)函數(shù)調(diào)用來(lái)控制。緩存區(qū)可以很大,一次傳輸操作可能會(huì)導(dǎo)致不可接受的延遲,我們把它稱為延時(shí)(latency)。為了解決這個(gè)問題,ALSA將緩存區(qū)拆分成一系列周期(period)(OSS/Free中叫片斷fragments).ALSA以period為單元來(lái)傳送數(shù)據(jù)。

一個(gè)周期(period)存儲(chǔ)一些幀(frames)。每一幀包含時(shí)間上一個(gè)點(diǎn)所抓取的樣本。對(duì)于立體聲設(shè)備,一個(gè)幀會(huì)包含兩個(gè)信道上的樣本。

Buffer_size計(jì)算邏輯:

Buffer_size =?c->min = a->min * b-> min = period_size *

periods

底層獲得的Periods = 4,是tinplay.c中賦值的,period_size是上面計(jì)算出來(lái)的值。

.必須區(qū)分清alsa里的buffer

一. alsa展現(xiàn)的三層結(jié)構(gòu):

(1)audio interface

audio interface就是聲卡,它含有hardware

buffer,注意,這個(gè)hardware buffer是在聲卡里面,不是內(nèi)存。很多codec芯片并不像聲卡那么強(qiáng)大還有buffer,只是ap把數(shù)據(jù)通過i2scodec,其實(shí)我也不清楚wm8994這寫codec芯片里面有多大buffer,只是以為數(shù)據(jù)給它了就立馬播放了!

(2)computer:

這個(gè)指的是計(jì)算機(jī)的內(nèi)核和驅(qū)動(dòng),alsa驅(qū)動(dòng)專門管一塊內(nèi)存,這就是傳說中的ring buffer吧,alsa驅(qū)動(dòng)空間里有period,

frames的概念,當(dāng)(1)的audio interface引發(fā)中斷,內(nèi)核會(huì)捕捉到,再把處理移交alsa。

(3)application:

這個(gè)就是你寫的程序,你在用戶空間開辟一個(gè)buffer,比如playback,就交給alsa來(lái)play。

在上面的框架下,流程如下:

(1)playback:

application開辟一個(gè)buffer,填上數(shù)據(jù),調(diào)用alsa接口,alsabuffer數(shù)據(jù)復(fù)制到其驅(qū)動(dòng)空間的那塊內(nèi)存,再把數(shù)據(jù)交給hardware buffer。

(2)record:

同playback,相似的。

Alsa編譯安裝:http://blog.csdn.net/liu_chunhai/article/details/6582090

http://blog.csdn.net/shui1025701856/article/details/7646197

http://www.cnblogs.com/cslunatic/p/3677729.html

http://blog.csdn.net/zd394071264/article/details/8300045

http://blog.csdn.net/ropenyuan/article/details/9344299

http://www.cnblogs.com/lifan3a/articles/5481775.html

http://blog.chinaunix.net/uid-27106528-id-3328766.html

http://blog.csdn.net/u012769691/article/details/46727543

slsa編譯

http://blog.chinaunix.net/uid-23065002-id-3884658.html

https://www.oschina.net/news/72059/alsa-lib-1-1-1

http://www.360doc.com/content/11/0613/13/168576_126609790.shtml

alsa錄音

http://blog.csdn.net/lijin6249/article/details/51955206

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一.聲音參數(shù)基本概念: 聲音是連續(xù)模擬量,計(jì)算機(jī)將它離散化之后用數(shù)字表示,就有了以下幾個(gè)名詞術(shù)語(yǔ)。 樣本長(zhǎng)度(sa...
    cs1001閱讀 5,635評(píng)論 0 3
  • #include#include#include#include#include//#include "stdio...
    cs1001閱讀 953評(píng)論 2 0
  • 從一個(gè)同步式編程風(fēng)格遷移到Node平臺(tái)(在Node架構(gòu)中,持續(xù)傳遞風(fēng)格和異步接口是常用方式),將是一件令人受挫...
    宮若石閱讀 499評(píng)論 0 0
  • https://nodejs.org/api/documentation.html 工具模塊 Assert 測(cè)試 ...
    KeKeMars閱讀 6,620評(píng)論 0 6
  • 相關(guān)類介紹 WebResourceRequest添加于API21,封裝了一個(gè)Web資源的請(qǐng)求信息,包含:請(qǐng)求地址,...
    愛碼士閱讀 944評(píng)論 0 5

友情鏈接更多精彩內(nèi)容