Flutter音频录制插件flutter_audio_recorder的使用

Flutter音频录制插件flutter_audio_recorder的使用

flutter_audio_recorder简介

pub version Awesome Flutter

English | 简体中文

flutter_audio_recorder 是一个支持音频录制、暂停、恢复和停止的 Flutter 插件,并且提供了访问音频电平表属性的功能(如 average powerpeak power)。

支持平台

  • Android
  • iOS

代码示例

安装

pubspec.yaml 文件中添加以下依赖:

dependencies:
  flutter_audio_recorder: ^0.5.0

然后运行 flutter pub get

iOS权限配置

  1. Info.plist 文件中添加麦克风使用描述:
<key>NSMicrophoneUsageDescription</key>
<string>Can We Use Your Microphone Please</string>
  1. 使用 hasPermission API 请求用户授权。

Android权限配置

  1. ./android/app/src/main/AndroidManifest.xml 中添加以下权限:
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  1. 使用 hasPermission API 请求用户授权。

配置

iOS

  • 部署目标版本需为 8.0 或更高。

Android

  • 如果使用 AndroidX,请使用最新版本(0.5.x)。
  • 如果使用旧版 Android,请使用旧版本(0.4.9)。

使用方法

推荐的 API 使用顺序为:hasPermission => init => start -> (pause <-> resume) * n -> stop。每次开始新的录音前都需要调用 init

检查权限

首先检查权限,如果未设置则请求权限,否则返回录制权限的状态:

bool hasPermission = await FlutterAudioRecorder.hasPermissions;

初始化

在开始录音之前,初始化并检查文件是否存在:

var recorder = FlutterAudioRecorder("file_path.mp4"); // 支持 .wav .aac .m4a
await recorder.initialized;

或者指定音频格式:

var recorder = FlutterAudioRecorder("file_path", audioFormat: AudioFormat.AAC); // 或 AudioFormat.WAV
await recorder.initialized;

设置采样率

var recorder = FlutterAudioRecorder("file_path", audioFormat: AudioFormat.AAC, sampleRate: 22000); // 默认采样率为 16000
await recorder.initialized;

音频格式与扩展名映射

音频格式 扩展名列表
AAC .m4a .aac .mp4
WAV .wav

开始录音

await recorder.start();
var recording = await recorder.current(channel: 0);

获取录音详情

var current = await recording.current(channel: 0);
// print(current.status);

可以使用定时器每 50 毫秒访问一次详细信息(录音结束后取消定时器):

new Timer.periodic(tick, (Timer t) async {
        var current = await recording.current(channel: 0);
        // print(current.status);
        setState(() {
        });
      });

录音对象属性

名称 类型
path String
extension String
duration Duration
audioFormat AudioFormat
metering AudioMetering
status RecordingStatus

metering 属性

名称 类型
peakPower double
averagePower double
isMeteringEnabled bool

status 属性

状态
Unset
Initialized
Recording
Paused
Stopped

暂停录音

await recorder.pause();

恢复录音

await recorder.resume();

停止录音

停止后,再次调用 init 来创建新的录音:

var result = await recorder.stop();
File file = widget.localFileSystem.file(result.path);

示例代码

以下是一个完整的示例代码,展示了如何使用 flutter_audio_recorder 进行音频录制、播放等操作:

import 'dart:async';
import 'dart:io' as io;

import 'package:audioplayers/audioplayers.dart';
import 'package:file/file.dart';
import 'package:file/local.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_audio_recorder/flutter_audio_recorder.dart';
import 'package:path_provider/path_provider.dart';

void main() {
  SystemChrome.setEnabledSystemUIOverlays([]);
  runApp(new MyApp());
}

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Scaffold(
        body: SafeArea(
          child: new RecorderExample(),
        ),
      ),
    );
  }
}

class RecorderExample extends StatefulWidget {
  final LocalFileSystem localFileSystem;

  RecorderExample({localFileSystem})
      : this.localFileSystem = localFileSystem ?? LocalFileSystem();

  [@override](/user/override)
  State<StatefulWidget> createState() => new RecorderExampleState();
}

class RecorderExampleState extends State<RecorderExample> {
  FlutterAudioRecorder _recorder;
  Recording _current;
  RecordingStatus _currentStatus = RecordingStatus.Unset;

