Example voice-activated timer app
This example app highlights performance issues with the speech_to_text package when using merged platform and UI threads (Flutter 3.27 and above).
This example is for iOS only (Android wasn't tested but might have the same issues).
Running the app
Run the app on a real iOS device in profile or release mode.
After accepting the microphone and speech recognition permissions, use the voice-activated commands:
- Say "start" to start the timer
- Say "stop" to stop the timer
- Say "reset" to reset the timer
- Say "time" to speak the current time via TTS
Performance issues
The tests below were performed on an iPhone XR running iOS 17.6.1.
- Calls to
_speech.listentake ~0.5 seconds on average - Calls to
_speech.stoptake ~0.2 seconds on average
On Flutter 3.32.1 and master (3.33.0-1.0.pre.417), both calls cause several dropped frames (this can be observed in the StopwatchDisplay widget which fails to update the display at 60Hz), regardless of whether FLTEnableMergedPlatformUIThread is set to true or false in the Info.plist.
On Flutter 3.24.5, the calls take the same amount of time but do not cause dropped frames (separate threads).
iOS Setup
The app uses microphone and speech recognition, so it is configured as follows.
ios/Runner/Info.plist:
<key>NSMicrophoneUsageDescription</key>
<string>This app needs microphone access to recognize voice commands like "start" and "stop" for hands-free timer control during exercise.</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>This app needs speech recognition access to recognize voice commands like "start" and "stop" for hands-free timer control during exercise.</string>
<key>FLTEnableMergedPlatformUIThread</key>
<false/> ios/Podfile:
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
# https://github.com/Baseflow/flutter-permission-handler/issues/1391#issuecomment-2392231125
target.build_configurations.each do |config|
# You can remove unused permissions here
# for more information: https://github.com/Baseflow/flutter-permission-handler/blob/main/permission_handler_apple/ios/Classes/PermissionHandlerEnums.h
# e.g. when you don't need camera permission, just add 'PERMISSION_CAMERA=0'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
## dart: PermissionGroup.microphone
'PERMISSION_MICROPHONE=1',
## dart: PermissionGroup.speech
'PERMISSION_SPEECH_RECOGNIZER=1',
]
end
end
end