인프런 커뮤니티 질문&답변

Namchul Ghim님의 프로필 이미지
Namchul Ghim

작성한 질문수

[2024 최신] [코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

화상채팅 agora api가 6.x대로 바뀌면서 강의에서 보여주시는 함수들이 맞질 않습니다. 인자도 안맞고요

작성

·

440

0

화상채팅 agora api가 6.x대로 바뀌면서 강의에서 보여주시는 함수들이 맞질 않습니다. 인자도 안맞고요.

초보자입장에서 이거 따라할수가 없어 보입니다.

저만 그런건지 이런 건 업데이트가 안될까요?

 

답변 2

0

코드팩토리님의 프로필 이미지
코드팩토리
지식공유자

영상이 나오기전에 변경된부분 코드로 먼저 확인해보실 수 있도록 수정코드 첨부해드립니다.

아고라 6.0.0기준 home_screen.dart 파일을 아래와같이 작성하시면 됩니다.

기능은 기존 영상과 완전히 똑같고 코드도 똑같은형태로 마이그레이션만 진행한 상태입니다.

업데이트된 영상으로 조만간 찾아뵙도록 하겠습니다.

import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import '../const/agora.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';

class CamScreen extends StatefulWidget {
  const CamScreen({Key? key}) : super(key: key);

  @override
  _CamScreenState createState() => _CamScreenState();
}

class _CamScreenState extends State<CamScreen> {
  RtcEngine? engine; // 아고라 엔진을 저장할 변수
  int? uid; // 내 ID
  int? otherUid; // 상대방 ID

  Future<bool> init() async {
    final resp = await [Permission.camera, Permission.microphone].request();

    final cameraPermission = resp[Permission.camera];
    final micPermission = resp[Permission.microphone];

    if (cameraPermission != PermissionStatus.granted ||
        micPermission != PermissionStatus.granted) {
      throw '카메라 또는 마이크 권한이 없습니다.';
    }

    if (engine == null) {
      // ➊ 엔진이 정의되지 않았으면 새로 정의하기

      engine = createAgoraRtcEngine();

      // 아고라 엔진을 초기화합니다.
      await engine!.initialize(
        // 초기화할때 사용할 세팅을 제공합니다.
        RtcEngineContext(
          // 미리 저장해둔 APP ID를 입력합니다
          appId: APP_ID,
          // 라이브 동영상 송출에 최적화합니다.
          channelProfile: ChannelProfileType.channelProfileLiveBroadcasting,
        ),
      );

      engine!.registerEventHandler(
        // ➋ 아고라 엔진에서 받을 수 있는 이벤트 값들 등록
        RtcEngineEventHandler(
          onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
            // ➌ 채널 접속에 성공했을 때 실행
            print('채널에 입장했습니다. uid : ${connection.localUid}');
            setState(() {
              this.uid = connection.localUid;
            });
          },
          onLeaveChannel: (RtcConnection connection, RtcStats stats) {
            // ➍ 채널을 퇴장했을 때 실행
            print('채널 퇴장');
            setState(() {
              uid = null;
            });
          },
          onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) {
            // ➎ 다른 사용자가 접속했을 때 실행
            print('상대가 채널에 입장했습니다. uid : $remoteUid');
            setState(() {
              otherUid = remoteUid;
            });
          },
          onUserOffline: (RtcConnection connection, int remoteUid,
              UserOfflineReasonType reason) {
            // ➏ 다른 사용자가 채널을 나갔을 때 실행
            print('상대가 채널에서 나갔습니다. uid : $uid');
            setState(() {
              otherUid = null;
            });
          },
        ),
      );

      // 엔진으로 영상을 송출하겠다고 세팅합니다.
      await engine!.setClientRole(role: ClientRoleType.clientRoleBroadcaster);
      await engine!.enableVideo(); // ➐ 동영상 기능을 활성화합니다.
      await engine!.startPreview(); // 핸드폰 카메라를 이용해 동영상을 화면에 실행합니다.
      // 채널에 들어가기
      await engine!.joinChannel(
        // ➑ 채널 입장하기
        token: TEMP_TOKEN,
        channelId: CHANNEL_NAME,
        options: ChannelMediaOptions(),
        uid: 0,
      );
    }

    return true;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('LIVE'),
      ),
      body: FutureBuilder(
        // ➊ Future값을 기반으로 위젯 렌더링
        future: init(),
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          if (snapshot.hasError) {
            // ➋ Future 실행 후 에러가 이씅ㄹ때
            return Center(
              child: Text(
                snapshot.error.toString(),
              ),
            );
          }

          if (!snapshot.hasData) {
            // ➌ Future 실행 후 아직 데이터가 없을 때 (로딩 중)
            return Center(
              child: CircularProgressIndicator(),
            );
          }

          return Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              Expanded(
                child: Stack(  // children 위젯들을 순서대로 위로 쌓아주기
                  children: [
                    renderMainView(), // 화면 전체에 상대방 카메라가 찍는 영상 배치하기
                    Align(
                      alignment: Alignment.topLeft, // 위 좌측에 내 카메라가 찍는 영상 배치하기
                      child: Container(
                        color: Colors.grey,
                        height: 160,
                        width: 120,
                        child: renderSubView(),
                      ),
                    ),
                  ],
                ),
              ),
              Padding(
                padding: EdgeInsets.symmetric(horizontal: 8.0),
                child: ElevatedButton(  // 뒤로가기 기능 및 채널 퇴장 기능
                  onPressed: () async {
                    if(engine != null){
                      await engine!.leaveChannel();
                    }

                    Navigator.of(context).pop();
                  },
                  child: Text('채널 나가기'),
                ),
              ),
            ],
          );
        },
      ),
    );
  }

  Widget renderSubView(){
    if(uid != null){
      // AgoraVideoView 위젯을 사용하면
      // 동영상을 화면에 보여주는 위젯을 구현할 수 있습니다.
      return AgoraVideoView(
        // VideoViewController를 매개변수로 입력해주면
        // 해당 컨트롤러가 제공해주는 동영상 정보를
        // AgoraVideoView 위젯을통해 보여줄 수 있습니다.
        controller: VideoViewController(
          rtcEngine: engine!,
          // VideoCanvas에 0을 입력해서 내 영상을 보여줍니다.
          canvas: const VideoCanvas(uid: 0),
        ),
      );
    }else{
      // 아직 내가 채널에 접속하지 않았다면
      // 로딩화면을 보여줍니다.
      return CircularProgressIndicator();
    }
  }

  Widget renderMainView() {
    if (otherUid != null) {
      return AgoraVideoView(
        // VideoViewController.remote 생성자를 이용하면
        // 상대방의 동영상을 AgoraVideoView 그려낼 수 있습니다.
        controller: VideoViewController.remote(
          rtcEngine: engine!,
          // uid에 상대방 ID를 입력해줍니다.
          canvas: VideoCanvas(uid: otherUid),
          connection: const RtcConnection(channelId: CHANNEL_NAME),
        ),
      );
    } else {
      // 상대가 아직 채널에 들어오지 않았다면
      // 대기 메세지를 보여줍니다.
      return Center(
        child: const Text(
          '다른 사용자가 입장할때가지 대기해주세요.',
          textAlign: TextAlign.center,
        ),
      );
    }
  }
}
Namchul Ghim님의 프로필 이미지
Namchul Ghim
질문자

