Introducción al complemento:
flutter_sound
Este complemento puede realizar iOS和Android
las funciones de grabación y reproducción de la plataforma. Es decir, puede reproducir archivos de audio locales y archivos URL remotos. Aquí presentaré el uso de este complemento y cómo resolver algunos problemas comunes encontrados.
-
flutter_sound admite múltiples formatos de grabación
-
flutter_sound admite múltiples formatos de reproducción
-
flutter_sound admite tamaño de amplitud de audio
Información del complemento:
Dirección del complemento: github.com/ryanheise/a…
Versión del complemento: 9.2.9
Preparación antes de usar el plugin
Establecer descripción de permiso de micrófono
- iOS: debe agregar permisos al archivo info.plist
<key>NSMicrophoneUsageDescription</key>
<string>描述你使用麦克风用来干嘛</string>
复制代码
注意:还需要在Podfile文件中配置
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
## dart: PermissionGroup.microphone
'PERMISSION_MICROPHONE=1',
]
end
end
end
复制代码
También necesita agregar una libc++.tbd
biblioteca al proyecto iOS, la ruta específica
- Android: requiere configuración
AndroidManifest.xml
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
复制代码
Los siguientes complementos también se utilizan aquí
Complemento de administración de permisos allow_handler
Información del complemento:permission_handler: ^9.2.0
Dirección del complemento: pub.flutter-io.cn/packages/pe…
Complemento de configuración de hardware de audio audio_session
Información del complemento:audio_session: ^0.1.6
Dirección del complemento: github.com/ryanheise/a…
complemento de animación
Información del complemento:lottie: 1.2.1
Dirección del complemento: pub.flutter-io.cn/packages/fl...
Métodos comúnmente utilizados
Métodos comunes de grabación
Inicializar el objeto de grabación
FlutterSoundRecorder recorderModule = FlutterSoundRecorder();
复制代码
activar la grabación
Future<void> init() async {
//开启录音
await recorderModule.openRecorder();
//设置订阅计时器
await recorderModule
.setSubscriptionDuration(const Duration(milliseconds: 10));
//初始化日期插件
await initializeDateFormatting();
}
复制代码
Permisos de micrófono
Future<bool> getPermissionStatus() async {
Permission permission = Permission.microphone;
//granted 通过,denied 被拒绝,permanentlyDenied 拒绝且不在提示
PermissionStatus status = await permission.status;
if (status.isGranted) {
return true;
} else if (status.isDenied) {
requestPermission(permission);
} else if (status.isPermanentlyDenied) {
openAppSettings();
} else if (status.isRestricted) {
requestPermission(permission);
} else {}
return false;
}
///申请权限
void requestPermission(Permission permission) async {
PermissionStatus status = await permission.request();
if (status.isPermanentlyDenied) {
openAppSettings();
}
}
复制代码
empezar a grabar
/// 开始录音
_startRecorder() async {
try {
//获取麦克风权限
await getPermissionStatus().then((value) async {
if (!value) {
return;
}
//用户允许使用麦克风之后开始录音
Directory tempDir = await getTemporaryDirectory();
var time = DateTime.now().millisecondsSinceEpoch;
String path = '${tempDir.path}/$time${ext[Codec.aacADTS.index]}';
//这里我录制的是aac格式的,还有其他格式
await recorderModule.startRecorder(
toFile: path,
codec: Codec.aacADTS,
bitRate: 8000,
numChannels: 1,
sampleRate: 8000,
);
/// 监听录音
_recorderSubscription = recorderModule.onProgress!.listen((e) {
var date = DateTime.fromMillisecondsSinceEpoch(
e.duration.inMilliseconds,
isUtc: true);
var txt = DateFormat('mm:ss:SS', 'en_GB').format(date);
//设置了最大录音时长
if (date.second >= _maxLength) {
_stopRecorder();
return;
}
setState(() {
//更新录音时长
_recordText = txt.substring(1, 5);
});
});
setState(() {
//更新录音状态和录音文件路径
_state = RecordPlayState.recording;
_path = path;
});
});
} catch (err) {
setState(() {
_stopRecorder();
_state = RecordPlayState.record;
_cancelRecorderSubscriptions();
});
}
}
复制代码
finalizar grabación
/// 结束录音
_stopRecorder() async {
try {
await recorderModule.stopRecorder();
_cancelRecorderSubscriptions();
// _getDuration();
} catch (err) {}
setState(() {
_state = RecordPlayState.record;
});
}
///销毁录音
void dispose() {
super.dispose();
_cancelRecorderSubscriptions();
_releaseFlauto();
}
/// 取消录音监听
void _cancelRecorderSubscriptions() {
if (_recorderSubscription != null) {
_recorderSubscription!.cancel();
_recorderSubscription = null;
}
}
/// 释放录音
Future<void> _releaseFlauto() async {
try {
await recorderModule.closeRecorder();
} catch (e) {}
}
/// 判断文件是否存在
Future<bool> _fileExists(String path) async {
return await File(path).exists();
}
复制代码
Reproducir métodos comunes
Inicializar el reproductor
FlutterSoundPlayer playerModule = FlutterSoundPlayer();
复制代码
operación de inicialización
init() async {
await playerModule.closePlayer();
await playerModule.openPlayer();
await playerModule
.setSubscriptionDuration(const Duration(milliseconds: 10));
//这块是设置音频,暂时没用到可以不用设置
final session = await AudioSession.instance;
await session.configure(AudioSessionConfiguration(
avAudioSessionCategory: AVAudioSessionCategory.playAndRecord,
avAudioSessionCategoryOptions:
AVAudioSessionCategoryOptions.allowBluetooth |
AVAudioSessionCategoryOptions.defaultToSpeaker,
avAudioSessionMode: AVAudioSessionMode.spokenAudio,
avAudioSessionRouteSharingPolicy:
AVAudioSessionRouteSharingPolicy.defaultPolicy,
avAudioSessionSetActiveOptions: AVAudioSessionSetActiveOptions.none,
androidAudioAttributes: const AndroidAudioAttributes(
contentType: AndroidAudioContentType.speech,
flags: AndroidAudioFlags.none,
usage: AndroidAudioUsage.voiceCommunication,
),
androidAudioFocusGainType: AndroidAudioFocusGainType.gain,
androidWillPauseWhenDucked: true,
));
}
复制代码
empezar a jugar
///开始播放,这里做了一个播放状态的回调
void startPlayer(PlayStateBack callBack) async {
try {
if (path.contains('http')) {
await playerModule.startPlayer(
fromURI: path,
codec: Codec.mp3,
sampleRate: 44000,
whenFinished: () {
stopPlayer();
callBack(0);
});
} else {
//判断文件是否存在
if (await _fileExists(path)) {
if (playerModule.isPlaying) {
playerModule.stopPlayer();
}
await playerModule.startPlayer(
fromURI: path,
codec: Codec.aacADTS,
sampleRate: 44000,
whenFinished: () {
stopPlayer();
callBack(0);
});
} else {}
}
//监听播放进度
_playerSubscription = playerModule.onProgress!.listen((e) {});
callBack(1);
} catch (err) {
callBack(0);
}
}
复制代码
finalizar reproducción
/// 结束播放
void stopPlayer() async {
try {
await playerModule.stopPlayer();
cancelPlayerSubscriptions();
} catch (err) {}
}
/// 取消播放监听
void cancelPlayerSubscriptions() {
if (_playerSubscription != null) {
_playerSubscription!.cancel();
_playerSubscription = null;
}
}
///获取播放状态
Future<PlayerState> getPlayState() async {
return await playerModule.getPlayerState();
}
/// 释放播放器
void releaseFlauto() async {
try {
await playerModule.closePlayer();
} catch (e) {
print(e);
}
}
/// 判断文件是否存在
Future<bool> _fileExists(String path) async {
return await File(path).exists();
}
复制代码
Implementación de animación
En el proceso de grabación y reproducción es inevitable utilizar animación, aquí te diré cómo cargarla.gif和动画文件
Cargando gifs animados
Visibility(
visible: (item.playing.value == 1) ? true : false,
child: Image.asset('assets/-comm/comm_audio_paly.gif', width: 20, height: 20,),
replacement: const Image(
image: AssetImage('assets/-comm/comm_audio_icon.png'),
width: 20,
height: 20,
),
)
复制代码
Cargar archivo de animación
Lottie.asset('assets/-comm/record_audio_animation.json',
height: 25,
width: ScreenAdapter.screenWidth() -ScreenAdapter.width(160),
animate: true)
复制代码
subir archivos
Subir archivos de audio
var map = {
"file": MultipartFile.fromBytes(
await File.fromUri(Uri(path: path)).readAsBytes(),
filename: "$fileName.mp3",
contentType: MediaType.parse("audio/mp3"))
};
复制代码
Resumir
Lo anterior describe cómo grabar, cómo reproducir archivos de audio locales y remotos, cómo implementar animaciones y cómo cargar archivos de audio después de la grabación Estos son los problemas que generalmente encontramos al usar esta función. También se enumeran los problemas encontrados en el proceso de uso, espero poder ayudarlo.