當前位置:編程學習大全網 - 源碼下載 - 請教Linux下ALSA聲道切換

請教Linux下ALSA聲道切換

解各參數含義及些基本概念

本度(sample):本記錄音頻數據基本單位見8位16位

通道數(channel):該參數1表示單聲道2則立體聲

楨(frame):楨記錄聲音單元其度本度與通道數乘積

采率(rate):每秒鐘采數該數針楨言

周期(period):音頻設備處理所需要楨數於音頻設備數據訪問及音頻數據存儲都單位

交錯模式(interleaved):種音頻數據記錄式交錯模式數據連續楨形式存放即首先記錄完楨1左聲道本右聲道本(假設立體聲格式)再始楨2記錄非交錯模式首先記錄周期內所楨左聲道本再記錄右聲道本數據連續通道式存儲數情況我需要使用交錯模式

period(周期):硬件斷間間隔間表示輸入延

聲卡接口指針指示聲卡硬件緩存區前讀寫位置要接口運行指針循環指向緩存區某位置

frame size = sizeof(one sample) * nChannels

alsa配置緩存(buffer)周期(size)runtime幀(frames)形式存儲

period_bytes = frames_to_bytes(runtime, runtime->period_size);

bytes_to_frames()

The period and buffer sizes are not dependent on the sample format because they are measured in frames; you do not need to change them.

ALSA聲音編程介紹

ALSA表示高級Linux聲音體系結構(Advanced Linux Sound Architecture)由系列內核驅應用程序編譯接口(API)及支持Linux聲音實用程序組篇文章我簡單介紹ALSA項目基本框架及軟件組主要集介紹PCM接口編程包括您自實踐程序示例

您使用ALSA原能新並唯用聲音API您想完低級聲音操作便能夠化控制聲音並化提高性能或者您使用其聲音API沒特性ALSA選擇您已經寫音頻程序能想要ALSA聲卡驅添加本支持您音頻興趣想播放音頻文件高級API更選擇比SDL,OpenAL及些桌面環境提供工具集另外您能ALSA支持Linux環境使用ALSA

ALSA歷史

ALSA項目發起起Linux聲卡驅(OSS/Free drivers)沒積極維護並且落於新聲卡技術Jaroslav Kysela早先寫聲卡驅並由始ALSA項目隨便更發者加入發隊伍更聲卡支持API結構重組

Linux內核2.5發程ALSA合並官源碼樹發布內核2.6ALSA已經內建穩定內核版本並廣泛使用

數字音頻基礎

聲音由變化氣壓組麥克風轉換器轉換電形式模/數(ADC)轉換器模擬電壓轉換離散本值聲音固定間間隔采采速率稱采率本輸數/模(DAC)轉換器比擴音器轉換原模擬信號

本位表示本影響聲音轉換數字信號精確程度素另主要素采率奈奎斯特(Nyquist)理論要離散系統奈奎斯特頻率高於采信號高頻率或帶寬避免混疊現象

ALSA基礎

ALSA由許聲卡聲卡驅程序組同提供稱libasoundAPI庫應用程序發者應該使用libasound內核ALSA接口libasound提供高級並且編程便編程接口並且提供設備邏輯命名功能發者甚至需要知道類似設備文件低層接口相反OSS/Free驅內核系統調用級編程要求發者提供設備文件名並且利用ioctrl實現相應功能向兼容ALSA提供內核模塊模擬OSS前許OSS基礎發應用程序需要任何改ALSA運行另外libaoss庫模擬OSS需要內核模塊

ALSA包含插件功能使用插件擴展新聲卡驅包括完全用軟件實現虛擬聲卡ALSA提供系列基於命令行工具集比混音器(mixer)音頻文件播放器(aplay)及控制特定聲卡特定屬性工具

ALSA體系結構

ALSA API解幾主要接口:

1 控制接口:提供管理聲卡註冊請求用設備通用功能

2 PCM接口:管理數字音頻放(playback)錄音(capture)接口本文續總結重點放接口發數字音頻程序用接口

3 Raw MIDI接口:支持MIDI(Musical Instrument Digital Interface),標準電樂器些API提供聲卡MIDI總線訪問原始接口基於MIDI事件工作由程序員負責管理協議及間處理

4 定器(Timer)接口:同步音頻事件提供聲卡間處理硬件訪問

5 序器(Sequencer)接口

6 混音器(Mixer)接口

設備命名

