Flutter
这页只覆盖客户端单端视角,目标是尽快跑通“引用 SDK -> 初始化 -> 连接并播放”。
前置条件
环境要求
| 项目 | 要求 |
|---|---|
| Flutter | >=3.13.0 |
| Dart | >=3.1.0 <4.0.0 |
| 支持平台 | Android / iOS / macOS |
1. 引用 SDK
yaml
dependencies:
flutter:
sdk: flutter
tirtc_av: ^<latest-version>版本号从Flutter SDK 发布说明获取。
2. 初始化 SDK
dart
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// 应用启动时初始化一次。
await TiRtc.initialize();
runApp(
MaterialApp(
home: PlayerPage(
remoteId: 'your-remote-id',
token: 'v1.xxxxxx', // got from backend
audioStreamId: yourAudioStreamId,
videoStreamId: yourVideoStreamId,
),
),
);
}3. 连接并播放
这份 quick start 按“连上就发”策略保持最短路径。如果你的设备端采用“收到订阅再发”,连接进入 TiRtcConnState.connected 后再调用 conn.subscribeAudio(streamId: audioStreamId)、conn.subscribeVideo(streamId: videoStreamId),页面离开前再调用 conn.unsubscribeAudio(streamId: audioStreamId)、conn.unsubscribeVideo(streamId: videoStreamId)。
dart
class PlayerPage extends StatefulWidget {
const PlayerPage({
super.key,
required this.remoteId,
required this.token,
required this.audioStreamId,
required this.videoStreamId,
});
final String remoteId;
final String token;
final int audioStreamId;
final int videoStreamId;
@override
State<PlayerPage> createState() => _PlayerPageState();
}
class _PlayerPageState extends State<PlayerPage> {
static const String tag = 'TiRtcQuickStart';
final conn = TiRtcConn();
final audioOutput = TiRtcAudioOutput();
final videoOutput = TiRtcVideoOutput();
@override
void initState() {
super.initState();
// 打印基础状态,便于先定位黑屏、无声或断连。
conn.onStateChanged = (state) {
debugPrint('$tag conn state=$state');
};
conn.onDisconnected = (code) {
debugPrint('$tag conn disconnected code=$code');
};
conn.onError = (code) {
debugPrint('$tag conn error code=$code');
};
audioOutput.onStateChanged = (state) {
debugPrint('$tag audio state=$state');
};
audioOutput.onError = (code) {
debugPrint('$tag audio error code=$code');
};
videoOutput.onStateChanged = (state) {
debugPrint('$tag video state=$state');
};
videoOutput.onRenderSizeChanged = (size) {
debugPrint('$tag video size=${size.width}x${size.height}');
};
videoOutput.onError = (code) {
debugPrint('$tag video error code=$code');
};
// 绑定要播放的远端音视频流,再发起连接。
audioOutput.attach(
connection: conn,
streamId: widget.audioStreamId,
);
videoOutput.attach(
connection: conn,
streamId: widget.videoStreamId,
);
final int code = conn.connect(
remoteId: widget.remoteId,
token: widget.token,
);
if (code != 0) {
debugPrint('$tag connect request failed code=$code');
}
}
@override
void dispose() {
// 页面销毁时释放对象。
videoOutput.detach();
videoOutput.dispose();
audioOutput.detach();
audioOutput.dispose();
conn.disconnect();
conn.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: AspectRatio(
aspectRatio: 16 / 9,
child: videoOutput.view(),
),
),
);
}
}