startRecording method
Start recording audio from microphone
onAudioData Callback for audio data chunks (16kHz mono Int16 PCM)
Throws AudioCaptureError if recording cannot be started.
Implementation
Future<void> startRecording(
void Function(Uint8List audioData) onAudioData) async {
if (_isRecording) {
_logger.warning('Already recording');
return;
}
try {
_onAudioData = onAudioData;
// Check if we can record
_logger.info('Checking microphone permission...');
if (!await _recorder.hasPermission()) {
_logger.error('No microphone permission');
throw AudioCaptureError.permissionDenied();
}
_logger.info('✅ Microphone permission granted');
// Start streaming audio in PCM 16-bit format
_logger.info(
'Starting audio stream: ${targetSampleRate}Hz, mono, PCM16bits...');
final stream = await _recorder.startStream(
const RecordConfig(
encoder: AudioEncoder.pcm16bits,
sampleRate: targetSampleRate,
numChannels: 1, // Mono
bitRate: 256000,
),
);
_logger.info('✅ Audio stream created, setting up listener...');
// Track data delivery
int chunkCount = 0;
// Listen to audio stream
_audioStreamSubscription = stream.listen(
(data) {
chunkCount++;
// Log first few chunks to verify data flow
if (chunkCount <= 3) {
_logger.info(
'🎵 Audio data received: chunk #$chunkCount, ${data.length} bytes');
}
if (_isRecording && _onAudioData != null) {
_onAudioData!(data);
} else {
_logger.warning(
'⚠️ Audio data ignored: isRecording=$_isRecording, hasCallback=${_onAudioData != null}');
}
},
onError: (Object error) {
_logger.error('❌ Audio stream error: $error');
},
onDone: () {
_logger.info('🛑 Audio stream ended (total chunks: $chunkCount)');
},
);
_isRecording = true;
_recordingStateController.add(true);
_logger.info(
'✅ Recording started successfully (16kHz mono PCM) - waiting for audio data...');
} catch (e) {
_logger.error('❌ Failed to start recording: $e');
_onAudioData = null;
throw AudioCaptureError.engineStartFailed();
}
}