eggnstone_amazon_chime 0.4.1 eggnstone_amazon_chime: ^0.4.1 copied to clipboard
A wrapper for the Amazon Chime SDKs. Allows to join Chime meetings using audio and video.
import 'dart:convert';
import 'dart:io';
import 'package:chime_example/data/Mapping.dart';
import 'package:chime_example/data/Mappings.dart';
import 'package:device_info/device_info.dart';
import 'package:eggnstone_amazon_chime/eggnstone_amazon_chime.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:permission_handler/permission_handler.dart';
const MAX_VIEW_COUNT = 2;
void main()
{
runApp(App());
}
class App extends StatefulWidget
{
@override
_AppState createState()
=> _AppState();
}
class _AppState extends State<App>
{
String _version = 'Unknown';
String _createMeetingSessionResult = 'CreateMeetingSession: Unknown';
String _audioVideoStartResult = 'AudioVideo: Unknown';
String _audioVideoStartLocalVideoResult = 'AudioVideoLocalVideo: Unknown';
String _audioVideoStartRemoteVideoResult = 'AudioVideoRemoteVideo: Unknown';
List<ChimeDefaultVideoRenderView> _chimeViews;
Mappings _mappings = Mappings();
bool _isAndroidEmulator = false;
@override
void initState()
{
super.initState();
_chimeViews = List<ChimeDefaultVideoRenderView>();
for (int viewIndex = 0; viewIndex < MAX_VIEW_COUNT; viewIndex++)
_chimeViews.add(ChimeDefaultVideoRenderView(
onPlatformViewCreated: (int viewId)
=> _mappings.add(viewIndex, viewId))
);
_startChime();
}
@override
Widget build(BuildContext context)
{
var children = List<Widget>();
for (int i = 0; i < MAX_VIEW_COUNT; i++)
children.add(Expanded(child: _chimeViews[i]));
var chimeViewColumn = Column(children: children);
Widget content = _isAndroidEmulator
? Padding(
padding: const EdgeInsets.all(16),
child: Center(
child: Text('Chime does not support Android emulators (x86 devices).\n\nIf you see the SDK version above then the connection to the SDK works though.')
)
)
: Column(
children: [
Text(_createMeetingSessionResult),
SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text('Audio/Video:'),
RaisedButton(
child: Text('Start'),
onPressed: ()
=> _audioVideoStart()
),
RaisedButton(
child: Text('Stop'),
onPressed: ()
=> _audioVideoStop()
)
]
),
Text(_audioVideoStartResult),
SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text('Local Video:'),
RaisedButton(
child: Text('Start'),
onPressed: ()
=> _audioVideoStartLocalVideo()
),
RaisedButton(
child: Text('Stop'),
onPressed: ()
=> _audioVideoStopLocalVideo()
)
]
),
Text(_audioVideoStartLocalVideoResult),
SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text('Remote Video:'),
RaisedButton(
child: Text('Start'),
onPressed: ()
=> _audioVideoStartRemoteVideo()
),
RaisedButton(
child: Text('Stop'),
onPressed: ()
=> _audioVideoStopRemoteVideo()
)
]
),
Text(_audioVideoStartRemoteVideoResult),
SizedBox(height: 8),
Expanded(child: chimeViewColumn)
]
);
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('ChimePlugin')),
body: Column(
children: [
SizedBox(height: 8),
Text(_version),
SizedBox(height: 8),
Expanded(child: content)
]
)
)
);
}
void _startChime()
async
{
await _getVersion();
if (Platform.isAndroid)
{
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
if (androidInfo.isPhysicalDevice)
{
_addListener();
await _createMeetingSession();
}
else
{
setState(()
{
_isAndroidEmulator = true;
});
}
}
else
{
_addListener();
await _createMeetingSession();
}
}
Future<void> _getVersion()
async
{
String version;
try
{
version = await Chime.version;
}
on PlatformException
{
version = 'Failed to get version.';
}
if (mounted)
setState(()
{
_version = version;
});
}
void _addListener()
{
Chime.eventChannel.receiveBroadcastStream().listen(
(data)
async
{
dynamic event = JsonDecoder().convert(data);
String eventName = event['Name'];
dynamic eventArguments = event['Arguments'];
switch (eventName)
{
case 'OnVideoTileAdded':
_handleOnVideoTileAdded(eventArguments);
break;
case 'OnVideoTileRemoved':
_handleOnVideoTileRemoved(eventArguments);
break;
default:
print('Chime.eventChannel.receiveBroadcastStream().listen()/onData()');
print('Warning: Unhandled event: $eventName');
print('Data: $data');
break;
}
},
onDone: ()
{
print('Chime.eventChannel.receiveBroadcastStream().listen()/onDone()');
},
onError: (e)
{
print('Chime.eventChannel.receiveBroadcastStream().listen()/onError()');
}
);
}
Future<void> _createMeetingSession()
async
{
if (await Permission.microphone
.request()
.isGranted == false)
{
_createMeetingSessionResult = 'Need microphone permission.';
return;
}
if (await Permission.camera
.request()
.isGranted == false)
{
_createMeetingSessionResult = 'Need camera permission.';
return;
}
String meetingSessionState;
try
{
meetingSessionState = await Chime.createMeetingSession(
meetingId: 'Test-MeetingId',
externalMeetingId: 'Test-ExternalMeetingId',
mediaRegion: 'eu-central-1',
mediaPlacementAudioHostUrl: 'SomeGuid.k.m1.ec1.app.chime.aws:3478',
mediaPlacementAudioFallbackUrl: 'wss://haxrp.m1.ec1.app.chime.aws:443/calls/Test-MeetingId',
mediaPlacementSignalingUrl: 'wss://signal.m1.ec1.app.chime.aws/control/Test-MeetingId',
mediaPlacementTurnControlUrl: 'https://ccp.cp.ue1.app.chime.aws/v2/turn_sessions',
attendeeId: 'Test-AttendeeId',
externalUserId: 'Test-ExternalUserId-1',
joinToken: 'Test-JoinToken'
);
}
on PlatformException catch (e)
{
meetingSessionState = 'Failed to create MeetingSession. PlatformException: $e';
}
catch (e)
{
meetingSessionState = 'Failed to create MeetingSession. Error: $e';
}
if (mounted)
setState(()
{
_createMeetingSessionResult = meetingSessionState;
});
}
Future<void> _audioVideoStart()
async
{
String result;
try
{
result = await Chime.audioVideoStart();
}
on PlatformException catch (e)
{
result = 'AudioVideoStart failed: PlatformException: $e';
}
catch (e)
{
result = 'AudioVideoStart failed: Error: $e';
}
if (mounted)
setState(()
{
_audioVideoStartResult = result;
});
}
Future<void> _audioVideoStop()
async
{
String result;
try
{
result = await Chime.audioVideoStop();
}
on PlatformException catch (e)
{
result = 'AudioVideoStop failed: PlatformException: $e';
}
catch (e)
{
result = 'AudioVideoStop failed: Error: $e';
}
if (mounted)
setState(()
{
_audioVideoStartResult = result;
});
}
Future<void> _audioVideoStartLocalVideo()
async
{
String result;
try
{
result = await Chime.audioVideoStartLocalVideo();
}
on PlatformException catch (e)
{
result = 'AudioVideoStartLocalVideo failed: PlatformException: $e';
}
catch (e)
{
result = 'AudioVideoStartLocalVideo failed: Error: $e';
}
if (mounted)
setState(()
{
_audioVideoStartLocalVideoResult = result;
});
}
Future<void> _audioVideoStopLocalVideo()
async
{
String result;
try
{
result = await Chime.audioVideoStopLocalVideo();
}
on PlatformException catch (e)
{
result = 'AudioVideoStopLocalVideo failed: PlatformException: $e';
}
catch (e)
{
result = 'AudioVideoStopLocalVideo failed: Error: $e';
}
if (mounted)
setState(()
{
_audioVideoStartLocalVideoResult = result;
});
}
Future<void> _audioVideoStartRemoteVideo()
async
{
String result;
try
{
result = await Chime.audioVideoStartRemoteVideo();
}
on PlatformException catch (e)
{
result = 'AudioVideoStartRemoteVideo failed: PlatformException: $e';
}
catch (e)
{
result = 'AudioVideoStartRemoteVideo failed: Error: $e';
}
if (mounted)
setState(()
{
_audioVideoStartRemoteVideoResult = result;
});
}
Future<void> _audioVideoStopRemoteVideo()
async
{
String result;
try
{
result = await Chime.audioVideoStopRemoteVideo();
}
on PlatformException catch (e)
{
result = 'AudioVideoStopRemoteVideo failed: PlatformException: $e';
}
catch (e)
{
result = 'AudioVideoStopRemoteVideo failed: Error: $e';
}
if (mounted)
setState(()
{
_audioVideoStartRemoteVideoResult = result;
});
}
void _handleOnVideoTileAdded(dynamic arguments)
async
{
int tileId = arguments['TileId'];
Mapping mapping = _mappings.getByTileId(tileId);
if (mapping != null)
{
print('_handleOnVideoTileAdded: Already mapped. TileId=${mapping.tileId}] => ViewId=${mapping.viewId} => binding again');
await Chime.bindVideoView(mapping.viewId, mapping.tileId);
return;
}
for (int viewIndex = 0; viewIndex < MAX_VIEW_COUNT; viewIndex++)
{
mapping = _mappings.getByViewIndex(viewIndex);
if (mapping.tileId == null)
{
mapping.tileId = tileId;
print('_handleOnVideoTileAdded: New mapping: TileId=${mapping.tileId} => ViewId=${mapping.viewId} => binding');
await Chime.bindVideoView(mapping.viewId, mapping.tileId);
return;
}
}
print('Error: _handleOnVideoTileAdded: Could not find free view. Ignoring new video tile.');
}
void _handleOnVideoTileRemoved(dynamic arguments)
async
{
int tileId = arguments['TileId'];
Mapping mapping = _mappings.getByTileId(tileId);
if (mapping == null)
{
print('Error: _handleOnVideoTileRemoved: Could not find mapping for TileId=$tileId');
return;
}
print('_handleOnVideoTileRemoved: Found mapping: TileId=${mapping.tileId} => ViewId=${mapping.viewId} => unbinding');
mapping.tileId = null;
await Chime.unbindVideoView(tileId);
}
}