Implementing Voice Recognition in Flutter Apps

Voice recognition has become an integral part of modern mobile applications. Implementing voice recognition in Flutter apps can significantly enhance user experience by allowing users to interact with the app using their voice. This capability opens up a range of possibilities, from voice commands to dictation and accessibility features.

Why Implement Voice Recognition in Flutter?

  • Enhanced User Experience: Enables hands-free interaction.
  • Accessibility: Makes apps more accessible to users with disabilities.
  • Efficiency: Speeds up data entry and navigation.

Tools and Packages for Voice Recognition in Flutter

Flutter provides several packages that make implementing voice recognition easier:

  • speech_to_text: A popular package for speech recognition.
  • flutter_sound: Used for recording audio, which can be coupled with speech-to-text services.
  • Native platform APIs (for advanced control).

Using the speech_to_text Package

The speech_to_text package is a straightforward solution for adding voice recognition to Flutter apps. It supports multiple languages and provides a simple API.

Step 1: Add the Dependency

Add the speech_to_text package to your pubspec.yaml file:

dependencies:
  flutter:
    sdk: flutter
  speech_to_text: ^6.3.0  # Use the latest version

Run flutter pub get to install the package.

Step 2: Import the Package

Import the speech_to_text package in your Dart file:

import 'package:speech_to_text/speech_to_text.dart' as stt;

Step 3: Initialize Speech-to-Text

Initialize the SpeechToText instance in your Flutter widget. This usually happens in the initState method:

import 'package:flutter/material.dart';
import 'package:speech_to_text/speech_to_text.dart' as stt;

class VoiceRecognitionScreen extends StatefulWidget {
  @override
  _VoiceRecognitionScreenState createState() => _VoiceRecognitionScreenState();
}

class _VoiceRecognitionScreenState extends State {
  stt.SpeechToText _speech;
  bool _isListening = false;
  String _text = 'Press the button and start speaking';

  @override
  void initState() {
    super.initState();
    _speech = stt.SpeechToText();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Voice Recognition'),
      ),
      body: Center(
        child: Text(_text),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _listen,
        child: Icon(_isListening ? Icons.mic_off : Icons.mic),
      ),
    );
  }
}

Step 4: Implement the Listen Function

Implement the _listen function to start and stop listening for speech. This function uses the listen method from the SpeechToText class to capture audio and convert it to text.

Future _listen() async {
  if (!_isListening) {
    bool available = await _speech.initialize(
      onStatus: (status) => print('Status: $status'),
      onError: (errorNotification) => print('Error: $errorNotification'),
    );
    if (available) {
      setState(() => _isListening = true);
      _speech.listen(
        onResult: (result) => setState(() {
          _text = result.recognizedWords;
        }),
      );
    } else {
      print("The user has denied the use of speech recognition.");
    }
  } else {
    setState(() => _isListening = false);
    _speech.stop();
  }
}

Add the _listen function to your _VoiceRecognitionScreenState class:

class _VoiceRecognitionScreenState extends State {
  stt.SpeechToText _speech;
  bool _isListening = false;
  String _text = 'Press the button and start speaking';

  @override
  void initState() {
    super.initState();
    _speech = stt.SpeechToText();
  }

  Future _listen() async {
    if (!_isListening) {
      bool available = await _speech.initialize(
        onStatus: (status) => print('Status: $status'),
        onError: (errorNotification) => print('Error: $errorNotification'),
      );
      if (available) {
        setState(() => _isListening = true);
        _speech.listen(
          onResult: (result) => setState(() {
            _text = result.recognizedWords;
          }),
        );
      } else {
        print("The user has denied the use of speech recognition.");
      }
    } else {
      setState(() => _isListening = false);
      _speech.stop();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Voice Recognition'),
      ),
      body: Center(
        child: Text(_text),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _listen,
        child: Icon(_isListening ? Icons.mic_off : Icons.mic),
      ),
    );
  }
}

Complete Code


import 'package:flutter/material.dart';
import 'package:speech_to_text/speech_to_text.dart' as stt;

class VoiceRecognitionScreen extends StatefulWidget {
  @override
  _VoiceRecognitionScreenState createState() => _VoiceRecognitionScreenState();
}

class _VoiceRecognitionScreenState extends State {
  stt.SpeechToText _speech;
  bool _isListening = false;
  String _text = 'Press the button and start speaking';

  @override
  void initState() {
    super.initState();
    _speech = stt.SpeechToText();
  }

  Future _listen() async {
    if (!_isListening) {
      bool available = await _speech.initialize(
        onStatus: (status) => print('Status: $status'),
        onError: (errorNotification) => print('Error: $errorNotification'),
      );
      if (available) {
        setState(() => _isListening = true);
        _speech.listen(
          onResult: (result) => setState(() {
            _text = result.recognizedWords;
          }),
        );
      } else {
        print("The user has denied the use of speech recognition.");
      }
    } else {
      setState(() => _isListening = false);
      _speech.stop();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Voice Recognition'),
      ),
      body: Center(
        child: Text(_text),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _listen,
        child: Icon(_isListening ? Icons.mic_off : Icons.mic),
      ),
    );
  }
}

Handling Permissions

Before using voice recognition, ensure your app has the necessary permissions. The speech_to_text package usually handles permission requests automatically, but you might need to add specific permission declarations in your AndroidManifest.xml (for Android) and Info.plist (for iOS) files.

For Android, add the following permission in AndroidManifest.xml:


For iOS, add the following description in Info.plist:

NSMicrophoneUsageDescription
This app needs microphone access to use voice recognition.

Customizing Voice Recognition

The speech_to_text package allows for various customizations, such as:

  • Language Selection: Choose the language to recognize.
  • Listening Mode: Configure how the speech recognition listens.
  • Pause Handling: Manage how pauses in speech are handled.

Setting the Language

You can set the language by passing the localeId parameter to the listen method:

_speech.listen(
  onResult: (result) => setState(() {
    _text = result.recognizedWords;
  }),
  localeId: 'en_US', // Example: English (United States)
);

Advanced Usage: Combining with flutter_sound

For more control over audio recording, you can use the flutter_sound package to record audio and then send it to a speech-to-text service (like Google Cloud Speech-to-Text or Amazon Transcribe). This approach is useful for scenarios where you need to process audio files or require advanced audio recording features.

Conclusion

Implementing voice recognition in Flutter apps using the speech_to_text package is relatively straightforward and can greatly improve the user experience. Ensure you handle permissions properly and consider customizing the recognition settings to suit your app’s needs. For more advanced scenarios, combining flutter_sound with a cloud-based speech-to-text service offers greater flexibility and control.