flutter 音频录制插件(flutter_sound)

flutter_sound

官方介绍:这个插件为android和ios平台提供了简单的记录器和播放器功能。这只支持每个平台的默认文件扩展名。这个插件处理来自远程url的文件。这个插件可以处理本地播放流(通过桥接来同步准确的时间)。

插件网址:https://pub.dev/packages/flutter_sound

安装

pubspec.yaml添加依赖

dependencies:
  ...
  
  flutter_sound: ^1.1.5

接着在控制台运行flutter packages get获取依赖,最重要一点需要在AndroidManifest.xml文件中添加,权限请求



代码(copy 官方)

期间出现的插件,请自行安装,方法同上

import 'package:flutter/material.dart';
import 'package:intl/intl.dart' show DateFormat;
import 'package:intl/date_symbol_data_local.dart';

import 'dart:io';
import 'dart:async';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:flutter_sound/android_encoder.dart';
import 'dart:convert';


class RecorderPage extends StatelessWidget {
  const RecorderPage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("音频录制页面"),
      ),
      body: RecorderContent(),
    );
  }
}

class RecorderContent extends StatefulWidget {
  RecorderContent({Key key}) : super(key: key);

  _RecorderContentState createState() => _RecorderContentState();
}

class _RecorderContentState extends State {
  bool _isRecording = false;
  bool _isPlaying = false;
  StreamSubscription _recorderSubscription;
  StreamSubscription _dbPeakSubscription;
  StreamSubscription _playerSubscription;
  FlutterSound flutterSound;

  String _recorderTxt = '00:00:00';
  String _playerTxt = '00:00:00';
  double _dbLevel;

  double slider_current_position = 0.0;
  double max_duration = 1.0;

  @override
  void initState() {
    super.initState();
    flutterSound = new FlutterSound();
    flutterSound.setSubscriptionDuration(0.01);
    flutterSound.setDbPeakLevelUpdate(0.8);
    flutterSound.setDbLevelEnabled(true);
    initializeDateFormatting();
  }

  void startRecorder() async {
    try {
     
      String path = await flutterSound.startRecorder(null);
      print("数据$path");

      _recorderSubscription = flutterSound.onRecorderStateChanged.listen((e) {
        DateTime date = new DateTime.fromMillisecondsSinceEpoch(
            e.currentPosition.toInt(),
            isUtc: true);
        // print("时长$date");
        String txt = DateFormat('mm:ss:SS', 'en_GB').format(date);

        this.setState(() {
          this._recorderTxt = txt.substring(0, 8);
        });
      });
      // _dbPeakSubscription =
      //     flutterSound.onRecorderDbPeakChanged.listen((value) {
      //   print("got update -> $value");
      //   setState(() {
      //     this._dbLevel = value;
      //   });
      // });

      this.setState(() {
        this._isRecording = true;
      });
    } catch (err) {
      print('startRecorder error: $err');
    }
  }

  void stopRecorder() async {
    try {
      String result = await flutterSound.stopRecorder();
      print('停止录音返回结果: $result');

      if (_recorderSubscription != null) {
        _recorderSubscription.cancel();
        _recorderSubscription = null;
      }
      if (_dbPeakSubscription != null) {
        _dbPeakSubscription.cancel();
        _dbPeakSubscription = null;
      }

      this.setState(() {
        this._isRecording = false;
      });
    } catch (err) {
      print('stopRecorder error: $err');
    }
  }

  void startPlayer() async {
    String path = await flutterSound.startPlayer(null);
    File file= await new File(path);
    List contents = await file.readAsBytesSync();

    // return print("file文件:$contents");
    await flutterSound.setVolume(1.0);
    print('startPlayer: $path');

    try {
      _playerSubscription = flutterSound.onPlayerStateChanged.listen((e) {
        if (e != null) {
          slider_current_position = e.currentPosition;
          max_duration = e.duration;

          DateTime date = new DateTime.fromMillisecondsSinceEpoch(
              e.currentPosition.toInt(),
              isUtc: true);
          String txt = DateFormat('mm:ss:SS', 'en_GB').format(date);
          this.setState(() {
            this._isPlaying = true;
            this._playerTxt = txt.substring(0, 8);
          });
        }
      });
    } catch (err) {
      print('error: $err');
    }
  }

  void stopPlayer() async {
    try {
      String result = await flutterSound.stopPlayer();
      print('stopPlayer: $result');
      if (_playerSubscription != null) {
        _playerSubscription.cancel();
        _playerSubscription = null;
      }

      this.setState(() {
        this._isPlaying = false;
      });
    } catch (err) {
      print('error: $err');
    }
  }

