start method
Starts listenening to audio.
Uses sampleRate and bufferSize for capturing audio.
Uses androidAudioSource to determine recording type on Android.
When waitForFirstDataOnAndroid is set, it waits for firstDataTimeout duration on first data to arrive.
Will not listen if first date does not arrive in time. Set as true by default on Android.
When waitForFirstDataOnIOS is set, it waits for firstDataTimeout duration on first data to arrive.
Known to not work reliably on iOS and set as false by default.
Implementation
Future<void> start(
void Function(Uint8List) listener,
Function onError, {
int sampleRate = 44100,
int bufferSize = 4000,
int fps = -1,
int androidAudioSource = ANDROID_AUDIOSRC_DEFAULT,
Duration firstDataTimeout = const Duration(seconds: 1),
bool waitForFirstDataOnAndroid = true,
bool waitForFirstDataOnIOS = false,
}) async {
if (_initialized == null) {
throw Exception("Capture must be initialized before use");
}
if (_initialized == false) {
throw Exception("Capture failed to initialize");
}
// We are already listening
if (_audioCaptureEventChannelSubscription != null) return;
// init channel stream
final stream =
_audioCaptureEventChannel.receiveBroadcastStream({
"sampleRate": sampleRate,
"bufferSize": bufferSize,
"audioSource": androidAudioSource,
"fps": fps,
}).cast<Map>();
// The channel will have format:
// {
// "audioData": Float32List,
// "actualSampleRate": double,
// }
_actualSampleRate = null;
var audioStream = stream.map((event) {
_actualSampleRate = event.get('actualSampleRate');
return event.get('audioData') as Uint8List;
});
// Do we need to wait for first data?
final waitForFirstData =
(Platform.isAndroid && waitForFirstDataOnAndroid) ||
(Platform.isIOS && waitForFirstDataOnIOS);
Completer<void>? completer = Completer();
// Prevent stream for starting over because we have no listenre between firstWhere check and this line which initally was at the end of the code
_audioCaptureEventChannelSubscription = audioStream
.skipWhile((element) => !completer.isCompleted)
.listen(listener, onError: onError);
if (waitForFirstData) {
try {
await audioStream
.firstWhere((element) => (_actualSampleRate ?? 0) > 10)
.timeout(firstDataTimeout);
} catch (e) {
// If we timeout, cancel the stream and throw error
completer.completeError(e);
await stop();
rethrow;
}
}
completer.complete();
}