네.. 감사합니다. 강사님.

안그래도 강의듣고 나름 맞춰서 해보려고 했는데 일부 버그가 있어서 헤매고 있었습니다.

보내주신거 참고해서 다시 해보면 될거 같네요.

정말 감사합니다.

 

0

코드팩토리님의 프로필 이미지
코드팩토리
지식공유자

안녕하세요.

Semantic Versioning상 메이저 버전 업데이트는 완전 다른 API가 됩니다.

6.x 버전과 5.x 버전은 호환이 안되는게 당연합니다.

그러니 강의에서 사용하는 버전을 그대로 사용해주셔야합니다. (Flutter 3.3 버전 이상의경우 아고라 5.2.x 버전 이상)

이건 모든 강의가 똑같습니다. 추후 업데이트를 할 예정이나 강의 업데이트가 모든 API 업데이트를 동시에 따라갈수가 없습니다.

하지만 그 어떤 버전이든 한번 사용해보면 다음세대의 버전도 금방 사용할 수 있게 되기때문에 학습을 진행하신 후 필요를 느끼시면 업데이트 후 무엇이 바뀌었는지 차이점만 파악하시면 될 것 같습니다.

아고라 외에도 초보 강의에 많은 업데이트가 계획되어있으니 참고해주세요.

감사합니다.

Namchul Ghim님의 프로필 이미지
Namchul Ghim

작성한 질문수

질문하기