API庫使用邏輯設備名設備文件設備名字真實硬件名字插件名字硬件名字使用hw:i,j格式其i卡號j塊聲卡設備號第聲音設備hw:0,0.別名默認引用第塊聲音設備並且本文示例真用插件使用另外唯名字比plughw:,表示插件插件提供硬件設備訪問提供像采率轉換軟件特性硬件本身並支持特性

聲音緩存數據傳輸

每聲卡都硬件緩存區保存記錄本緩存區足夠滿聲卡產斷內核聲卡驅使用直接內存(DMA)訪問通道本傳送內存應用程序緩存區類似於放任何應用程序使用DMA自緩存區數據傳送聲卡硬件緩存區

硬件緩存區環緩存說數據達緩存區末尾重新緩存區起始位置ALSA維護指針指向硬件緩存及應用程序緩存區數據操作前位置內核外部看我應用程序緩存區興趣所本文討論應用程序緩存區

應用程序緩存區通ALSA庫函數調用控制緩存區傳輸操作能導致接受延遲我稱延(latency)解決問題ALSA緩存區拆系列周期(period)(OSS/Free叫片斷fragments).ALSAperiod單元傳送數據

周期(period)存儲些幀(frames)每幀包含間點所抓取本於立體聲設備幀包含兩信道本圖1展示解程:緩存區解周期幀本圖包含些假定數值圖左右信道信息交替存儲幀內稱交錯(interleaved)模式非交錯模式信道所本數據存儲另外信道數據

Over and Under Run

聲卡數據總連續硬件緩存區應用程序緩存區間傳輸例外錄音例應用程序讀取數據夠快循環緩存區新數據覆蓋種數據丟失稱overrun.放例應用程序寫入數據緩存區速度夠快緩存區"餓死"錯誤稱"underrun"ALSA文檔兩種情形統稱"XRUN"適設計應用程序化XRUN並且恢復

典型聲音程序

使用PCM程序通類似面偽代碼:

打放或錄音接口

設置硬件參數(訪問模式數據格式信道數采率等等)

while 數據要處理:

讀PCM數據(錄音)

或 寫PCM數據(放)

關閉接口

我文看些工作代碼我建議您Linux系統測試運行些代碼查看輸並嘗試修改推薦代碼本文相關所實例清單FTP獲取:ftp.ssc.com/pub/lj/listings/issue126/6735.tgz

Listing 1. Display Some PCM Types and Formats

#include asoundlib.h>

int main() {

int val;

printf("ALSA library version: %s/n",

SND_LIB_VERSION_STR);

printf("/nPCM stream types:/n");

for (val = 0; val <= SND_PCM_STREAM_LAST; val++)

printf(" %s/n",

snd_pcm_stream_name((snd_pcm_stream_t)val));

printf("/nPCM access types:/n");

for (val = 0; val <= SND_PCM_ACCESS_LAST; val++)

printf(" %s/n",

snd_pcm_access_name((snd_pcm_access_t)val));

printf("/nPCM formats:/n");

for (val = 0; val <= SND_PCM_FORMAT_LAST; val++)

if (snd_pcm_format_name((snd_pcm_format_t)val)

!= NULL)

printf(" %s (%s)/n",

snd_pcm_format_name((snd_pcm_format_t)val),

snd_pcm_format_description(

(snd_pcm_format_t)val));

printf("/nPCM subformats:/n");

for (val = 0; val <= SND_PCM_SUBFORMAT_LAST;

val++)

printf(" %s (%s)/n",

snd_pcm_subformat_name((

snd_pcm_subformat_t)val),

snd_pcm_subformat_description((

snd_pcm_subformat_t)val));

printf("/nPCM states:/n");

for (val = 0; val <= SND_PCM_STATE_LAST; val++)

printf(" %s/n",

snd_pcm_state_name((snd_pcm_state_t)val));

return 0;

}

清單顯示些ALSA使用PCM數據類型參數首先需要做包括文件些文件包含所庫函數聲明其顯示ALSA庫版本

程序剩部叠代些PCM數據類型流類型始ALSA每叠代值提供符號量名並且提供功能函數顯示某特定值描述字符串看ALSA支持許格式我1.0.15版本支持達36種格式

程序必須鏈接alsalib庫通編譯需要加-lasound選項些alsa庫函數使用dlopen函數及浮點操作所您能需要加-ldl,-lm選項

面該程序Makefile:

CC=gcc

TARGET=test

SRC=$(wildcard *.c)

OBJECT= ${SRC:.c=.o}

INCLUDES=-I/usr/include/alsa

LDFLAGS=-lasound

all:$(TARGET)

$(OBJECT):$(SRC)

