Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Operationg multiple flutter_sound instance independently #232

Closed
kiha-la opened this issue Mar 4, 2020 · 5 comments
Closed

Operationg multiple flutter_sound instance independently #232

kiha-la opened this issue Mar 4, 2020 · 5 comments

Comments

@kiha-la
Copy link

kiha-la commented Mar 4, 2020

Version of flutter_sound

flutter_sound: ^2.0.4

flutter doctor

[√] Flutter (Channel stable, v1.12.13+hotfix.8, on Microsoft Windows [Version 10.0.17763.1039], locale ja-JP)

[√] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
[√] Android Studio (version 3.6)
[√] VS Code, 64-bit edition (version 1.42.1)
[√] Connected device (1 available)

Platforms you faced the error (IOS or Android or both?)

Tested on Android

Expected behavior

  1. Call only one onRecorderDbPeakChanged callback within the multiple FlutterSound instances.
  2. Able to stop any recorder one of them.

Actual behavior

  1. onRecorderDbPeakChanged for all FlutterSound instances.
  2. Can only control the recorder that started last.
Restarted application in 1,157ms.
D/FlutterSoundPlugin(11332): rawAmplitude: 0.0 Base DB: 0.0
I/flutter (11332): startRecorder: /data/user/0/com.dooboolab.fluttersoundexample/cache/file_dbLevel_disable.aac
D/FlutterSoundPlugin(11332): rawAmplitude: 0.0 Base DB: 0.0
I/flutter (11332):
I/flutter (11332): got dB update of  file_dbLevel_disable -> 0.0
I/flutter (11332): 	2020-03-04T15:24:33.141111
I/flutter (11332): startRecorder: /data/user/0/com.dooboolab.fluttersoundexample/cache/file_dbLevel_enable.aac
D/FlutterSoundPlugin(11332): rawAmplitude: 1410.0 Base DB: 42.67625931342095
I/flutter (11332):
I/flutter (11332): got dB update of  file_dbLevel_disable -> 42.67625931342095
I/flutter (11332): 	2020-03-04T15:24:34.111216
I/flutter (11332):
I/flutter (11332): got dB update of  file_dbLevel_enable -> 42.67625931342095
I/flutter (11332): 	2020-03-04T15:24:34.111296
D/FlutterSoundPlugin(11332): rawAmplitude: 1175.0 Base DB: 41.09263439246845
I/flutter (11332):
I/flutter (11332): got dB update of  file_dbLevel_disable -> 41.09263439246845
I/flutter (11332): 	2020-03-04T15:24:35.112086
I/flutter (11332):
I/flutter (11332): got dB update of  file_dbLevel_enable -> 41.09263439246845
I/flutter (11332): 	2020-03-04T15:24:35.112165
I/flutter (11332): STOP!!!
I/flutter (11332): stopRecorder: /data/user/0/com.dooboolab.fluttersoundexample/cache/file_dbLevel_enable.aac

Tested environment (Emulator? Real Device?)

  • Android API 29 (Emulator)

Steps to reproduce the behavior

  1. l.29 Declare two instances with FlutterSound member.

    • One of them is set to flutterSound.setDbLevelEnabled(false), another is flutterSound.setDbLevelEnabled(true).
  2. l.39 Execute flutterSound.startRecorder against both instance.

    • The order of execution is 'setDbLevelEnabled(false) one' -> 'setDbLevelEnabled(true) one' .
  3. Result of two onRecorderDbPeakChanged callback are shown.

  4. l.57 Call flutterSound.stopRecorder() of the dBLevel Disabled instance.

  5. flutterSound.stopRecorder() of the dBLevel Enabled instance is called.

    • The audio recorder in FlutterSound is overwritten?
  6. Exception has occurred due to _recorderSubscription of the dBLevel Enabled instance called against null recorder.

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart' show DateFormat;
import 'package:intl/date_symbol_data_local.dart';
import 'dart:async';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:path_provider/path_provider.dart' show getTemporaryDirectory;

void main() async {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  var recorder_dbLevel_disable = AudioRecorder(isEnableDbPeak: false); //iInstance DbLevel Disabled
  var recorder_dbLevel_enable = AudioRecorder(isEnableDbPeak: true); //Instance DbLevel Enabled

  @override
  void initState() {
    // TODO: implement initState
    super.initState();

    recorder_dbLevel_disable.startRecorder(fileName: "file_dbLevel_disable"); //Start recording from  DbLevel Disabled instance
    recorder_dbLevel_enable.startRecorder(fileName: "file_dbLevel_enable");
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('App Name'),
      ),
      floatingActionButton: new FloatingActionButton(
          child: new Icon(Icons.add_circle), onPressed: fabPressed),
    );
  }

  void fabPressed() {
    print("STOP!!!");
    recorder_dbLevel_disable.stopRecorder();
  }
}

class AudioRecorder {
  StreamSubscription _dbPeakSubscription;
  StreamSubscription _recorderSubscription;
  FlutterSound flutterSound;

