Java API 说明
使用 Java SDK 连接设备、接收媒体帧、保存文件并收发消息。工程依赖、JDK 和系统要求见 Java SDK 接入。
Client 与 Connection
ClientOptions.builder() 设置 appId、accessKeyId、accessKeySecret 和可写的绝对 cacheDir(Path)。可选 endpoint 省略时使用默认地址,显式空字符串无效。同一进程一个 RtcClient,可以创建多条连接。
| 操作 | 方法 |
|---|---|
| 创建连接 | client.newConnection() 或 client.newConnection(listener) |
| 连接 | connection.connect(deviceId) → CompletableFuture<Void>,无需传 Token |
| 状态与断开 | state()、disconnect();后续断线由 Connection.Listener.onStateChanged 通知 |
| 订阅 | subscribeAudio(id)、unsubscribeAudio(id)、subscribeVideo(id)、unsubscribeVideo(id) |
| 请求关键帧 | requestVideoKeyframe(id) |
| 命令 | sendCommand(long commandId, byte[] data);Listener 的 onCommand 接收 |
| 流消息 | sendStreamMessage(int id, Duration timestamp, byte[] data);Listener 的 onStreamMessage 接收 |
Stream ID 为 0..15,设备端发送、Output 绑定和订阅使用同一编号;同方向音频和视频使用不同编号。自定义命令字从 0x2001 起。流消息时间戳使用非负毫秒,最大为 uint32 毫秒。
接收第一帧视频
设置环境变量 TIRTC_APP_ID、TIRTC_ACCESS_KEY_ID、TIRTC_SECRET_KEY_ID、TIRTC_DEVICE_ID。设备发送视频流 11;将下面的类加入已配置依赖的应用并运行。收到首帧输出尺寸,失败或超时抛出异常。
import com.tange.ai.tirtc.*;
import java.nio.file.Paths;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
public final class ReceiveVideo {
public static void main(String[] args) throws Exception {
ClientOptions options = ClientOptions.builder()
.appId(System.getenv("TIRTC_APP_ID"))
.accessKeyId(System.getenv("TIRTC_ACCESS_KEY_ID"))
.accessKeySecret(System.getenv("TIRTC_SECRET_KEY_ID"))
.cacheDir(Paths.get(".tirtc-cache").toAbsolutePath())
.build();
CountDownLatch received = new CountDownLatch(1);
AtomicReference<TiRtcException> failure = new AtomicReference<>();
AtomicReference<VideoFrame> first = new AtomicReference<>();
try (RtcClient client = new RtcClient(options);
Connection connection = client.newConnection(new Connection.Listener() {
@Override public void onStateChanged(ConnectionState state, TiRtcException error) {
if (error != null) { failure.set(error); received.countDown(); }
}
});
VideoOutput video = new VideoOutput(connection, 11, new VideoOutput.Listener() {
@Override public void onFrame(VideoFrame frame) {
first.compareAndSet(null, frame);
received.countDown();
}
@Override public void onError(TiRtcException error) {
failure.set(error); received.countDown();
}
})) {
CompletableFuture<Void> attempt = connection.connect(System.getenv("TIRTC_DEVICE_ID"));
try {
attempt.get(30, TimeUnit.SECONDS);
} catch (TimeoutException error) {
attempt.cancel(false);
throw error;
}
connection.subscribeVideo(11);
connection.requestVideoKeyframe(11);
if (!received.await(30, TimeUnit.SECONDS)) {
throw new TimeoutException("30 秒内未收到视频帧");
}
if (failure.get() != null) { throw failure.get(); }
VideoFrame frame = first.get();
System.out.printf("video: %dx%d%n", frame.width(), frame.height());
}
}
}get(timeout, unit) 自身超时不会取消连接;示例显式取消 Future。初次连接失败由 Future 交付,之后的断线仍需监听状态回调。
Output 与 Frame
四类 Output 为 AudioOutput、VideoOutput、EncodedAudioOutput、EncodedVideoOutput。构造时传 Connection、Stream ID 和对应 Listener,立即绑定到该连接。每个 Listener 的 onFrame 必填,另有 onStateChanged、onError。
detach() 解除当前绑定,attach(id) 只能重新绑定同一来源的 Stream ID;最终调用 close()。不要将一个 Output 重挂到另一条 Connection。SDK 回调帧,播放、渲染和后续处理由应用完成;不提供本地音视频输入。
Frame 是不可变快照,可在回调后保留。音频通过 frame.data() 读取只读 ByteBuffer,视频通过 frame.planes() 的数据和 stride() 读取各平面;按帧实际格式、尺寸、采样率和声道解释数据。
MP4 与 JPEG
RecordingFile file;
try (RecordingTask task = connection.startRecording(new StartRecordingOptions(11, 10))) {
// 保持接收,业务需要结束保存时调用:
file = task.stop();
}上面为签名示意,connection 已连接并订阅相应流。可省略音频,只保存视频。解码视频有帧后调用 video.takeSnapshot() 取得 SnapshotFile。
两类文件的 path() 返回临时文件 Path;用 Files.copy 保存到业务目录,再调用 delete() 或 close() 删除临时源。成功领取的文件独立于任务和 Client;不要依赖关闭连接来取得录制结果,应先显式 stop()。stop() 领取文件后仍需关闭 RecordingTask,上例由 try-with-resources 完成。
释放与错误处理
资源实现 AutoCloseable,使用上例的 try-with-resources 按 Output、Connection、Client 逆序关闭。父对象关闭会级联释放后代,close() 幂等。活动录制先显式停止并处理文件。
持续 Listener 中不能同步控制同一资源树,包括发送消息、订阅和关闭;重入会抛出 IN_USE。将收到的消息或状态投递到业务线程,再调用 SDK,回调保持简短。
同步失败抛出 TiRtcException,通过 category()、code() 查类别和错误码。Future 失败通过 ExecutionException.getCause() 查看原因。记录操作、异常和 client.uploadLogs() 返回的日志 ID,便于排查。