$(CC) -c $(INCLUDES) $<

$(TARGET):$(OBJECT)

$(CC) -o $@ $< $(LDFLAGS)

.PHONY:clean

clean:

@rm -rf $(OBJECT) $(TARGET) *~

Listing 2. Opening PCM Device and Setting Parameters

/*

This example opens the default PCM device, sets

some parameters, and then displays the value

of most of the hardware parameters. It does not

perform any sound playback or recording.

*/

/* Use the newer ALSA API */

#define ALSA_PCM_NEW_HW_PARAMS_API

/* All of the ALSA library API is defined

* in this header */

#include asoundlib.h>

int main() {

int rc;

snd_pcm_t *handle;

snd_pcm_hw_params_t *params;

unsigned int val, val2;

int dir;

snd_pcm_uframes_t frames;

/* Open PCM device for playback. */

rc = snd_pcm_open(&handle, "default",

SND_PCM_STREAM_PLAYBACK, 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, 2);

/* 44100 bits/second sampling rate (CD quality) */

val = 44100;

snd_pcm_hw_params_set_rate_near(handle,

params, &val, &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);

}

/* Display information about the PCM interface */

printf("PCM handle name = '%s'/n",

snd_pcm_name(handle));

printf("PCM state = %s/n",

snd_pcm_state_name(snd_pcm_state(handle)));

snd_pcm_hw_params_get_access(params,

(snd_pcm_access_t *) &val);

printf("access type = %s/n",

snd_pcm_access_name((snd_pcm_access_t)val));

snd_pcm_hw_params_get_format(params, &val);

printf("format = '%s' (%s)/n",

snd_pcm_format_name((snd_pcm_format_t)val),

snd_pcm_format_description(

(snd_pcm_format_t)val));

snd_pcm_hw_params_get_subformat(params,

(snd_pcm_subformat_t *)&val);

printf("subformat = '%s' (%s)/n",

snd_pcm_subformat_name((snd_pcm_subformat_t)val),

snd_pcm_subformat_description(

(snd_pcm_subformat_t)val));

snd_pcm_hw_params_get_channels(params, &val);

printf("channels = %d/n", val);

snd_pcm_hw_params_get_rate(params, &val, &dir);

printf("rate = %d bps/n", val);

snd_pcm_hw_params_get_period_time(params,

&val, &dir);

printf("period time = %d us/n", val);

snd_pcm_hw_params_get_period_size(params,

&frames, &dir);

printf("period size = %d frames/n", (int)frames);

snd_pcm_hw_params_get_buffer_time(params,

&val, &dir);

printf("buffer time = %d us/n", val);

snd_pcm_hw_params_get_buffer_size(params,

(snd_pcm_uframes_t *) &val);

printf("buffer size = %d frames/n", val);

snd_pcm_hw_params_get_periods(params, &val, &dir);

printf("periods per buffer = %d frames/n", val);

snd_pcm_hw_params_get_rate_numden(params,

&val, &val2);

printf("exact rate = %d/%d bps/n", val, val2);

val = snd_pcm_hw_params_get_sbits(params);

printf("significant bits = %d/n", val);

snd_pcm_hw_params_get_tick_time(params,

&val, &dir);

printf("tick time = %d us/n", val);

val = snd_pcm_hw_params_is_batch(params);

printf("is batch = %d/n", val);

val = snd_pcm_hw_params_is_block_transfer(params);

printf("is block transfer = %d/n", val);

val = snd_pcm_hw_params_is_double(params);

printf("is double = %d/n", val);

val = snd_pcm_hw_params_is_half_duplex(params);

printf("is half duplex = %d/n", val);

val = snd_pcm_hw_params_is_joint_duplex(params);

printf("is joint duplex = %d/n", val);

val = snd_pcm_hw_params_can_overrange(params);

printf("can overrange = %d/n", val);

val = snd_pcm_hw_params_can_mmap_sample_resolution(params);

printf("can mmap = %d/n", val);

val = snd_pcm_hw_params_can_pause(params);

printf("can pause = %d/n", val);

val = snd_pcm_hw_params_can_resume(params);

printf("can resume = %d/n", val);

val = snd_pcm_hw_params_can_sync_start(params);

printf("can sync start = %d/n", val);

snd_pcm_close(handle);

return 0;

}

  • 上一篇:an下載後彈出javascript錯誤為什麽
  • 下一篇:我懶得學習。我該怎麽辦?(如果方法有效,人民幣獎勵我。絕不撒謊!)
  • copyright 2024編程學習大全網