Вопрос или проблема
Я создаю приложение для слухового аппарата на Flutter для тех, кто не слышит нормально. Идея заключается в том, что звук, который микрофон получает от пользователя, можно изменять, изменяя его частоту, высоту тона и другие настройки с помощью ползунка или чего-то подобного, а динамик воспроизводит этот звук с обработанными настройками. Проблема, с которой я сталкиваюсь, заключается в том, что Flutter сначала записывает звук, а затем воспроизводит его. Как сделать так, чтобы звук непосредственно воспроизводился с микрофона на динамик? Динамик может быть мобильным или гарнитурой.
Я ожидаю, что звук будет воспроизводиться наряду со звуком с микрофона.
import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:permission_handler/permission_handler.dart';
class VoiceChanger extends StatefulWidget {
@override
_VoiceChangerState createState() => _VoiceChangerState();
}
class _VoiceChangerState extends State<VoiceChanger> {
late final StreamController<Uint8List> _audioStreamController;
FlutterSoundRecorder? _recorder;
FlutterSoundPlayer? _player;
bool isRecording = false;
bool isPlayingBack = false;
@override
void initState() {
super.initState();
_recorder = FlutterSoundRecorder();
_player = FlutterSoundPlayer();
_audioStreamController = StreamController<Uint8List>();
initAudio();
}
Future<void> initAudio() async {
await _recorder!.openRecorder();
await _player!.openPlayer();
await _player!.setVolume(1.0);
}
Future<void> startRecording() async {
if (await Permission.microphone.request().isGranted) {
// Начинаем запись в поток
await _recorder!.startRecorder(
toStream: _audioStreamController.sink,
codec: Codec.pcm16,
);
// Слушаем поток и воспроизводим аудиоданные в реальном времени
_audioStreamController.stream.listen((data) async {
// Обеспечиваем плавность воспроизведения
if (!isPlayingBack) {
isPlayingBack = true;
await _player!.startPlayer(
fromDataBuffer: data,
codec: Codec.pcm16,
whenFinished: () {
isPlayingBack = false; // Установить флаг воспроизведения в false, когда закончится
},
);
} else {
// Подаем новые аудиоданные на воспроизведение без перерыва
await _player!.feedFromStream(data);
}
});
setState(() {
isRecording = true;
});
} else {
print("Разрешение на использование микрофона не предоставлено");
}
}
Future<void> stopRecording() async {
await _recorder!.stopRecorder();
setState(() {
isRecording = false;
isPlayingBack = false; // Остановить воспроизведение
});
}
@override
void dispose() {
_recorder?.closeRecorder();
_player?.closePlayer();
_audioStreamController.close(); // Убедиться, что поток закрыт
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Изменитель голоса'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: isRecording ? stopRecording : startRecording,
child: Text(isRecording ? 'Остановить запись' : 'Начать запись'),
),
],
),
),
);
}
}
Чтобы достичь воспроизведения аудио в реальном времени во время записи, рассмотрите следующие подходы:
- Используйте метод feedFromStream от flutter_sound: Вы уже используете этот метод, но убедитесь, что подаете аудиоданные на воспроизведение сразу, как только они становятся доступными от рекордера.
- Используйте AudioTrack из пакета audioplayers: Создайте экземпляр AudioTrack и передайте записанные аудиоданные в его метод play.
- Изучите другие пакеты: dart_av: Предоставляет низкоуровневые возможности обработки аудио. audiomix: Позволяет смешивание аудиопотоков.
- Измените пакет flutter_sound: Если вышеуказанные решения не работают, рассмотрите возможность изменения пакета flutter_sound для включения воспроизведения в реальном времени. Вот обновленная версия вашего метода startRecording с использованием feedFromStream:
Future<void> startRecording() async {
// ...
_audioStreamController.stream.listen((data) async {
if (_player!.isPlaying) {
await _player!.feedFromStream(data);
} else {
await _player!.startPlayer(
fromDataBuffer: data,
codec: Codec.pcm16,
);
}
});
// ...
}
Ответ или решение
Проблема воспроизведения аудио во время записи в приложении Flutter
При разработке приложения слухового aids на Flutter, у вас возникла задача реализовать прямую передачу звука с микрофона на динамик без промежуточной записи. Это необходимо для того, чтобы пользователи могли настраивать параметры звука, такие как частота и высота тона, в реальном времени. Однако текущая реализация, как вы заметили, сначала записывает звук, а только потом воспроизводит его. Давайте рассмотрим возможные решения этой проблемы.
Варианты решения проблемы
-
Использование метода
feedFromStream
из пакетаflutter_sound
.
Вы уже на верном пути, применяя этот метод, однако важно убедиться, что данные аудио передаются в динамик сразу после их получения от рекордера. Это поможет избежать задержек в воспроизведении. -
Создание экземпляра AudioTrack из пакета
audioplayers
.
Этот пакет позволяет более гибко управлять аудиопотоками. Возможно, вам потребуется создать экземплярAudioTrack
и передавать записанные аудиоданные в методplay
. -
Изучение других пакетов.
Рассмотрите возможность использования пакетов, таких какdart_av
для низкоуровневой работы с аудио, илиaudiomix
, который позволяет смешивать аудиопотоки. Эти решения могут дать вам больше контроля над обработкой звука и его воспроизведением. -
Модификация пакета
flutter_sound
.
Если предложенные решения не подходят, возможно, стоит рассмотреть модификацию самого пакетаflutter_sound
, чтобы включить функцию воспроизведения в реальном времени. Это требует глубокого понимания внутренней структуры пакета, но может оказаться самым эффективным решением.
Пример доработки вашей функции startRecording
Вот обновленный вариант вашей функции startRecording
, который включает в себя использование метода feedFromStream
более эффективно:
Future<void> startRecording() async {
if (await Permission.microphone.request().isGranted) {
await _recorder!.startRecorder(
toStream: _audioStreamController.sink,
codec: Codec.pcm16,
);
_audioStreamController.stream.listen((data) async {
if (_player!.isPlaying) {
await _player!.feedFromStream(data);
} else {
await _player!.startPlayer(
fromDataBuffer: data,
codec: Codec.pcm16,
whenFinished: () {
isPlayingBack = false; // Сброс состояния воспроизведения
},
);
}
});
setState(() {
isRecording = true;
});
} else {
print("Нет доступа к микрофону");
}
}
Заключение
Практическое применение вышеописанных подходов позволит вам создать функциональность в вашем приложении, где звук будет воспроизводиться непосредственно из микрофона в реальном времени без постоянных задержек на запись. Важно тщательно протестировать каждое из решений, чтобы понять, какое из них наилучшим образом подходит для ваших требований. Надеюсь, предоставленные рекомендации помогут вам в реализации вашего проекта.