语音对讲
客户端在已建立的 TiRTC 连接上采集本地麦克风,并把声音发送给设备端,适用于门铃对讲等场景。
如果你还没完成客户端工程接入、连接或远端音视频播放,先看对应客户端的 SDK 接入页(例如 Web、Flutter 或 React Native)、建立与设备端的连接和音视频流传输与播放。
前提条件
- 客户端已经完成
TiRtc.initialize(...)。 - 连接已经建立,状态进入
connected/CONNECTED。 - 应用已经完成系统麦克风权限申请。Android 需要
RECORD_AUDIO;iOS 需要麦克风权限;Flutter 和 React Native 按目标平台申请对应权限。 - 设备端已经准备好接收客户端本地音频,并和客户端约定相同的
stream_id。
与设备端约定对讲使用的音频 stream_id
语音对讲使用客户端本地麦克风输入。客户端的示例和 DevTools CLI 默认使用:
| 用途 | stream_id |
|---|---|
| 客户端麦克风对讲 | 14 |
14 是示例取值;也可以约定其他 stream_id,取值范围是 0 到 15。
启动语音对讲
基本顺序是:创建 TiRtcAudioInput -> 设置采集参数 -> 绑定连接和本地音频 stream_id -> 调用 start()。
dart
final TiRtcAudioInput talkbackInput = TiRtcAudioInput();
Future<int> startTalkback(TiRtcConn conn) async {
talkbackInput.onStateChanged = (TiRtcInputState state) {
debugPrint('talkback state=$state');
};
talkbackInput.onError = (int code, String? message) {
debugPrint('talkback error=$code message=${message ?? ""}');
};
int code = await talkbackInput.setOptions(
const TiRtcAudioInputOptions(
codec: TiRtcAudioCodec.g711a,
sampleRate: TiRtcAudioSampleRate.rate16k,
channels: TiRtcAudioChannelCount.mono,
aecMode: TiRtcAudioAecMode.enabled,
),
);
if (code != 0) return code;
code = await talkbackInput.attach(connection: conn, streamId: 14);
if (code != 0) return code;
return talkbackInput.start();
}
Future<void> stopTalkback(TiRtcConn conn) async {
await talkbackInput.stop();
await talkbackInput.detach(connection: conn);
await talkbackInput.dispose();
}tsx
import {
TiRtcAudioAecMode,
TiRtcAudioChannelCount,
TiRtcAudioCodec,
TiRtcAudioInput,
TiRtcAudioSampleRate,
TiRtcConn,
} from 'tirtc-av-react-native';
const talkbackInput = new TiRtcAudioInput();
async function startTalkback(conn: TiRtcConn): Promise<number> {
talkbackInput.onStateChanged = (state) => {
console.info(`talkback state=${state}`);
};
talkbackInput.onError = (code, message) => {
console.warn(`talkback error=${code} message=${message ?? ''}`);
};
let code = await talkbackInput.setOptions({
codec: TiRtcAudioCodec.g711a,
sampleRate: TiRtcAudioSampleRate.rate16k,
channels: TiRtcAudioChannelCount.mono,
aecMode: TiRtcAudioAecMode.enabled,
});
if (code !== 0) return code;
code = await talkbackInput.attach(conn, 14);
if (code !== 0) return code;
return talkbackInput.start();
}
async function stopTalkback(conn: TiRtcConn): Promise<void> {
await talkbackInput.stop();
await talkbackInput.detach(conn);
await talkbackInput.dispose();
}kotlin
val talkbackInput = TiRtcAudioInput()
fun startTalkback(conn: TiRtcConn): Int {
talkbackInput.onStateChanged = TiRtcInputStateListener { state ->
Log.i("TiRTC", "talkback state=$state")
}
talkbackInput.onError = TiRtcInputErrorListener { code, message ->
Log.w("TiRTC", "talkback error=$code message=$message")
}
var code = talkbackInput.setOptions(
TiRtcAudioInputOptions(
codec = TiRtcAudioCodec.G711A,
sampleRate = TiRtcAudioSampleRate.RATE_16K,
channels = TiRtcAudioChannelCount.MONO,
aecMode = 1,
),
)
if (code != 0) return code
code = talkbackInput.attach(conn, 14)
if (code != 0) return code
return talkbackInput.start()
}
fun stopTalkback(conn: TiRtcConn) {
talkbackInput.stop()
talkbackInput.detach(conn)
talkbackInput.dispose()
}ts
import { TiRtcAudioInput, TiRtcAudioCodec, TiRtcAudioSampleRate } from 'tirtc-av/Index';
const talkbackInput = new TiRtcAudioInput();
async function startTalkback(conn: TiRtcConn): Promise<number> {
let code = await talkbackInput.setOptions({
codec: TiRtcAudioCodec.g711a,
sampleRate: TiRtcAudioSampleRate.rate16k,
channels: 1,
aecMode: 1,
});
if (code !== 0) return code;
code = await talkbackInput.attach({ connection: conn, streamId: 14 });
if (code !== 0) return code;
return talkbackInput.start();
}
async function stopTalkback(conn: TiRtcConn): Promise<void> {
await talkbackInput.stop();
await talkbackInput.detach({ connection: conn });
await talkbackInput.dispose();
}swift
final class Talkback: NSObject, TiRtcAudioInputDelegate {
private let input = TiRtcAudioInput()
override init() {
super.init()
input.delegate = self
}
func start(conn: TiRtcConn) -> Int32 {
let options = TiRtcAudioInputOptions()
options.codec = .g711a
options.sampleRate = .rate16k
options.channels = .mono
options.aecMode = 1
var code = input.setOptions(options)
if code != 0 { return code }
code = input.attach(connection: conn, streamId: 14)
if code != 0 { return code }
return input.start()
}
func stop(conn: TiRtcConn) {
_ = input.stop()
_ = input.detach(connection: conn)
input.dispose()
}
func audioInput(_ input: TiRtcAudioInput, didChangeState state: TiRtcInputState) {
print("talkback state=\(state.rawValue)")
}
func audioInput(_ input: TiRtcAudioInput, didFailWithCode code: Int32, message: String?) {
print("talkback error=\(code) message=\(message ?? "")")
}
}js
const talkbackInput = TiRtcAudioInput({
connection,
streamId: 14,
});
async function startTalkback() {
talkbackInput.setOptions({ sampleRate: 8000 });
await talkbackInput.start(); // 在点击按钮等用户手势里调用,浏览器会在这里申请麦克风权限
await talkbackInput.attach();
}
async function stopTalkback() {
talkbackInput.stop();
await talkbackInput.detach();
}确认语音已送到设备端
TiRtcAudioInput.start() 返回 0 只表示客户端已经开始采集和发送请求。真正跑通语音对讲,需要同时看到两个结果:
- 客户端输入状态进入
running/RUNNING,并且没有触发输入错误回调。 - 你在客户端说话时,设备端能收到或播出对应
stream_id的音频。使用 C SDK 接收时,可在TIRTCCALLBACKS.on_audio中检查pFi->stream_id,示例默认是14。
常见问题
打开麦克风失败
优先检查:
- 应用是否已经获得系统麦克风权限。
- 连接是否已经进入 connected。
- 本地对讲使用的
stream_id是否和设备端接收配置一致。 TiRtcAudioInput是否还绑定着旧连接或旧stream_id;更换绑定前先stop()和detach()。
设备端听不到客户端声音
优先检查:
- 客户端是否调用了
TiRtcAudioInput.start()并拿到返回值0。 - 设备端是否在接收客户端约定的本地音频
stream_id,例如示例默认14。 - 客户端系统输入设备是否正常,麦克风是否被其他应用独占。
- 如果使用 DevTools CLI 验证语音对讲,CLI 是否用
--input system --output both启动。