  void pausePlayer() async {
    String result = await flutterSound.pausePlayer();
    print('pausePlayer: $result');
  }

  void resumePlayer() async {
    String result = await flutterSound.resumePlayer();
    print('resumePlayer: $result');
  }

  void seekToPlayer(int milliSecs) async {
    String result = await flutterSound.seekToPlayer(milliSecs);
    print('seekToPlayer: $result');
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        child: ListView(
      children: [
        Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              margin: EdgeInsets.only(top: 24.0, bottom: 16.0),
              child: Text(
                this._recorderTxt,
                style: TextStyle(
                  fontSize: 48.0,
                  color: Colors.black,
                ),
              ),
            ),
            _isRecording
                ? LinearProgressIndicator(
                    value: 100.0 / 160.0 * (this._dbLevel ?? 1) / 100,
                    valueColor: AlwaysStoppedAnimation(Colors.green),
                    backgroundColor: Colors.red,
                  )
                : Container()
          ],
        ),
        Row(
          children: [
            Container(
              width: 56.0,
              height: 56.0,
              child: ClipOval(
                child: FlatButton(
                    onPressed: () {
                      if (!this._isRecording) {
                        return this.startRecorder();
                      }
                      this.stopRecorder();
                    },
                    padding: EdgeInsets.all(8.0),
                    child: this._isRecording ? Text("停止") : Text("开始录音")),
              ),
            ),
          ],
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
        ),
        Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              margin: EdgeInsets.only(top: 60.0, bottom: 16.0),
              child: Text(
                this._playerTxt,
                style: TextStyle(
                  fontSize: 48.0,
                  color: Colors.black,
                ),
              ),
            ),
          ],
        ),
        Row(
          children: [
            Container(
              width: 56.0,
              height: 56.0,
              child: ClipOval(
                child: FlatButton(
                  onPressed: () {
                    startPlayer();
                  },
                  padding: EdgeInsets.all(8.0),
                  child: Text("开始"),
                ),
              ),
            ),
            Container(
              width: 56.0,
              height: 56.0,
              child: ClipOval(
                child: FlatButton(
                  onPressed: () {
                    pausePlayer();
                  },
                  padding: EdgeInsets.all(8.0),
                  child: Text("暂停"),
                ),
              ),
            ),
            Container(
              width: 56.0,
              height: 56.0,
              child: ClipOval(
                child: FlatButton(
                  onPressed: () {
                    stopPlayer();
                  },
                  padding: EdgeInsets.all(8.0),
                  child: Text("停止"),
                ),
              ),
            ),
          ],
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
        ),
        Container(
            height: 56.0,
            child: Slider(
                value: slider_current_position,
                min: 0.0,
                max: max_duration,
                onChanged: (double value) async {
                  await flutterSound.seekToPlayer(value.toInt());
                },
                divisions: max_duration.toInt()))
      ],
    ));
  }
}

音频录制出现音质很差的问题

在出现这个问题的时候,经过一系列的排查,这行代码出现的问题

void startRecorder() async {
    try {
     
      String path = await flutterSound.startRecorder(null);
      print("数据$path");

      _recorderSubscription = flutterSound.onRecorderStateChanged.listen((e) {
        DateTime date = new DateTime.fromMillisecondsSinceEpoch(
            e.currentPosition.toInt(),
            isUtc: true);
        // print("时长$date");
        String txt = DateFormat('mm:ss:SS', 'en_GB').format(date);

        this.setState(() {
          this._recorderTxt = txt.substring(0, 8);
        });
      });
      // _dbPeakSubscription =
      //     flutterSound.onRecorderDbPeakChanged.listen((value) {
      //   print("got update -> $value");
      //   setState(() {
      //     this._dbLevel = value;
      //   });
      // });

      this.setState(() {
        this._isRecording = true;
      });
    } catch (err) {
      print('startRecorder error: $err');
    }
  }

通过查看它的的参数源码

Future startRecorder(String uri,
      {int sampleRate = 44100, int numChannels = 2, int bitRate,
        AndroidEncoder androidEncoder = AndroidEncoder.AAC,
        IosQuality iosQuality = IosQuality.LOW
      }) async {
    try {
    ...

有一个bitRate的参数,这个要设置,会改变这个录制的音质
我的这个加的320000

String path = await flutterSound.startRecorder(null,bitRate:320000);

你可能感兴趣的:(flutter)