You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
6.3.2
Unable to video on TestFlight build IOS
Its working perfectly fine locally and on android but IOS when pushed to Testflight unable to view the video
Platforms affected
Android
iOS
macOS
Windows
Web
Steps to reproduce
Create token from backend
Join video call
Join channel
Unable to view video
Expected results
We should be able to view the video
Actual results
Currently could not see the current user or remote user video
class JoinTelehealthVideoWidget extends StatefulWidget {
final String channelName;
final String rtcToken;
final bool isMicEnabled;
final bool isVideoEnabled;
@OverRide
State createState() =>
_JoinTelehealthVideoWidgetState();
}
class _JoinTelehealthVideoWidgetState extends State {
late final AgoraService _agoraService;
late JoinTelehealthVideoModel _model;
late final RtcEngine _agoraEngine;
final Set _users = {};
late double _viewAspectRatio;
// StreamController for broadcasting messages
To properly investigate this issue, we need to collect sensitive information that shouldn't be discussed in a public forum.
Please submit a ticket through Agora Support for a detailed investigation. Once you have any findings or solutions, feel free to share them here to help other developers. Thank you for your understanding!
Version of the agora_rtc_engine
6.3.2
Unable to video on TestFlight build IOS
Its working perfectly fine locally and on android but IOS when pushed to Testflight unable to view the video
Platforms affected
Steps to reproduce
Expected results
Actual results
Code sample
Code sample
[Paste your code here]
Screenshots or Video
Screenshots / Video demonstration
`import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:ollie/bloc/agoraBloc/agora_bloc.dart';
import 'package:ollie/bloc/bookAppointmentBloc/bookAppointment_bloc.dart';
import 'package:ollie/constants/agora_constants.dart';
import 'package:ollie/constants/app_styles.dart';
import 'package:ollie/repository/user_repository.dart';
import 'package:ollie/routes/route_names.dart';
import 'package:ollie/services/agora_service.dart';
import 'package:ollie/services/agora_user.dart';
import 'package:ollie/utils/app_helpers.dart';
import 'package:ollie/utils/design_system_size_config.dart';
import 'package:ollie/views/booking/join_telehealth_video/message_stream_service.dart';
import 'package:ollie/views/booking/join_telehealth_video/trascript_view_state.dart';
import 'package:ollie/views/inbox/direct_message/chat_screen_view_state.dart';
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '../../../proto/SttMessage.pb.dart' as proto;
import 'join_telehealth_video_model.dart';
export 'join_telehealth_video_model.dart';
class JoinTelehealthVideoWidget extends StatefulWidget {
final String channelName;
final String rtcToken;
final bool isMicEnabled;
final bool isVideoEnabled;
const JoinTelehealthVideoWidget({
super.key,
required this.channelName,
required this.rtcToken,
this.isMicEnabled = false,
this.isVideoEnabled = false,
});
@OverRide
State createState() =>
_JoinTelehealthVideoWidgetState();
}
class _JoinTelehealthVideoWidgetState extends State {
late final AgoraService _agoraService;
late JoinTelehealthVideoModel _model;
late final RtcEngine _agoraEngine;
final Set _users = {};
late double _viewAspectRatio;
// StreamController for broadcasting messages
int? _currentUid;
bool _isMicEnabled = false;
bool _isVideoEnabled = false;
@OverRide
void initState() {
super.initState();
_model = createModel(context, () => JoinTelehealthVideoModel());
// _agoraService = AgoraService.instance;
// _model.isMicMuted = widget.isMuted;
// _model.isVideoEnabled = widget.isVideoEnabled;
}
Future createDataStream() async {
await _agoraEngine.createDataStream(
DataStreamConfig(syncWithAudio: true, ordered: true),
);
}
Future _initialize() async {
_viewAspectRatio = kIsWeb
? 3 / 2
: (Platform.isAndroid || Platform.isIOS)
? 2 / 3
: 3 / 2;
}
Future _initAgoraRtcEngine() async {
_agoraEngine = createAgoraRtcEngine();
await _agoraEngine.initialize(
RtcEngineContext(
appId: AgoraConstants.appId,
channelProfile: ChannelProfileType.channelProfileLiveBroadcasting,
audioScenario: AudioScenarioType
.audioScenarioGameStreaming, // Improves iOS audio performance
),
);
}
void _addAgoraEventHandlers() {
_agoraEngine.registerEventHandler(
RtcEngineEventHandler(
onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
log('✅ Joined channel: ${connection.channelId}');
print('✅ Joined channel: ${connection.channelId}');
// setState(() {
// _currentUid = connection.localUid;
// });
print('✅ Joined channel: current user Id ${connection.localUid}');
},
onStreamMessage:
(connection, remoteUid, streamId, data, length, sentTs) {
messageStreamService.onStreamMessage(
connection, remoteUid, streamId, data, length, sentTs);
// var message = proto.Text.fromBuffer(data);
// log("message: ${message.words}");
// _messageStreamController.add(TrascriptViewState(
// message: message.words
// .where((item) => item.isFinal == true && item.text.isNotEmpty)
// .first
// .text,
// userId: message.uid.toString()));
},
onUserMuteVideo: (connection, remoteUid, muted) {
log('📹 Remote user video muted: $remoteUid - $muted');
setState(() {
_model.isRemoteVideoEnabled = !muted;
});
},
onUserMuteAudio: (connection, remoteUid, muted) {
log('🔇 Remote user audio muted: $remoteUid - $muted');
},
onUserJoined: (RtcConnection connection, int uid, int elapsed) {
log('👤 Remote user joined: $uid');
if (uid >= 20000000) {
return;
}
setState(() {
_users.add(AgoraUser(
uid: uid,
view: AgoraVideoView(
controller: VideoViewController.remote(
rtcEngine: _agoraEngine,
canvas: VideoCanvas(uid: uid),
connection: RtcConnection(channelId: widget.channelName),
),
)));
});
},
onUserOffline:
(RtcConnection connection, int uid, UserOfflineReasonType reason) {
setState(() {
_users.removeWhere((user) => user.uid == uid);
});
},
),
);
}
Future _onCallEnd(BuildContext context) async {
await _agoraEngine.leaveChannel();
if (context.mounted) Navigator.of(context).pop();
}
Future _onToggleAudio() async {
_isMicEnabled = !_isMicEnabled;
await _agoraEngine.muteLocalAudioStream(!_isMicEnabled);
setState(() {});
}
Future _onToggleCamera() async {
_isVideoEnabled = !_isVideoEnabled;
await _agoraEngine.muteLocalVideoStream(!_isVideoEnabled);
setState(() {});
}
Future _onSwitchCamera() async {
await _agoraEngine.switchCamera();
}
/// Initialize and Join Channel
Future _initializeAndJoinChannel() async {
try {
await _agoraService.initialize(
uid: 0,
isMicEnabled: _model.isMicMuted,
isVideoEnabled: _model.isVideoEnabled);
await _agoraService.setAsHost();
await _agoraService.startPreview();
if (mounted) {
setState(() => _model.isAgoraInitialized = true);
final userID = UserRepository().userData.id;
await _agoraService.joinChannel(
widget.rtcToken, widget.channelName, userID);
}
} catch (e) {
log('Error initializing Agora: $e');
}
}
/// Toggle Microphone
void _toggleMic() async {
if (_model.isAgoraInitialized) {
setState(() => _model.isMicMuted = !_model.isMicMuted);
await _agoraService.muteAudio(_model.isMicMuted);
}
}
/// Toggle Video
void _toggleVideo() async {
if (_model.isAgoraInitialized) {
setState(() => _model.isVideoEnabled = !_model.isVideoEnabled);
await _agoraService.muteVideo(!_model.isVideoEnabled);
}
}
Future _disposeAgora() async {
await _agoraEngine.leaveChannel();
await _agoraEngine.release();
}
@OverRide
void dispose() {
_users.clear();
_disposeAgora();
}
@OverRide
Widget build(BuildContext context) {
final doctorId = context
.watch()
.bookingDetailsViewState
?.doctorId ??
0;
final doctorName = context
.watch()
.bookingDetailsViewState
?.doctorName ??
'';
}
/// Waiting Placeholder
Widget _buildWaitingForUser() {
return Center(
child: Text(
'Waiting for remote user...',
style: AppStyles.primaryBold(24),
),
);
}
/// Bottom Control Buttons
Widget _buildBottomControls() {
return Positioned(
bottom: 20,
left: 0,
right: 0,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
/// End Call Button
_buildControlButton(Icons.call_end, Colors.red, () {
_onCallEnd(context);
Navigator.pop(context);
}),
}
/// Build Control Button
Widget _buildControlButton(IconData icon, Color color, VoidCallback onTap) {
return CircleAvatar(
radius: 28,
backgroundColor: FlutterFlowTheme.of(context).secondaryBackground,
child: IconButton(icon: Icon(icon, color: color), onPressed: onTap),
);
}
/// More Options (Transcript, Chat)
Widget _buildMoreOptions() {
return CircleAvatar(
radius: 28,
backgroundColor: FlutterFlowTheme.of(context).secondaryBackground,
child: PopupMenuButton(
icon: const Icon(Icons.more_vert, color: Colors.black),
onSelected: (value) => _handleMoreOptions(value),
itemBuilder: (context) => [
_buildPopupMenuItem('Transcript', Icons.notes),
_buildPopupMenuItem('In-call chat', Icons.chat),
],
),
);
}
/// Popup Menu Item
PopupMenuItem _buildPopupMenuItem(String text, IconData icon) {
return PopupMenuItem(
value: text,
child: Row(children: [
Icon(icon, color: Colors.black),
const SizedBox(width: 8),
Text(text)
]),
);
}
/// Handle More Options
void _handleMoreOptions(String value) {
if (value == 'Transcript') {
context.pushNamed(RouteNames.transcriptionView,
extra: widget.channelName);
} else if (value == 'In-call chat') {
context.read().add(InitializeAgoraChatServerEvent());
context.pushNamed(
RouteNames.inCallChat,
extra: ChatScreenViewState(
chatId: '',
fullName: context
.read()
.bookingDetailsViewState
?.doctorName ??
'',
channelName: widget.channelName,
profilePic: '',
userId: context
.read()
.bookingDetailsViewState
?.doctorId ??
0,
),
);
}
}
/// Local Video View (Top Right)
Widget _buildLocalVideoView() {
return Align(
alignment: Alignment.topRight,
child: Container(
width: DesignSystemSizeConfig.width(120),
margin: const EdgeInsets.only(top: 60, right: 20),
height: DesignSystemSizeConfig.height(150),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(8.0),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: _isVideoEnabled
? AgoraVideoView(
controller: VideoViewController(
rtcEngine: _agoraEngine,
canvas: VideoCanvas(uid: _currentUid ?? 0),
),
onAgoraVideoViewCreated: (viewId) {
log('Local video view created: $viewId');
_agoraEngine.startPreview();
},
)
: _buildProfilePlaceholder(),
),
),
);
}
/// Profile Placeholder
Widget _buildProfilePlaceholder() {
return Center(
child: CircleAvatar(
backgroundColor: Colors.white,
radius: 30,
child: Text(getInitials(UserRepository().userData.firstName ?? '',
UserRepository().userData.lastName ?? '')),
),
);
}
/// Remote Profile Placeholder
Widget _buildRemoteUserPlaceHolder(String name) {
return Center(
child: CircleAvatar(
backgroundColor: Colors.white,
radius: 30,
child: Text(getInitialsFromFullName(name)),
),
);
}
}
`
Logs
Logs
[Paste your logs here]
Flutter Doctor output
Doctor output
[Paste your output here]
The text was updated successfully, but these errors were encountered: