<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          音頻系統(tǒng),Alsa 里面的buff 是怎么計(jì)算的?

          共 3239字,需瀏覽 7分鐘

           ·

          2020-09-02 21:40

          相關(guān)文章

          (干貨)Ai音箱和Linux音頻驅(qū)動(dòng)小談
          Linux ALSA 圖解
          我在MTK平臺(tái)下調(diào)試音頻ALSA

          我們知道聲音是模擬信號(hào),模擬信號(hào)轉(zhuǎn)成數(shù)字信號(hào)就一定有大小,既然有大小,那我們就需要開(kāi)辟內(nèi)存來(lái)保存這些數(shù)據(jù)。

          ---- 我們知道,視頻流的一幀就是一張圖像 ------ 但是音頻不一樣,音頻的一幀不能表示是一句話(huà),因?yàn)槟悴恢酪粋€(gè)人說(shuō)話(huà)的時(shí)間長(zhǎng)度。

          java讀取音頻代碼

          int?bufferLen?=?mSampleRateInHz?*?channels?*?2?/?10;?//?100ms?data
          ????????????????//int?bufferLen?=?2048;

          ????????????????if?((channels?==?1)?&&?(mSampleRateInHz?==?32000)?&&?(mAudioSource?==?6)?&&?(mMaxChannels?>?0))
          ????????????????{?//?get?raw?data
          ????????????????????bufferLen?=?16000?*?mMaxChannels?*?2?/?10;?//?100ms?data
          ????????????????}
          ????????????????byte[]?buffer?=?new?byte[bufferLen];
          ????????????????mAudioRecorder?=?new?AudioRecord(mAudioSource,?mSampleRateInHz,?mChannelConfig,
          ????????????????????????????AudioFormat.ENCODING_PCM_16BIT,?bufferLen?*?10);?//1?sec?buffer
          ??????????????????while(true)
          ??????????????????{
          ???????????????????size?=?mAudioRecorder.read(buffer,?0,?bufferLen);?//100ms
          ??????????????????}

          tinycap 里面的 pcm_read 代碼

          int?pcm_read(struct?pcm?*pcm,?void?*data,?unsigned?int?count)
          {
          ????struct?snd_xferi?x;

          ????if?(!(pcm->flags?&?PCM_IN))
          ????????return?-EINVAL;

          ????x.buf?=?data;
          ????x.frames?=?count?/?(pcm->config.channels?*
          ????????????????????????pcm_format_to_bits(pcm->config.format)?/?8);

          ????for?(;;)?{
          ????????if?(!pcm->running)?{
          ????????????if?(pcm_start(pcm)?????????????????fprintf(stderr,?"start?error");
          ????????????????return?-errno;
          ????????????}
          ????????}
          ????????if?(ioctl(pcm->fd,?SNDRV_PCM_IOCTL_READI_FRAMES,?&x))?{
          ????????????pcm->prepared?=?0;
          ????????????pcm->running?=?0;
          ????????????if?(errno?==?EPIPE)?{
          ????????????????????/*?we?failed?to?make?our?window?--?try?to?restart?*/
          ????????????????pcm->underruns++;
          ????????????????continue;
          ????????????}
          ????????????return?oops(pcm,?errno,?"cannot?read?stream?data");
          ????????}
          ????????return?0;
          ????}
          }

          提煉下重點(diǎn)

          我們?cè)诶锩婵吹囊粋€(gè)英文單詞 frames ,frames 相當(dāng)一幀的數(shù)據(jù)。

          ----但是這個(gè)一幀跟視頻流里面的一張圖像又不是一個(gè)概念,這里的一幀相當(dāng)于聲音里面的最小計(jì)量單位。


          音頻幀圖解

          解釋一下上面的圖片

          假設(shè)我們使用的是一個(gè)立體聲 16位 16k的音頻流,不管是錄音還是播放都一樣,那么

          • 立體聲 = 2通道
          • 1次ADC轉(zhuǎn)換樣本數(shù)據(jù)是 16bits = 2bytes
          • 1個(gè)幀 代表 所有通道的ADC轉(zhuǎn)換數(shù)據(jù)。那么我們現(xiàn)在是雙通道,所以
            • 1幀 = (通道數(shù)) * (樣本大小bytes) = 2 * 2 = 4bytes
          • 為了能支持2 * 16k的采樣率,系統(tǒng)必須支持如下的速度
            • bsp_rate = (通道數(shù)) * (1個(gè)樣本長(zhǎng)度) * (采樣率) = 1幀 * 采樣率 =
              2 * 2 *16k = 64000bytes/sec(秒)

          假設(shè)現(xiàn)在 alsa每秒中斷DMA一次。那么我們每秒都需要64000bytes數(shù)據(jù)準(zhǔn)備好,才能滿(mǎn)足一個(gè) 雙通道 16 位 16k的音頻流。

          • 如果半秒中斷一次,那么每次中斷就是 64000bytes/ 2 = 32000bytes
          • 如果我們100ms 產(chǎn)生一次中斷,那么每次中斷就是 64000bytes / 10 = 6400bytes

          我們可以通過(guò)設(shè)置period size 來(lái)控制pcm中斷的產(chǎn)生。

          反推一下
          ---- 如果我們?cè)O(shè)置一個(gè)16位雙通道16k的音頻流, 并且每次都有1600幀數(shù)據(jù)
          ---- 4 byte * 1600frams = 6400字節(jié)
          ---- 一次中斷會(huì)需要6400字節(jié)的數(shù)據(jù)
          ----那么他就是100ms中斷一次「看上面的推斷」

          alsa會(huì)自己適應(yīng)實(shí)際的buffer_size 和period_size,根據(jù)請(qǐng)求的通道數(shù),和他們其他的一些屬性。

          把音頻格式轉(zhuǎn)換成bits的代碼

          unsigned?int?pcm_format_to_bits(enum?pcm_format?format)
          {
          ????switch?(format)?{
          ????case?PCM_FORMAT_S32_LE:
          ????case?PCM_FORMAT_S24_LE:
          ????????return?32;
          ????case?PCM_FORMAT_S24_3LE:
          ????????return?24;
          ????default:
          ????case?PCM_FORMAT_S16_LE:
          ????????return?16;
          ????};
          }

          我們會(huì)使用這個(gè)函數(shù)拿到對(duì)應(yīng)格式的音頻bit「正常是16bit 和 32bit」,但是,我們讀寫(xiě)數(shù)據(jù)是字節(jié)對(duì)齊bytes對(duì)齊的,這也是我們看到很多地方有除以8這個(gè)操作的原因。

          ?x.buf?=?data;
          ?x.frames?=?count?/?(pcm->config.channels?*
          ????????????????????????pcm_format_to_bits(pcm->config.format)?/?8);

          測(cè)試的小程序

          ---- 用來(lái)錄音的測(cè)試程序

          #include?

          #define?UNUSED(x)?(void)(x)

          int?main(int?argc,?char?**argv)?{
          ????UNUSED(argc);
          ????UNUSED(argv);
          ????char?*cmd?=?"tinycap?/sdcard/1.pcm?-D?0?-d?3?-r?16000?-c?2?-b?16";
          ????char?buf[256];
          ????FILE?*fp?=?popen(cmd,?"r");
          ????for?(int?i=0;?i<16;?i++)?{
          ????????int?result?=?fread(buf,?1,?sizeof(buf),?fp);
          ????????printf("read?%d?bytes\n",?result);
          ????}
          ????pclose(fp);
          ????return?0;
          }

          這個(gè)程序會(huì)打開(kāi)聲卡 0 第 3 個(gè)pcm通路去錄音。
          我們這里沒(méi)有設(shè)置「-p」這個(gè)屬性,加上這個(gè)屬性之后,就會(huì)知道在1秒內(nèi)的中斷次數(shù),從而知道1秒內(nèi)的音頻大小了。當(dāng)然了,我們不設(shè)置,也會(huì)有一個(gè)默認(rèn)值的。


          ? 推薦閱讀:
          ? ??專(zhuān)輯|Linux文章匯總
          ? ??專(zhuān)輯|程序人生
          ? ??專(zhuān)輯|C語(yǔ)言


          嵌入式Linux
          微信掃描二維碼,關(guān)注我的公眾號(hào)?
          瀏覽 31
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚州中文字幕 | 日韩无码观看 | www高清无码 | 国产精品久久久久一区欢美无码 | 欧美操逼高清 |