Java 在多媒體傳輸上受限於頻寬與即時性,語音傳輸常採用「點對點」模式。核心難點在於:穩定的網路連線、適當的取樣率、高效的壓縮編解碼。本文採用開源專案 Answer Machine (jsresources.org) 提供的 AudioCapture、AudioPlayStream、AMAudioFormat 等類別,搭配 Tritonus GSM codec,實作一個精簡的網路對講機。
| 類別 | 職責 | 核心 API |
|---|---|---|
AMAudioFormat | 封裝 CD/FM/TELEPHONE/GSM 四種音訊格式參數,整合 Tritonus GSM codec | AudioFormat, AudioFormat.Encoding |
AudioCapture | 從麥克風擷取 PCM → GSM 壓縮,提供 AudioInputStream | TargetDataLine, AudioSystem, LineListener |
AudioPlayStream | GSM 解碼 → 喇叭播放,提供 write(byte[], int, int) | SourceDataLine |
Debug | 除錯輸出,正式版可屏蔽 | — |
tritonus_share.jar、tritonus_gsm.jar 放入 classpath。set CLASSPATH=.;tritonus_gsm.jar;tritonus_share.jarjavac am\*.java am\audio\*.javajar cmf packaging\manifest.mf am.jar am\*.class am\audio\*.classam.jar (約 8KB),專案引用即可,執行期無需 Tritonus jar。jphone 主類別,實作 Runnable、ActionListener,負責 UI、初始化音訊硬體、啟動執行緒。VoiceSender (執行緒) 讀取 AudioCapture 串流 → 經 CallLink 發送;CallLink 管理 Socket 連線、監聽、輸入/輸出串流。TALK_PORT。private AudioCapture PhoneMIC;
private AudioPlayStream PhoneSPK;
private AudioFormat format;
format = AMAudioFormat.getLineAudioFormat(AMAudioFormat.FORMAT_CODE_GSM);
PhoneMIC = new AudioCapture(AMAudioFormat.FORMAT_CODE_GSM);
PhoneSPK = new AudioPlayStream(format);
PhoneMIC.open(); PhoneSPK.open();
PhoneSPK.start(); // 啟動播放執行緒
byte[] gsmData = new byte[bufSize];
InputStream in = curCallLink.getInputStream();
while (!Thread.currentThread().isInterrupted()) {
int n = in.read(gsmData);
if (n == -1) break;
PhoneSPK.write(gsmData, 0, n);
}
InputStream micStream = PhoneMIC.getAudioInputStream();
PhoneMIC.start();
OutputStream out = curCallLink.getOutputStream();
byte[] buf = new byte[bufSize];
while (!Thread.currentThread().isInterrupted()) {
int n = micStream.read(buf);
if (n > 0) out.write(buf, 0, n);
}
class CallLink {
String ipAddr; Socket outSock; ServerSocket inServSock; Socket inSock;
CallLink(String ip) { ipAddr = ip; }
void open() throws IOException { if (ipAddr!=null) outSock=new Socket(ipAddr, TALK_PORT); }
void listen() throws IOException { inServSock=new ServerSocket(TALK_PORT); inSock=inServSock.accept(); }
InputStream getInputStream() throws IOException { return inSock!=null? inSock.getInputStream():null; }
OutputStream getOutputStream() throws IOException { return outSock!=null? outSock.getOutputStream():null; }
void close() throws IOException { if(inSock!=null) inSock.close(); if(outSock!=null) outSock.close(); }
}
# c.bat (編譯)
javac -classpath .;lib\am.jar jphone.java
# r.bat (執行)
java -classpath .;lib\am.jar jphone
雙方輸入對方 IP,點擊「撥出電話」。亦可輸入 127.0.0.1 自我測試,敲擊麥克風聽回聲驗證。