Agoraについて
Agoraは、ビデオ、音声、対話的な放送ソリューションのAPIを提供するリアルタイムコミュニケーションプラットフォームです。
準備
1. 新しいプロジェクトを作成
flutter create agora_sample
2. Agora SDKをプロジェクトに追加
flutter pub add agora_rtc_engine
flutter pub add permission_handler
3. シンプルな音波を表示するためのパッケージを追加
flutter pub add loading_indicator
参考:https://pub.dev/packages/loading_indicator
4. Agora.io で開発者アカウントにサインアップする
準備は完了です。はじめましょう!
実装
Agoraプロジェクトを設定
Agora.ioのプロジェクト管理画面でプロジェクトを選択して、設定画面に移動します。
Generate temp RTC Token
リンクをクリックしましょう。
ここで、チャネル名を入力して、トークンを生成しましょう。このトークンは後でチャネルに参加するために使用されます。
音波Widgetを作成
sound_wave.dart
class SoundWave extends StatelessWidget {
const SoundWave({super.key, required this.hasVoiceCome});
final bool hasVoiceCome;
@override
Widget build(BuildContext context) {
List<Color> soundWaveColors = const [
Color(0xFFFF5500),
Color(0xFFFF6600),
Color(0xFFFF7700),
Color(0xFFFF8800),
Color(0xFFFF9900),
Color(0xFFFAA400),
Color(0xFFFBAD00),
Color(0xFFFCB400),
Color(0xFFFDBA00),
Color(0xFFFECC00),
];
return Row(
children: List.generate(
2,
(index) {
return Padding(
padding: const EdgeInsets.only(right: 8.0),
child: LoadingIndicator(
indicatorType: Indicator.lineScalePulseOutRapid,
colors: soundWaveColors.sublist(index * 5, (index + 1) * 5),
pause: !hasVoiceCome,
),
);
},
),
);
}
}
通話画面を作成
call_screen.dart
class CallScreen extends StatefulWidget {
const CallScreen({super.key});
@override
State<CallScreen> createState() => _CallScreenState();
}
class _CallScreenState extends State<CallScreen> {
late RtcEngine _agoraEngine;
bool _muted = false;
bool _speakerOff = false;
bool _hasVoiceCome = false;
int? _remoteUid;
bool _isJoined = false;
final appId = ''; // コピーしたアプリID
final uid = 0; // 参加するユーザーID
final channelId = ''; // 設定したチャネルID(test)
final token = ''; // 生成されたトークン
@override
void initState() {
super.initState();
setupVoiceSDKEngine().onError((error, stackTrace) => {
debugPrint(error.toString()),
debugPrint(stackTrace.toString()),
});
}
@override
void dispose() {
super.dispose();
_agoraEngine.leaveChannel();
}
void _onToggleMute() {
setState(() {
_muted = !_muted;
});
_agoraEngine.muteLocalAudioStream(_muted);
}
void _onToggerSpeaker() {
setState(() {
_speakerOff = !_speakerOff;
});
_agoraEngine.setEnableSpeakerphone(!_speakerOff);
}
void _onJoin() async {
ChannelMediaOptions options = const ChannelMediaOptions(
clientRoleType: ClientRoleType.clientRoleBroadcaster,
channelProfile: ChannelProfileType.channelProfileCommunication,
);
try {
await _agoraEngine.joinChannel(
token: token,
channelId: channelId,
options: options,
uid: uid,
);
} catch (e) {
debugPrint(e.toString());
}
}
void _onLeave() {
_agoraEngine.leaveChannel();
}
Future<void> setupVoiceSDKEngine() async {
try {
// Retrieve or request microphone permission
await [Permission.microphone].request();
// Create an instance of the Agora engine
_agoraEngine = createAgoraRtcEngine();
await _agoraEngine.initialize(RtcEngineContext(appId: appId));
// Enables the audioVolumeIndication
await _agoraEngine.enableAudioVolumeIndication(
interval: 250, smooth: 8, reportVad: true);
// Register the event handler
_agoraEngine.registerEventHandler(
RtcEngineEventHandler(
onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
setState(() {
_isJoined = true;
});
},
onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) {
setState(() {
_remoteUid = remoteUid;
});
},
onUserOffline: (RtcConnection connection, int remoteUid,
UserOfflineReasonType reason) {
setState(() {
_remoteUid = null;
});
},
onAudioVolumeIndication: (
RtcConnection connection,
List<AudioVolumeInfo> speakers,
int speakerNumber,
int totalVolume,
) {
setState(() {
_hasVoiceCome = speakers.any((speaker) => speaker.vad == 1);
});
},
onError: (err, msg) => {
debugPrint(err.toString()),
debugPrint(msg.toString()),
},
),
);
} catch (err) {
debugPrint(err.toString());
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Get started with Voice Calling'),
),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(height: 40, child: Center(child: _status())),
Column(
children: [
SizedBox(
height: 60.0,
child: SoundWave(hasVoiceCome: _hasVoiceCome),
),
const SizedBox(height: 40.0),
BottomActionBar(
muted: _muted,
speakerOff: _speakerOff,
onToggleMute: _onToggleMute,
onToggleSpeaker: _onToggerSpeaker,
onJoin: _onJoin,
onLeave: _onLeave,
),
],
)
],
),
),
);
}
Widget _status() {
String statusText;
if (!_isJoined) {
statusText = 'Join a channel';
} else if (_remoteUid == null) {
statusText = 'Waiting for a remote user to join...';
} else {
statusText = 'Connected to remote user, uid:$_remoteUid';
}
return Text(
statusText,
);
}
}
-
enableAudioVolumeIndication(interval:, smooth:, reportVad:)
: ユーザーの音量インジケーターを報告するようにするために使用されます。-
smooth
はオーディオボリュームインジケーターの感度です。 値の範囲は 0 ~ 10 です。 -
reportVad
: ローカルユーザーの音声アクティビティの検出を有効にします。 有効にすると、onAudioVolumeIndication
コールバックのvad
パラメータがローカルユーザーの音声アクティビティ ステータスを報告します。
-
-
onAudioVolumeIndication
:_hasVoiceCome = speakers.any((speaker) => speaker.vad == 1)
: 少なくとも1人の話者が話しているかどうかを確認します。
実装が完了しました。試してみましょう!
結果
会話に参加するには、上記のサイトにアクセスし、以前に設定したチャネルに関する情報を入力します。
そして結果を体験しましょう!
終わり。