A Flutter plugin for the Daily mobile SDK.
This plugin is currently under development. There may be some missing features compared to the mobile SDKs. PRs are welcome.
Note that the Daily mobile SDKs are still in Beta for both Android and iOS. Thus, it's not recommended for using in production apps.
Prefer running in a real device instead of emulators.
This plugin was developed within Teamflow, which kindly granted permission to make it open-source.
iOS >= 13.0
Android: Not supported yet.
To run the example app:
- Install Flutter
- Run
flutter pub get
to update the dependencies - Run
make
in the root of the repository to generate the Pigeon files cd example
and thenflutter run
to
If you are running the iOS app from a Mac with Apple Silicon:
- Enter the example/ios folder:
cd example/ios
- Run
make
to run the pod install and update the native dependencies.
To get an URL for testing your app, create your account at daily.co, then create a room in the dashboard. For testing purpose, you can create a public room which don't require a token, however, you should avoid it in production.
// Import the package
import 'package:daily_client/daily_client.dart' as daily;
// Instantiate the DailyClient
final _dailyClient = daily.DailyClient();
// Join the call
try {
final result = await _dailyClient.join(
url: url,
token: token, // It can be empty
enableCamera: true,
enableMicrophone: true,
);
print(result.localParticipant);
print(result.remoteParticipants);
} on daily.DailyClientException catch (e) {
print(e.message);
}
await _dailyClient.leave();
This plugin uses streams to inform about changes in the call. You can listen to them before the join()
method.
import 'package:daily_client/daily_client.dart' as daily;
StreamSubscription? _eventsSubscription;
StreamSubscription? _callStateSubscription;
// Start listeners before `join()`
_startListeners();
void _startListeners() {
_eventsSubscription = _dailyClient.events.listen((event) {
if (event is daily.ParticipantJoinedEvent) {
_onParticipantJoined(event.remoteParticipant);
}
if (event is daily.ParticipantLeftEvent) {
_onParticipantLeft(event.remoteParticipant);
}
if (event is daily.ParticipantUpdatedEvent) {
_onParticipantUpdated(event.remoteParticipant);
}
if (event is daily.LocalParticipantUpdatedEvent) {
_onLocalParticipantUpdated(event.localParticipant);
}
if (event is daily.ActiveSpeakerChangedEvent) {
_onActiveSpeakerChanged(event.remoteParticipant);
}
});
_callStateSubscription = _dailyClient.callState.listen(_onCallStateChanged);
}
void dispose(){
_eventsSubscription?.cancel();
_callStateSubscription?.cancel();
}
await _dailyClient.setMicrophoneEnabled(true);
await _dailyClient.setCameraEnabled(true);
// You should receive a [LocalParticipantUpdatedEvent] after each change. Use it to update the local participant state.
To show the participants video, use the VideoRenderer
widget with the Participant
as argument.
import 'package:daily_client/daily_client.dart' as daily;
@override
Widget build(BuildContext context) {
return daily.VideoRenderer(
participant: participant, //local or remote
isScreenShare: false, // false for camera, true for screen share video
videoScaleMode: daily.VideoScaleMode.fill,
);
}
The participants subscriptions are handled by Daily using profiles. They allow us to define manually whether we should subscribe to video and/or audio. For example: you can subscribe to audio and video for all the visible participants, and keep the other participants who are not in the screen with audio only, to save some resources.
By the default, the base
profile subscribe to both audio and video, so you shouldn't worry with that in your first implementation.
await _dailyClient.updateSubscriptionProfiles(const [
daily.SubscriptionProfileSettingsUpdate(
name: 'visible',
subscribeCamera: true,
subscribeMicrophone: true,
),
daily.SubscriptionProfileSettingsUpdate(
name: 'invisible',
subscribeCamera: false,
subscribeMicrophone: true,
),
// Here we are overriding the base profile to NOT subscribe by default
daily.SubscriptionProfileSettingsUpdate(
name: 'base',
subscribeCamera: false,
subscribeMicrophone: false,
),
]);
void _onParticipantJoined(daily.RemoteParticipant participant) {
// This is setting the `visible` profile as default. It's not necessary
// unless you need to handle custom subscriptions.
_dailyClient.updateSubscriptions([
daily.UpdateSubscriptionOptions(
participantId: participant.id,
profileName: SubscriptionProfiles.visible.name,
)
]);
}
Add these values to the info.plist
:
<key>NSMicrophoneUsageDescription</key>
<string>Daily example uses the microphone on a call</string>
<key>NSCameraUsageDescription</key>
<string>Daily example uses the camera on a call</string>
In progress