早期 Web 多媒體應用中,透過 Java Applet 嵌入網頁實現「錄音→壓縮→儲存→播放」完整鏈路。本文詳細拆解錄音機核心模組:Visual J++ J/Direct 呼叫 Windows winmm.dll 進行低延遲採樣、GSM 6.10 壓縮編碼、靜音區段偵測與資料頭標記、雙執行緒緩衝區解碼播放 AU 格式,並提供關鍵原始碼片段。
| 參數 | 設定值 | 說明 |
|---|---|---|
| 採樣率 | 8 kHz | 符合奈奎斯特定理,涵蓋語音頻帶 300~3400 Hz |
| 量化位數 | 16-bit | 動態範圍 96 dB,足夠語音品質 |
| 聲道 | 單聲道 | 資料量減半,適合網路傳輸 |
| 採樣塊大小 | 1600 bytes (0.1 秒) | 回呼頻率 10 Hz,平衡延遲與 CPU |
繞過 Java Sound API,直接以 J/Direct 映射 waveInOpen/PrepareHeader/AddBuffer/Start/Stop,利用回呼函數 Callback 於獨立執行緒推送 PCM 區塊,無需額外錄音執行緒。
// 關鍵類別結構
class AudioCapture {
WAVEINCAPS waveincaps;
WAVEHDR[] wavehdr;
Vector listeners;
native int waveInOpen(...);
native int waveInAddBuffer(...);
native int waveInStart(int hwi);
private class CallbackImpl extends Callback { ... } // J/Direct 回呼
synchronized void notifyListener(int minValue, byte[] audioData) { ... }
}
採用 GSM 6.10(壓縮比 10:1,品質尚可、速度中等)。每 0.1 秒區塊計算最小量化值 minValue,若為 0 視為靜音,僅寫入資料頭 0;否則寫入 1 + 壓縮資料體。
public void onAudioDataArrived(AudioDataEvent evt) {
int min = evt.getAudioMinValue();
fileWriter.write(min == 0 ? 0 : 1);
if (min != 0) {
Convert.BytesToInts(evt.getAudioData(), audioData);
fileWriter.write(Codec.encode(evt.getAudioData())); // GSM encode
}
}
檔案結構:[Header][Body][Header][Body]...,Header=1 byte,Body=33 bytes (GSM) 或 0 byte (靜音)。
Java Applet 原生支援 AU 格式,sun.audio.AudioPlayer.start(InputStream) 每 50ms 讀取 400 bytes。為避免解壓阻塞播放執行緒,採用「生產者-消費者」雙執行緒 + 環狀緩衝區:
AudioBuffer(InputStream 子類)。read() 取資料播放。AudioBuffer 以 wait/notify 同步,支援 suspend/resume/close 控制。class AudioBuffer extends InputStream {
byte[] data = new byte[4096];
int readPtr, writePtr, usedBytes, emptyBytes;
synchronized int read(byte[] buf, int off, int len) { ... } // 消費者
synchronized void write(byte[] buf, int off, int len) { ... } // 生產者
}
class AudioPlayer implements Runnable {
AudioBuffer buffer = new AudioBuffer(this);
public void run() {
while (!isClose) {
fileIn.read(compressData); // 讀壓縮資料
Codec.decode(compressData, auData); // 解壓
buffer.write(auData, 0, 400); // 推入緩衝區
}
}
// 啟動播放
sun.audio.AudioPlayer.start(buffer);
}
| 格式 | 壓縮比 | 檔案大小 | 音質 | 編解碼速度 | 資料率 |
|---|---|---|---|---|---|
| GSM 6.10 | 10:1 | 極小 | 普通 | 慢 | 165 B/s |
| IMA ADPCM | 4:1 | 小 | 良好 | 快 | 400 B/s |
| AU (μ-law) | 2:1 | 中 | 良好 | 極快 | 800 B/s |
AudioBuffer 實現 skip() 對應 UI 滑桿)Applet/NPAPI 已被瀏覽器封殺,現代 Web 應用請改用: