2021-05-12 14:32:11
OSS--跨平台的音訊介面簡介
OSS(Open Sound System)是unix平台上一個統一的音訊介面。以前,每個Unix廠商都會提供一個自己專有的API,用來處理音訊。這就意味著為一種Unix平台編寫的音訊處理應用程式,在移植到另外一種Unix平台上時,必須要重寫。不僅如此,在一種平台上具備的功能,可能在另外一個平台上無法實現。但是,OSS出現以後情況就大不一樣了,只要音訊處理應用程式按照OSS的API來編寫,那麼在移植到另外一個平台時,只需要重新編譯即可。因此,OSS提供了原始碼級的可移植性。
同時,很多的Unix工作站中,只能提供錄音與放音的功能。有了OSS後,給這些工作站帶來了MIDI功能,加上音訊流、語音識別/生成、計算機電話(CT)、JAVA以及其它的多媒體技術,在Unix工作站中,同樣可以享受到同Windows、Macintosh環境一樣的音訊世界。另外,OSS還提供了與視訊和動畫播放同步的音訊能力,這對在Unix中實現動畫、遊戲提供了幫助。
本文首先解釋在音訊程式設計時經常遇到的名詞、裝置檔案的含義,然後分別在錄音、播放、Mixer方面對OSS介面的使用方法進行介紹。由於OSS API十分豐富,因此在本文中只介紹那些最為常用的介面。對於OSS API的一個完整描述,可以參考[1]。
一、基礎知識
數位音訊裝置(有時也稱codec,PCM,DSP,ADC/DAC裝置):播放或錄製數位化的聲音。它的指標主要有:取樣速率(電話為8K,DVD為96K)、channel數目(單聲道,立體聲)、取樣解析度(8-bit,16-bit)。
mixer(混頻器):用來控制多個輸入、輸出的音量,也控制輸入(microphone,line-in,CD)之間的切換。
synthesizer(合成器):通過一些預先定義好的波形來合成聲音,有時用在遊戲中聲音效果的產生。
MIDI 介面:MIDI介面是為了連線舞台上的synthesizer、鍵盤、道具、燈光控制器的一種序列介面。
在Unix系統中,所有的裝置都被統一成檔案,通過對檔案的存取方式(首先open,然後read/write,同時可以使用ioctl讀取/設定引數,最後close)來存取裝置。在OSS中,主要有以下的幾種裝置檔案:
- /dev/mixer:存取音效卡中內建的mixer,調整音量大小,選擇音源。
- /dev/sndstat:測試音效卡,執行cat /dev/sndstat會顯示音效卡驅動的資訊。
- /dev/dsp 、/dev/dspW、/dev/audio:讀這個裝置就相當於錄音,寫這個裝置就相當於放音。/dev/dsp與/dev/audio之間的區別在於取樣的編碼不同,/dev/audio使用μ律編碼,/dev/dsp使用8-bit(無符號)線性編碼,/dev/dspW使用16-bit(有符號)線形編碼。/dev/audio主要是為了與SunOS相容,所以盡量不要使用。
- l /dev/sequencer:存取音效卡內建的,或者連線在MIDI介面的synthesizer。
這些裝置檔案的裝置編號見[1]。
二、音訊程式設計
OSS為音訊程式設計提供三種裝置,分別是/dev/dsp,/dev/dspW和/dev/audio,前面已經提到了它們之間的區別。
使用者可以直接使用Unix的命令來放音和錄音,命令cat /dev/dsp >xyz可用來錄音,錄音的結果放在xyz檔案中;命令cat xyz >/dev/dsp播放聲音檔案xyz。
如果通過程式設計的方式來使用這些裝置,那麼Unix平台通過檔案系統提供了統一的存取介面。程式設計師可以通過檔案的操作函數直接控制這些裝置,這些操作函數包括:open、close、read、write、ioctl等。下面我們就分別討論開啟音訊裝置、放音、錄音和引數調整。
1. 開啟音訊裝置
1) 標頭檔案定義
/*
* Standard includes
*/
#include <ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/soundcard.h>
/*
* Mandatory variables.
*/
#define BUF_SIZE 4096
int audio_fd;
unsigned char audio_buffer[BUF_SIZE];
2) 開啟裝置
if ((audio_fd = open(DEVICE_NAME, open_mode, 0)) == -1) {
/* Open of device failed */
perror(DEVICE_NAME);
exit(1);
}
open_mode有三種選擇:O_RDONLY,O_WRONLY和O_RDWR,分別表示唯讀、只寫和讀寫。OSS建議盡量使用唯讀或只寫,只有在全雙工的情況下(即錄音和放音同時)才使用讀寫模式。
2. 錄音
int len;
if ((len = read(audio_fd, audio_buffer, count)) == -1) {
perror("audio read");
exit(1);
}
count為錄音資料的位元組個數(建議為2的指數),但不能超過audio_buffer的大小。從讀位元組的個數可以精確的測量時間,例如8kHZ 16-bit stereo的速率為8000*2*2=32000bytes/second,這是知道何時停止錄音的唯一方法。
3. 放音
放音實際上和錄音很類似,只不過把read改成write即可,相應的audio_buffer中為音訊資料,count為資料的長度。
注意,使用者始終要讀/寫一個完整的取樣。例如一個16-bit的立體聲模式下,每個取樣有4個位元組,所以應用程式每次必須讀/寫4的倍數個位元組。
另外,由於OSS是一個跨平台的音訊介面,所以使用者在程式設計的時候,要考慮到可移植性的問題,其中一個重要的方面是讀/寫時的位元組順序。
4. 設定引數
設定取樣格式
int format;
format = AFMT_S16_LE;
if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format) == -1) {
/* fatal error */
perror("SNDCTL_DSP_SETFMT");
exit(1);
}
if (format != AFMT_S16_LE) {
/* 本裝置不支援選擇的取樣格式. */
}
在設定取樣格式之前,可以先測試裝置能夠支援那些取樣格式,方法如下:
int mask;
if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
/* Handle fatal error ... */
}
if (mask & AFMT_MPEG) {
/* 本裝置支援MPEG取樣格式 ... */}
設定通道數目
int channels = 2; /* 1=mono, 2=stereo */
if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
/* Fatal error */
perror("SNDCTL_DSP_CHANNELS");
exit(1);
}
if (channels != 2)
{/* 本裝置不支援立體聲模式 ... */}
設定取樣速率
int speed = 11025;
if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &speed)==-1) {
/* Fatal error */
perror("SNDCTL_DSP_SPEED");
exit(Error code);
}
if ( /* 返回的速率(即硬體支援的速率)與需要的速率差別很大... */ ) {
/* 本裝置不支援需要的速率... */
}
音訊裝置通過分頻的方法產生需要的取樣時鐘,因此不可能產生所有的頻率。驅動程式會計算出最接近要求的頻率來,使用者程式要檢查返回的速率值,如果誤差較小,可以忽略,但誤差不能太大。
三、Mixer程式設計
對Mixer的控制,包括調節音量(volume)、選擇錄音音源(microphone,line-in)、查詢mixer的功能和狀態,主要是通過Mixer裝置/dev/mixer的ioctl介面。相應的,ioctl介面提供的功能也分為三類:調節音量、查詢mixer的能力、選擇mixer的錄音通道。下面就分別介紹使用的方法:
下面的mixer_fd是對mixer裝置執行open操作返回的檔案描述符。
調節音量
應用程式通過ioctl的SOUND_MIXER_READ和SOUND_MIXER_WIRTE功能號來讀取/設定音量。在OSS中,音量的大小範圍在0-100之間。使用方法如下:
int vol;
if (ioctl(mixer_fd, SOUND_MIXER_READ(SOUND_MIXER_MIC), &vol) == -1) {
/* 存取了沒有定義的mixer通道... */
SOUND_MIXER_MIC是通道引數,表示讀microphone通道的音量,結果放置在vol中。如果通道是立體聲,那麼vol的最低有效位元組為左聲道的音量值,接著的位元組為右聲道的音量值,另外的兩個位元組不用。如果通道是單聲道,vol中左聲道與右聲道具有相同的值。
查詢mixer的能力
int mask;
if (ioctl(mixer_fd, SOUND_MIXER_READ_xxxx, &mask) == -1) {
/* Mixer 的沒有此能力... */
}
SOUND_MIXER_READ_xxxx 中的xxxx代表具體要查詢的內容,比如檢查可用的mixer通道用SOUND_MIXER_READ_DEVMASK;檢查可用的錄音裝置,用SOUND_MIXER_READ_RECMASK;檢查單聲道/立體聲,用SOUND_MIXER_READ_STEREODEVS;檢查mixer的一般能力,用SOUND_MIXER_READ_CAPS等等。所有通道的查詢的結果都放在mask中,所以要區分出特定通道的狀況,使用mask& (1 << channel_no)。
選擇mixer的錄音通道
首先可以通過SOUND_MIXER_READ_RECMASK檢查可用的錄音通道,然後通過SOUND_MIXER_WRITE_RECSRC選擇錄音通道。可以隨時通過SOUND_MIXER_READ_RECSRC查詢當前音效卡中已經被選擇的錄音通道。
OSS建議把mixer的使用者控制功能單獨出來形成一個通用的程式。但前提是,在使用mixer之前,首先通過API的查詢功能檢查音效卡的能力。在linux中,就有一個專門的mixer程式--aumix。
四、結束語
前面討論的是OSS中一些最基本的內容,實際上OSS中還有很多高階的特性,比如在音訊程式設計時十分重要的實時性問題,畫面與聲音的同步問題,這裡都沒有介紹。如果讀者對這些特性感興趣的話,可以進一步參考[1]。另外,在[2]中,還可以下載使用OSS介面的樣例程式。
相關主題
- Open Sound SystemTM Programmer's Guide, version 1.11, http://www.opensound.com
相關文章