  [@override](/user/override)
  void initState() {
    super.initState();
    _init();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return new Center(
      child: new Padding(
        padding: new EdgeInsets.all(8.0),
        child: new Column(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              new Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: new FlatButton(
                      onPressed: () {
                        switch (_currentStatus) {
                          case RecordingStatus.Initialized:
                            {
                              _start();
                              break;
                            }
                          case RecordingStatus.Recording:
                            {
                              _pause();
                              break;
                            }
                          case RecordingStatus.Paused:
                            {
                              _resume();
                              break;
                            }
                          case RecordingStatus.Stopped:
                            {
                              _init();
                              break;
                            }
                          default:
                            break;
                        }
                      },
                      child: _buildText(_currentStatus),
                      color: Colors.lightBlue,
                    ),
                  ),
                  new FlatButton(
                    onPressed: _currentStatus != RecordingStatus.Unset ? _stop : null,
                    child: new Text("Stop", style: TextStyle(color: Colors.white)),
                    color: Colors.blueAccent.withOpacity(0.5),
                  ),
                  SizedBox(
                    width: 8,
                  ),
                  new FlatButton(
                    onPressed: onPlayAudio,
                    child: new Text("Play", style: TextStyle(color: Colors.white)),
                    color: Colors.blueAccent.withOpacity(0.5),
                  ),
                ],
              ),
              new Text("Status : $_currentStatus"),
              new Text('Avg Power: ${_current?.metering?.averagePower}'),
              new Text('Peak Power: ${_current?.metering?.peakPower}'),
              new Text("File path of the record: ${_current?.path}"),
              new Text("Format: ${_current?.audioFormat}"),
              new Text(
                  "isMeteringEnabled: ${_current?.metering?.isMeteringEnabled}"),
              new Text("Extension : ${_current?.extension}"),
              new Text(
                  "Audio recording duration : ${_current?.duration.toString()}")
            ]),
      ),
    );
  }

  _init() async {
    try {
      if (await FlutterAudioRecorder.hasPermissions) {
        String customPath = '/flutter_audio_recorder_';
        io.Directory appDocDirectory;
        if (io.Platform.isIOS) {
          appDocDirectory = await getApplicationDocumentsDirectory();
        } else {
          appDocDirectory = await getExternalStorageDirectory();
        }

        customPath = appDocDirectory.path +
            customPath +
            DateTime.now().millisecondsSinceEpoch.toString();

        _recorder =
            FlutterAudioRecorder(customPath, audioFormat: AudioFormat.WAV);

        await _recorder.initialized;
        var current = await _recorder.current(channel: 0);
        setState(() {
          _current = current;
          _currentStatus = current.status;
        });
      } else {
        Scaffold.of(context).showSnackBar(
            new SnackBar(content: new Text("You must accept permissions")));
      }
    } catch (e) {
      print(e);
    }
  }

  _start() async {
    try {
      await _recorder.start();
      var recording = await _recorder.current(channel: 0);
      setState(() {
        _current = recording;
      });

      const tick = const Duration(milliseconds: 50);
      new Timer.periodic(tick, (Timer t) async {
        if (_currentStatus == RecordingStatus.Stopped) {
          t.cancel();
        }

        var current = await _recorder.current(channel: 0);
        setState(() {
          _current = current;
          _currentStatus = _current.status;
        });
      });
    } catch (e) {
      print(e);
    }
  }

  _resume() async {
    await _recorder.resume();
    setState(() {});
  }

  _pause() async {
    await _recorder.pause();
    setState(() {});
  }

  _stop() async {
    var result = await _recorder.stop();
    print("Stop recording: ${result.path}");
    print("Stop recording: ${result.duration}");
    File file = widget.localFileSystem.file(result.path);
    print("File length: ${await file.length()}");
    setState(() {
      _current = result;
      _currentStatus = _current.status;
    });
  }

  Widget _buildText(RecordingStatus status) {
    var text = "";
    switch (_currentStatus) {
      case RecordingStatus.Initialized:
        {
          text = 'Start';
          break;
        }
      case RecordingStatus.Recording:
        {
          text = 'Pause';
          break;
        }
      case RecordingStatus.Paused:
        {
          text = 'Resume';
          break;
        }
      case RecordingStatus.Stopped:
        {
          text = 'Init';
          break;
        }
      default:
        break;
    }
    return Text(text, style: TextStyle(color: Colors.white));
  }

  void onPlayAudio() async {
    AudioPlayer audioPlayer = AudioPlayer();
    await audioPlayer.play(_current.path, isLocal: true);
  }
}

更多关于Flutter音频录制插件flutter_audio_recorder的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter音频录制插件flutter_audio_recorder的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


