Canardoux / flutter_sound

Flutter plugin for sound. Audio recorder and player.
Mozilla Public License 2.0
878 stars 574 forks source link

[HELP]First call the native end of the voice input, then play the raw format file sound change #1049

Closed OmgKevin closed 5 months ago

OmgKevin commented 5 months ago

my code :

import 'dart:convert'; import 'package:flutter_sound/flutter_sound.dart'; import 'package:dio/dio.dart'; import 'dart:io'; import 'package:path_provider/path_provider.dart'; import 'package:crypto/crypto.dart';

class AudioPlayerUtil { late FlutterSoundPlayer _player; bool _isPlaying = false; Function? onPlaybackComplete;

AudioPlayerUtil() { _player = FlutterSoundPlayer(); _openAudioSession(); }

Future _openAudioSession() async { await _player.openPlayer(); }

Future _closeAudioSession() async { await _player.closePlayer(); }

Future _downloadFile(String url, String filename) async { Dio dio = Dio(); var response = await dio.get( url, options: Options(responseType: ResponseType.bytes), ); var tempDir = await getTemporaryDirectory(); var tempFile = File('${tempDir.path}/$filename'); await tempFile.writeAsBytes(response.data); return tempFile; }

Future _getCachedFile(String url) async { String fileExtension = url.split('.').last.split('?').first; String fileName = _getUniqueFileName(url, fileExtension); var tempDir = await getTemporaryDirectory(); var tempFile = File('${tempDir.path}/$fileName'); if (await tempFile.exists()) { return tempFile; } else { return await _downloadFile(url, fileName); } }

String _getUniqueFileName(String url, String fileExtension) { String uniqueName = url; if (url.contains('/')) { List parts = url.split('/'); String lastPart = parts.last; String hash = md5.convert(utf8.encode(lastPart)).toString(); uniqueName = hash + '.' + fileExtension; } return uniqueName; }

Future play(String audioUrl) async { if (!_isPlaying) { try { var tempFile = await _getCachedFile(audioUrl);

    String fileExtension = audioUrl.split('.').last.split('?').first;
    int sampleRate = 44100;
    int numChannels = 2;
    Codec codec;

    switch (fileExtension) {
      case 'mp3':
        codec = Codec.mp3;
        break;
      case 'wav':
        codec = Codec.pcm16WAV;
        break;
      case 'raw':
        codec = Codec.pcm16;
        sampleRate = 16000;
        numChannels = 1;
        break;
      default:
        throw UnsupportedError('不支持的音频格式: $fileExtension');
    }

    await _player.startPlayer(
      fromURI: tempFile.path,
      codec: codec,
      sampleRate: sampleRate,
      numChannels: numChannels,
      whenFinished: () {
        _isPlaying = false;
        if (onPlaybackComplete != null) {
          onPlaybackComplete!();
        }
      },
    );

    _isPlaying = true;

    _player.onProgress!.listen((event) {
      if (event != null && event.position >= event.duration) {
        _isPlaying = false;
        if (onPlaybackComplete != null) {
          onPlaybackComplete!();
        }
      }
    });
  } catch (e) {
    print("下载失败或音频播放异常: $e");
  }
}

}

Future pause() async { if (_isPlaying) { await _player.pausePlayer(); _isPlaying = false; } }

Future resume() async { if (!_isPlaying) { await _player.resumePlayer(); _isPlaying = true; } }

bool isPlaying() { return _isPlaying; }

void dispose() { _closeAudioSession(); } }

and Implementation of the call: AudioPlayerUtil audioPlayerUtil = AudioPlayerUtil(); audioPlayerUtil.play(renderContent.url ?? '');

The operation sequence is to call the native end recorder function first, and then play the voice after completion. The tone is abnormal.How should I adjust it?

OmgKevin commented 5 months ago

The operation sequence is to first call the native SDK recording function (call the microphone), and then use AudioPlayerUtil to play the voice after completion. The tone is abnormal. How can I adjust it?

Larpoux commented 5 months ago

Which codec do you use ? MP3, WAV or RAW? Which platform ? iOS or Android or WEB ? May we have the logs ? What is your tone problem ? Are the recorder and player doing something ? Or completely mute ?

OmgKevin commented 5 months ago

Which codec do you use ? MP3, WAV or RAW? Which platform ? iOS or Android or WEB ? May we have the logs ? What is your tone problem ? Are the recorder and player doing something ? Or completely mute ?

iOS devices, play raw files

OmgKevin commented 5 months ago

Which codec do you use ? MP3, WAV or RAW? Which platform ? iOS or Android or WEB ? May we have the logs ? What is your tone problem ? Are the recorder and player doing something ? Or completely mute ?

It is normal to start the application and directly call to play the raw file, but as long as the recorder is called first and then the play is called, the tone will change.

Larpoux commented 5 months ago

If you have a problem with the pitch with RAW records, it is because you don't specify the same sampleRate for recorder and player.

Larpoux commented 5 months ago

44100 is normal and is probably good for both

OmgKevin commented 5 months ago

44100 is normal and is probably good for both

After my test, I can only set sampleRate=16000, and the speech speed, tone and volume during playback are normal. Regarding what you said about not setting the same sampling rate for recording and playback, because I directly call StartRecord in the recording SDK, I can't see the internally set sampling rate, I can't be sure that the problem lies here

OmgKevin commented 5 months ago

44100 is normal and is probably good for both

I tried to call reset audio manager properties on the native iOS side before calling flutter_sound to play the voice if AVAudioSession.sharedInstance().category == AVAudioSession.Category.playAndRecord { do { try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playAndRecord, options: AVAudioSession.CategoryOptions.defaultToSpeaker) try AVAudioSession.sharedInstance().setActive(false) } catch { print("Error setting audio session category: (error.localizedDescription)") } } But it didn't work

OmgKevin commented 5 months ago

44100 is normal and is probably good for both

    int sampleRate = 16000;
    int numChannels = 1;
    Codec codec = Codec.pcm16;

I listened carefully and the tone seemed to have an echo.

OmgKevin commented 5 months ago

I solved this problem func setRecordAudioSession() { do { try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker]) try AVAudioSession.sharedInstance().setActive(true) } catch { print("Failed to set audio session category.") } } func activeAudioOption() { do { try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, options:[]) try AVAudioSession.sharedInstance().setActive(true) } catch { print("Error setting audio session category: \(error.localizedDescription)") } } Just make sure to call setRecordAudioSession when recording and activeAudioOption before playing, and you should be able to fix the problem.

OmgKevin commented 5 months ago

:)

Larpoux commented 5 months ago

great 👍