  t_CODEC _codec = t_CODEC.CODEC_AAC;

  AudioRecorder({bool isEnableDbPeak}) {
    flutterSound = new FlutterSound();
    flutterSound.setDbPeakLevelUpdate(1.0);
    flutterSound.setDbLevelEnabled(isEnableDbPeak);
    flutterSound.setSubscriptionDuration(1.0);
    initializeDateFormatting();
  }

  void startRecorder({String fileName}) async {
    try {
      Directory tempDir = await getTemporaryDirectory();

      String path = await flutterSound.startRecorder(
        uri: '${tempDir.path}/' + fileName + '.aac',
        codec: _codec,
      );
      print('startRecorder: $path');

      _dbPeakSubscription =
          flutterSound.onRecorderDbPeakChanged.listen((value) {
        print("\ngot dB update of  "+ fileName +" -> $value");
        print("\t" + DateTime.now().toIso8601String());
      });

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

      //print(fileName + ":" + txt);
    });
    } catch (err) {
      print('startRecorder error: $err');
    }
  }

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

      if (_dbPeakSubscription != null) {
        _dbPeakSubscription.cancel();
        _dbPeakSubscription = null;
      }
      if ( _recorderSubscription != null ) {
        _recorderSubscription.cancel ();
        _recorderSubscription = null;
      }
    } catch (err) {
      print('stopRecorder error: $err');
    }
  }
}

It seems that onRecorderDbPeakChanged is excused against all FlutterSound instances, because of _dbPeakController is static. I avoid this problem by changing _dbPeakController to non-static (I'm not sure this solution is safe or not... ). However I have not resolved 'recorder overwritten problem' yet.

Is there any reason FlutterSound does not support the multiple audio recording?

@Larpoux
Copy link
Collaborator

Larpoux commented Mar 6, 2020

I really think that flutter_sound should be re-entrant (can play or record several audios sessions independently).
But I do not think that it has already requested by someone. And surely not tested 😆 .
Thank you @kiha-la for your investigations. This is very interesting.

Not sure that this point will be a priority, and unfortunately we do not have plenty of time.
However I think this will be something nice to do inside flutter_sound.
I do not promise, but I will try to work on this issue when I will have some spare time.

@kiha-la
Copy link
Author

kiha-la commented Mar 9, 2020

I also think this usage is some kind of unexpected and "unsophisticated" 😑...
I guess this restriction comes from reason for the hardware management.
But from the point of view of the programmers, this like restriction should be hidden, shouldn't it?

In any case, I'm little bit confused by this behavior that the "instance I operate" and "actually operated instance" are not linked:confused:.

Thank you for your opinion and contribution @Larpoux 😄. (and also all contributors👍)
I hope this future implemented in someday.

@kiha-la kiha-la closed this as completed Mar 9, 2020
@Larpoux
Copy link
Collaborator

Larpoux commented Mar 15, 2020

The new flutter_sound version has two different modules:

  • The legacy flutter_sound with some improvments like some tools to control the Audio-focus
  • Flauto, wich adds @salvatore373 improvements .

Those two modules are completely separated. This has two benefits:

  • Separated functionalities means easier maintenance
  • The legacy flutter_sound module is totally backward compatible

My project would be to split again the legacy flutter_sound module into two different modules :

  • FlutterSoundRecorder
  • FlutterSoundPlayer
    Those two functionalities are not related together, and there is no reason to have just one module.
    Having two smaller modules will let the maintenance easier.

For having backward compatibility, the FlutterSoundPlayer module will be called simply FlutterSound and will inherit from flutterSoundRecorder.
But new developer will be encouraged to use the FlutterSoundRecorder module for recording.

Then, we will have three modules :

  • Flauto (which inherit from `FlutterSoundPlayer)
  • FlutterSoundPlayer (which inherit from FlutterSoundRecorder for backward compatibility)
  • FlutterSoundRecorder

Then, I think it will be easier to address #232 (which has been closed by its creator, but for me this issue is still valid and interesting).

@Larpoux
Copy link
Collaborator

Larpoux commented Mar 24, 2020

@kiha-la : I re-open your issue under #250 .
I really think that flutter_sound design is incorrect and should be fixed.

@Larpoux Larpoux mentioned this issue Mar 29, 2020
@Larpoux
Copy link
Collaborator

Larpoux commented Mar 29, 2020

PR #257 is a major re-design of flutter_sound architecture.
flutter_sound module is now split into :

  • FlautoRecorder
  • FlautoPlayer
    All modules are re-entrant. It is possible to start several FlautoPlayer and several FlautoRecorder at the same time.

Complete backward compatibility is provided by two deprecated modules :

  • FlutterSound.dart
  • Flauto.dart

@kiha-la : This PR is still in beta-version, and is still not merged in Flutter-Sound Master branch.
In the meantime, it will be great if you can test it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants