[BUG]: Playing audio from PCM stream on android at wrong speed
Flutter Sound Version : 9.23.1
-
FULL or LITE flavor ? FULL
-
Important: Result of the command :
flutter pub deps | grep flutter_sound
├── flutter_sound 9.23.1
│ ├── flutter_sound_platform_interface 9.23.1
│ ├── flutter_sound_web 9.23.1
│ │ ├── flutter_sound_platform_interface...
Severity
- Result is not what expected ?
Platforms you faced the error
-
Android
-
Real device
Describe the bug Thanks for continuous work on this great framework! After upgrading to 9.23.1, we encountered this issue:
Playing audio from pcm16 stream on android seems to be off (audio played at a very fast speed). The methods that we use:
await player.startPlayerFromStream(sampleRate: 24000);
// Replace deprecated call: await player.feedFromStream(buffer);
await player.feedUint8FromStream(buffer);
It did work well before with the deprecated method feedFromStream and it still does work well for iOS.
It could be that the sample rate 24000Hz was not passed correctly to the platform code, or the stream controller for uint8Food overwrites data in the buffer.
I am going to work now on your issue. I recently worked on Streams, to support Float32, multi-channels, and interleaved/plan mode.
I have probably introduced a regression. It was not intentional. Sorry for that.
Thanks for the quick check and thanks for your work on this issue! No worry! I just tried again and we can still use the
deprecated call feedFromStream for now!
Do you use several channels (stereo) ? I think that the problem is because I have not finished the work on Android. iOS is better finished. Web is in a very bad state, except for Float32//Plan mode.
I am glad that you are not blocked: I am currently busy working on the doc. I am doing a major cleaning of this fucking doc 😉 .
No, we have mono audio data only. Our use case is quite simple: we just want to play a stream of pcm16 data (mono, sampled at 24kHz). The framework works fantastic for us!!!
We do support web platform and we have our own code for now, later we will switch to use the framework when pcm16 is supported:
Dart code
void _sendPCMData(Uint8List pcmData) {
if (_audioContext == null || _workletNode == null) initialize();
// Convert Uint8List (raw PCM bytes) to Int16List
final ByteBuffer buffer = pcmData.buffer;
final Int16List int16Data = Int16List.view(buffer);
// Normalize PCM data to Float32 in range [-1, 1]
final Float32List floatData = Float32List(int16Data.length);
for (int i = 0; i < int16Data.length; i++) {
floatData[i] = int16Data[i] / 32768.0; // Normalize to Web Audio format
}
// Send data to JavaScript via JavaScript interop
_workletNode?.port.postMessage(floatData.toJS);
}
javascript code
class PCMProcessor extends AudioWorkletProcessor {
constructor() {
super();
this.buffer = new Float32Array(0); // Buffer to store PCM data
this.port.onmessage = (event) => {
// handle tts interrupting
if (typeof event.data === "string") {
if (event.data == "clear") {
this.buffer = new Float32Array(0);
}
} else {
this.enqueuePCM(event.data);
}
};
}
process(inputs, outputs, parameters) {
const output = outputs[0];
if (this.buffer.length > 0) {
for (let channel = 0; channel < output.length; channel++) {
output[channel].set(this.buffer.slice(0, output[channel].length));
}
this.buffer = this.buffer.slice(output[0].length); // Remove processed samples
// Send number of remaining samples
this.port.postMessage(this.buffer.length)
}
return true; // Continue processing
}
static get parameterDescriptors() {
return [];
}
enqueuePCM(data, sampleRate) {
this.buffer = new Float32Array([...this.buffer, ...data]); // Append new PCM data
}
}
registerProcessor("playpcm.worklet", PCMProcessor);