stream method

Stream<Uint8List> stream({
  1. BuildContext? context,
  2. required int frameTimeMs,
  3. AudioFormat format = AudioFormat.s16le,
  4. AudioSampleRate sampleRate = AudioSampleRate.hz48000,
})

Streams a sample in approximated real time in frames of duration frameTimeMs. The streamed data will always be mono (one channel)!

The data of this sample are loaded into memory and afterwards fragmented to sublists, so that each sublists holds data to play for frameTimeMs with respect to the format and sampleRate. If the last sublist is not long enought it is filled with zeroes.

Approximated real time means that the stream yields the sublists, while waiting frameTimeMs between yields. For waiting, a Timer is used, which is more precise than Future.delayed.

Only AudioFormat.f32le and AudioFormat.s16le can be streamed, AudioFormat.wav will result in an ArgumentError!

Implementation

Stream<Uint8List> stream(
    {BuildContext? context,
    required int frameTimeMs,
    AudioFormat format = AudioFormat.s16le,
    AudioSampleRate sampleRate = AudioSampleRate.hz48000}) {
  int bytesPerSample;
  switch (format) {
    case AudioFormat.wav:
      throw new ArgumentError(
          'Only ${AudioFormat.f32le} and ${AudioFormat.s16le} can be streamed!');
    case AudioFormat.s16le:
      bytesPerSample = 2;
      break;
    case AudioFormat.f32le:
      bytesPerSample = 4;
      break;
  }
  int bytesPerFragment = bytesPerSample *
      (audioSampleRateToInt(sampleRate) * frameTimeMs) ~/
      1000;
  Timer? t;
  StreamController<Uint8List>? controller =
      new StreamController<Uint8List>(onCancel: t?.cancel);
  load(format: format, sampleRate: sampleRate).then((Uint8List value) {
    List<Uint8List> data = value.fragment(bytesPerFragment).toList();
    if (!controller.isClosed && data.isNotEmpty) {
      controller.add(data[0]);
      if (data.length > 1) {
        int index = 1;
        t = new Timer.periodic(new Duration(milliseconds: frameTimeMs),
            (Timer t) {
          if (t.isActive) {
            controller.add(data[index]);
            index++;
            if (index == data.length) {
              t.cancel();
              controller.close();
            }
          }
        });
      }
    }
  });
  return controller.stream;
}