1)
2) image, font 추가
3) main.dart
import 'package:flutter/material.dart';
import 'package:video_call/screen/home_screen.dart';
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
fontFamily: 'NotoSans',
),
home: HomeScreen(),
));
}
4) const/agora.dart
5) screen/home_screen.dart
import 'package:flutter/material.dart';
import 'package:video_call/screen/cam_screen.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue[100],
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Expanded(
child: _Logo(),
),
Expanded(
child: _Image(),
),
Expanded(
child: _Button(),
),
],
),
),
);
}
}
class _Logo extends StatelessWidget {
const _Logo({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: Container(
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(16.0),
boxShadow: [
BoxShadow(
color: Colors.blue[300]!,
blurRadius: 12.0,
spreadRadius: 2.0,
)
],
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.videocam,
color: Colors.white,
size: 40.0,
),
SizedBox(
width: 12.0,
),
Text(
"LIVE",
style: TextStyle(
color: Colors.white,
fontSize: 30.0,
),
),
],
),
),
),
);
}
}
class _Image extends StatelessWidget {
const _Image({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: Image.asset(
"asset/img/home_img.png",
),
);
}
}
class _Button extends StatelessWidget {
const _Button({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) {
return CamScreen();
},
),
);
},
child: Text(
"입장하기",
),
),
],
);
}
}
6) screen/cam_screen.dart
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:video_call/const/agora.dart';
class CamScreen extends StatefulWidget {
const CamScreen({Key? key}) : super(key: key);
@override
State<CamScreen> createState() => _CamScreenState();
}
class _CamScreenState extends State<CamScreen> {
RtcEngine? engine;
// 내 ID
int? uid = 0;
int? otherUid;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"LIVE",
),
),
body: FutureBuilder<bool>(
future: init(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(
snapshot.error.toString(),
),
);
}
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Stack(
children: [
renderMainView(),
Align(
alignment: Alignment.topLeft,
child: Container(
color: Colors.grey,
height: 160,
width: 120,
child: renderSubView(),
),
),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: ElevatedButton(
onPressed: () async {
if (engine != null) {
await engine!.leaveChannel();
engine = null;
}
Navigator.of(context).pop();
},
child: Text('채널 나가기'),
),
),
],
);
},
),
);
}
renderMainView() {
if (uid == null) {
return Center(
child: Text('채널에 참여해주시요.'),
);
} else {
// 채널에 참여하고 있을 때
return AgoraVideoView(
controller: VideoViewController(
rtcEngine: engine!,
canvas: VideoCanvas(
uid: 0,
),
),
);
}
}
renderSubView() {
if (otherUid == null) {
return Center(
child: Text('채널에 유저가 없습니다.'),
);
} else {
return AgoraVideoView(
controller: VideoViewController.remote(
rtcEngine: engine!,
canvas: VideoCanvas(uid: otherUid),
connection: RtcConnection(channelId: CHANNEL_NAME),
),
);
}
}
Future<bool> init() async {
final resp = await [Permission.camera, Permission.microphone].request();
final cameraPermission = resp[Permission.camera];
final microphonePermission = resp[Permission.microphone];
if (cameraPermission != PermissionStatus.granted ||
microphonePermission != PermissionStatus.granted) {
throw "카메라 또는 마이크 권한이 없습니다.";
}
if (engine == null) {
engine = createAgoraRtcEngine();
await engine!.initialize(
RtcEngineContext(
appId: APP_ID,
),
);
engine!.registerEventHandler(
RtcEngineEventHandler(
// 내가 채널에 입장했을 때
// connection -> 연결정보
// elapsed -> 연결된 시간 (연결된지 얼마나 됐는지)
onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
print('채널에 입장했습니다. uid: ${connection.localUid}');
setState(() {
uid = connection.localUid;
});
},
// 내가 채널에서 나갔을 때
onLeaveChannel: (RtcConnection connection, RtcStats stats) {
print('채널 퇴장');
setState(() {
uid = null;
});
},
// 상대방 유저가 들어왔을 때
onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) {
print('상대가 채널에 입장했습니다. otherUid: $remoteUid');
setState(() {
otherUid = remoteUid;
});
},
// 상대가 나갔을 때
onUserOffline: (RtcConnection connection, int remoteUid,
UserOfflineReasonType reason) {
print('상대가 채널에서 나갔습니다. otherUid: $remoteUid');
setState(() {
otherUid = null;
});
},
),
);
await engine!.enableVideo();
await engine!.startPreview();
ChannelMediaOptions options = ChannelMediaOptions();
await engine!.joinChannel(
token: TEMP_TOKEN,
channelId: CHANNEL_NAME,
uid: 0,
options: options,
);
}
return true;
}
}
7)
https://webdemo.agora.io/basicVideoCall/index.html
Basic Video Call -- Agora
webdemo.agora.io
성공적으로 실행되는걸 볼 수 있다!!
'개발이 좋아서 > Flutter가 좋아서' 카테고리의 다른 글
[flutter] 켈린더 스케쥴러_UI 구현 (0) | 2023.01.17 |
---|---|
[flutter] 켈린더 스케쥴러_환경세팅 (0) | 2023.01.12 |
[flutter] 영상통화 앱_환경세팅 (0) | 2023.01.10 |
[flutter] StreamBuilder (0) | 2023.01.09 |
[flutter] FutureBuilder (0) | 2023.01.09 |