zego_zim_audio 1.0.0+3 copy "zego_zim_audio: ^1.0.0+3" to clipboard
zego_zim_audio: ^1.0.0+3 copied to clipboard

ZEGO ZIM Audio SDK is a flutter plugin wrapper based on ZIM native Android / iOS SDK.

example/lib/main.dart

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:zego_zim_audio/zego_zim_audio.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io' show Directory, File;

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _version = "";
  List<String> _recordings = [];
  Map<String,int> recordDurationMap = {};
  bool _isRecording = false;
  int _currentRecordDuration = 0;
  String _currentPlaying = '';
  int _currentPlayingDuration = 0;
  String _waitingPlaying = '';
  bool _isPlaying = false;
  bool _isSpeaker = true;
  bool isCancelRecord = false;
  ScrollController _scrollController = ScrollController();
  final GlobalKey<_MyAppState> key = GlobalKey();


  Future<void> clearApplicationDocumentsDirectory() async {
    Directory appDocDir = await getApplicationDocumentsDirectory();
    if (appDocDir.existsSync()) {
      await for (var entity in appDocDir.list()) {
        if (entity is File) {
          await entity.delete();
        }
      }
    }
  }
  @override
  void initState(){
    super.initState();
    clearApplicationDocumentsDirectory();
    ZIMAudio.getVersion().then((value) => {
      _version = value,
      setState((){})
    });
    ZIMAudio.getInstance().init("");
    ZIMAudioEventHandler.onError = (ZIMAudioError errorInfo){
      ErrorDiaLog.showFailedDialog(key.currentContext!,
          errorInfo.code.toString(), 'onError.message:${errorInfo.message}');
    };
    ZIMAudioEventHandler.onRecorderCompleted = (int totalDuration) async{
      setState(() {
        _isRecording = false;
        recordDurationMap['${_recordings.length + 1}'] = totalDuration;
        _recordings.add('${_recordings.length + 1}');
      });
      Future.delayed(Duration(milliseconds: 500), () {
        _scrollToTop();
      });
    };
    ZIMAudioEventHandler.onRecorderFailed = (int errorCode)async{
      setState((){
        _isRecording = false;
        ErrorDiaLog.showFailedDialog(key.currentContext!, errorCode.toString(), 'onRecorderFailed');
      });
    };
    ZIMAudioEventHandler.onRecorderStarted =()async{
      _isRecording = true;
      _currentRecordDuration = 0;
      setState(() {});
    };

    ZIMAudioEventHandler.onRecorderCancelled = () {
      _isRecording = false;
      setState(() {});
    };

    ZIMAudioEventHandler.onRecorderProgress = (int currentDuration) {
      if (kDebugMode) {
        print('[Flutter] onRecorderProgress:$currentDuration');
      }
      _currentRecordDuration = currentDuration;
      setState(() {

      });
    };

    ZIMAudioEventHandler.onPlayerStarted = (int duration) {
      setState(() {
        _isPlaying = true;
        _currentPlaying = _waitingPlaying;
        _currentPlayingDuration = duration;
      });
    };

    ZIMAudioEventHandler.onPlayerEnded = () {
      setState(() {
        _currentPlaying = '';
        _isPlaying = false;
      });
    };
    ZIMAudioEventHandler.onPlayerStopped = ()  {
      setState(() {
        _currentPlaying = '';
        _isPlaying = false;
      });
    };

    ZIMAudioEventHandler.onPlayerInterrupted = ()  {
      setState(() {
        _currentPlaying = '';
        _isPlaying = false;
      });
    };
    ZIMAudioEventHandler.onPlayerProgress = (int currentDuration) {
      setState(() {
        _currentPlayingDuration = currentDuration;
      });

    };
    ZIMAudioEventHandler.onPlayerFailed = (int errorCode) {
      setState(() {
        _isPlaying = false;
        _currentPlaying = '';
        ErrorDiaLog.showFailedDialog(key.currentContext!, errorCode.toString(), 'onPlayerFailed');
      });
    };
  }

  void _startRecording() async {
    try {
      Directory? dic = await getApplicationDocumentsDirectory();
      String path = '${dic.path}/${_recordings.length + 1}.mp3';
      await ZIMAudio.getInstance().startRecord(ZIMAudioRecordConfig(path,maxDuration: 120000));
    } catch (e) {
      print("Error starting recording: $e");
    }
  }

  void _CancelRecording() async {
    try {
      await ZIMAudio.getInstance().cancelRecord();
    }catch (e) {
      print("Error cancel recording: $e");
    }
  }

  void _CompleteRecording() async {
    try {
      await ZIMAudio.getInstance().completeRecord();
    } catch (e) {
      print("Error complete recording: $e");
    }
  }

  void _startPlaying(String recording) async {
    if(_isRecording){
      return;
    }
    try {
      Directory? dic = await getApplicationDocumentsDirectory();

      String path = '${dic.path}/$recording.mp3';
      await ZIMAudio.getInstance().startPlay(ZIMAudioPlayConfig(path,routeType: _isSpeaker?ZIMAudioRouteType.speaker:ZIMAudioRouteType.receiver));
      _waitingPlaying = recording;
    } catch (e) {
      print("Error starting playback: $e");
    }
  }

  Future<void> _stopPlaying() async {
    try {
      await ZIMAudio.getInstance().stopPlay();
    } catch (e) {
      print("Error stopping playback: $e");
    }
  }

  void _scrollToTop() {
    _scrollController.animateTo(
      _scrollController.position.maxScrollExtent,
      duration: Duration(milliseconds: 500),
      curve: Curves.easeInOut,
    );
  }
  String formatMillisecondsTime(int milliseconds) {
    int seconds = (milliseconds / 1000).floor();
    int remainingMilliseconds = milliseconds % 1000;
    int minutes = (seconds / 60).floor();
    int remainingSeconds = seconds % 60;

    String minutesStr = minutes.toString();
    String secondsStr = remainingSeconds.toString().padLeft(2, '0');
    String millisecondsStr = (remainingMilliseconds ~/ 10).toString().padLeft(2, '0');

    return '$minutesStr:$secondsStr.$millisecondsStr';
  }

  String formatSecondTime(int milliseconds) {
    int seconds = (milliseconds / 1000).floor();
    int remainingSeconds = seconds % 60;
    int minutes = (seconds / 60).floor();

    String minutesStr = minutes.toString().padLeft(1, '0');
    String secondsStr = remainingSeconds.toString().padLeft(2, '0');

    return '$minutesStr:$secondsStr';
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('ZIM Audio:$_version'),
        ),
        key: key,
        body: Column(
          children: [
            Flexible(
              flex: 2,
              child: ListView(
                controller: _scrollController,
                reverse: false,
                children: _recordings
                    .map(
                      (recording) => ListTile(
                    title: Text('Recording $recording'),
                    subtitle: Text('${formatSecondTime(recordDurationMap[recording]!)}'),
                    trailing: ElevatedButton(
                      onPressed: () {
                        if (recording == _currentPlaying) {
                          _stopPlaying();
                        } else {
                          _startPlaying(recording);
                        }
                        HapticFeedback.mediumImpact();
                      },

                      style: ButtonStyle(
                        backgroundColor: recording == _currentPlaying
                            ? MaterialStateProperty.all(Colors.red)
                            : null,
                      ),
                      child: Text(
                        recording == _currentPlaying && _isPlaying
                            ? '${formatSecondTime(recordDurationMap[recording]! - _currentPlayingDuration)}'
                            : 'Play',
                      ),
                    ),
                  ),
                )
                    .toList(),
              ),
            ),
            SizedBox(height: 20),
            IconButton(
              onPressed: () {
                _isSpeaker = !_isSpeaker;
                HapticFeedback.mediumImpact();
                if(_isSpeaker == true){
                  ZIMAudio.getInstance().setAudioRouteType(ZIMAudioRouteType.speaker);
                }else{
                  ZIMAudio.getInstance().setAudioRouteType(ZIMAudioRouteType.receiver);
                }
                setState(() {

                });
              },
              icon: Icon(
                _isSpeaker ? Icons.volume_up : Icons.hearing,
                color: Colors.grey,
              ),
              iconSize: 50,
              splashRadius: 30,
              padding: EdgeInsets.all(16),
              color: Colors.blue,
            ),
            Align(
              alignment: Alignment.bottomCenter,
              child: Padding(
                padding: const EdgeInsets.only(bottom: 20.0),
                child: GestureDetector(
                  onLongPressStart: (details) async{
                     _startRecording();
                     HapticFeedback.mediumImpact();
                  },
                  onLongPressEnd: (_) {
                    if(isCancelRecord){
                      _CancelRecording();
                    }else{
                      HapticFeedback.mediumImpact();
                      _CompleteRecording();
                    }
                    isCancelRecord = false;
                  },
                  onLongPressMoveUpdate: (LongPressMoveUpdateDetails details) {
                    if (details.localPosition.dy < -50) {
                      isCancelRecord = true;
                    }
                  },
                  child: Container(
                    padding: EdgeInsets.all(20),
                    decoration: BoxDecoration(
                      color: _isRecording ? Colors.red : Colors.blue,
                      borderRadius: BorderRadius.circular(10),
                    ),
                    child: Text(
                      _isRecording ? 'Swipe up to cancel ${formatSecondTime(_currentRecordDuration)}' : 'Press and hold to record',
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 18,
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class ErrorDiaLog {
  static Future<bool?> showFailedDialog(BuildContext context,
      String code, String message) {
    return showDialog<bool>(
        context: context,
        builder: (context) {
          return AlertDialog(
            title: const Text(
              "Error",
            ),
            content: Text('code:' + code + '\n\n' + 'message:' + message),
            actions: <Widget>[
              TextButton(
                  onPressed: (() {
                    Navigator.of(context).pop();
                  }),
                  child: const Text('OK'))
            ],
          );
        });
  }
}
3
likes
150
pub points
63%
popularity

Publisher

verified publisherzego.im

ZEGO ZIM Audio SDK is a flutter plugin wrapper based on ZIM native Android / iOS SDK.

Homepage

Documentation

API reference

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on zego_zim_audio