flutter_audio_recorder 是一个用于在 Flutter 应用中录制音频的插件。它提供了简单的 API 来开始、暂停、继续和停止音频录制,并且可以将录制的音频保存为文件。以下是如何在 Flutter 项目中使用 flutter_audio_recorder 插件的步骤。

1. 添加依赖

首先,在 pubspec.yaml 文件中添加 flutter_audio_recorder 依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_audio_recorder: ^0.7.0

然后运行 flutter pub get 来获取依赖包。

2. 配置权限

为了录制音频,你需要在 AndroidiOS 上配置相应的权限。

Android

AndroidManifest.xml 文件中添加以下权限:

<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

iOS

Info.plist 文件中添加以下权限:

<key>NSMicrophoneUsageDescription</key>
<string>We need access to your microphone to record audio.</string>

3. 初始化录音器

在你的 Dart 代码中,首先导入 flutter_audio_recorder 包,然后初始化录音器。

import 'package:flutter_audio_recorder/flutter_audio_recorder.dart';
import 'package:permission_handler/permission_handler.dart';

class AudioRecorder {
  FlutterAudioRecorder? _recorder;

  Future<void> init() async {
    // 检查并请求录音权限
    var status = await Permission.microphone.status;
    if (!status.isGranted) {
      await Permission.microphone.request();
    }

    // 初始化录音器
    _recorder = FlutterAudioRecorder('path_to_save_audio.mp4');
    await _recorder?.initialized;
  }
}

4. 开始录音

你可以使用 start() 方法来开始录音。

Future<void> startRecording() async {
  await _recorder?.start();
}

5. 暂停录音

你可以使用 pause() 方法来暂停录音。

Future<void> pauseRecording() async {
  await _recorder?.pause();
}

6. 继续录音

你可以使用 resume() 方法来继续录音。

Future<void> resumeRecording() async {
  await _recorder?.resume();
}

7. 停止录音并保存文件

你可以使用 stop() 方法来停止录音并保存文件。

Future<String?> stopRecording() async {
  var recording = await _recorder?.stop();
  return recording?.path; // 返回保存的音频文件路径
}

8. 获取录音状态

你可以使用 current() 方法来获取当前的录音状态,例如录音的持续时间、音量等。

Future<Recording> getRecordingStatus() async {
  return await _recorder?.current();
}

9. 完整示例

以下是一个完整的示例,展示了如何使用 flutter_audio_recorder 插件来录制音频:

import 'package:flutter/material.dart';
import 'package:flutter_audio_recorder/flutter_audio_recorder.dart';
import 'package:permission_handler/permission_handler.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: AudioRecorderScreen(),
    );
  }
}

class AudioRecorderScreen extends StatefulWidget {
  [@override](/user/override)
  _AudioRecorderScreenState createState() => _AudioRecorderScreenState();
}

class _AudioRecorderScreenState extends State<AudioRecorderScreen> {
  FlutterAudioRecorder? _recorder;
  bool _isRecording = false;
  String? _audioPath;

  [@override](/user/override)
  void initState() {
    super.initState();
    _initRecorder();
  }

  Future<void> _initRecorder() async {
    var status = await Permission.microphone.status;
    if (!status.isGranted) {
      await Permission.microphone.request();
    }

    _recorder = FlutterAudioRecorder('audio_recording.mp4');
    await _recorder?.initialized;
  }

  Future<void> _startRecording() async {
    await _recorder?.start();
    setState(() {
      _isRecording = true;
    });
  }

  Future<void> _pauseRecording() async {
    await _recorder?.pause();
  }

  Future<void> _resumeRecording() async {
    await _recorder?.resume();
  }

  Future<void> _stopRecording() async {
    var recording = await _recorder?.stop();
    setState(() {
      _isRecording = false;
      _audioPath = recording?.path;
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Audio Recorder'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            _isRecording
                ? Text('Recording...')
                : Text('Press the button to start recording'),
            SizedBox(height: 20),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                ElevatedButton(
                  onPressed: _isRecording ? _pauseRecording : _startRecording,
                  child: Text(_isRecording ? 'Pause' : 'Start'),
                ),
                SizedBox(width: 20),
                ElevatedButton(
                  onPressed: _isRecording ? _stopRecording : null,
                  child: Text('Stop'),
                ),
              ],
            ),
            SizedBox(height: 20),
            _audioPath != null
                ? Text('Audio saved at: $_audioPath')
                : Container(),
          ],
        ),
      ),
    );
  }
}
回到顶部