I'm trying to play audio from a stream of bytes in Flutter. I've used the Just Audio package's example on reading from a stream of bytes, and I'm still getting an error. The error is:
Playback error
E/ExoPlayerImplInternal(19173): com.google.android.exoplayer2.ExoPlaybackException: Source error
E/ExoPlayerImplInternal(19173): at com.google.android.exoplayer2.ExoPlayerImplInternal.handleIoException(ExoPlayerImplInternal.java:632)
E/ExoPlayerImplInternal(19173): at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:602)
E/ExoPlayerImplInternal(19173): at android.os.Handler.dispatchMessage(Handler.java:98)
E/ExoPlayerImplInternal(19173): at android.os.Looper.loop(Looper.java:154)
E/ExoPlayerImplInternal(19173): at android.os.HandlerThread.run(HandlerThread.java:61)
E/ExoPlayerImplInternal(19173): Caused by: com.google.android.exoplayer2.source.UnrecognizedInputFormatException: None of the available extractors (Mp3Extractor, FlvExtractor, FlacExtractor, WavExtractor, FragmentedMp4Extractor, Mp4Extractor, AmrExtractor, PsExtractor, OggExtractor, TsExtractor, MatroskaExtractor, AdtsExtractor, Ac3Extractor, Ac4Extractor, AviExtractor, JpegExtractor) could read the stream.
E/ExoPlayerImplInternal(19173): at com.google.android.exoplayer2.source.BundledExtractorsAdapter.init(BundledExtractorsAdapter.java:92)
E/ExoPlayerImplInternal(19173): at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:1017)
E/ExoPlayerImplInternal(19173): at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:412)
E/ExoPlayerImplInternal(19173): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
E/ExoPlayerImplInternal(19173): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
E/ExoPlayerImplInternal(19173): at java.lang.Thread.run(Thread.java:762)
E/AudioPlayer(19173): TYPE_SOURCE: None of the available extractors (Mp3Extractor, FlvExtractor, FlacExtractor, WavExtractor, FragmentedMp4Extractor, Mp4Extractor, AmrExtractor, PsExtractor, OggExtractor, TsExtractor, MatroskaExtractor, AdtsExtractor, Ac3Extractor, Ac4Extractor, AviExtractor, JpegExtractor) could read the stream.
I can see that something is wrong with the input format. However, I'm just not sure what it is. Here is the code that is supposed to perform the playback:
void initAudio() async {
final server = await ServerSocket.bind(InternetAddress.anyIPv4, port);
final player = AudioPlayer();
final session = await AudioSession.instance;
await session.configure(const AudioSessionConfiguration.speech());
await session.setActive(true);
server.listen((socket) {
// event is a socket
socket.listen((Uint8List data) async {
print(data);
player.setAudioSource(MyCustomSource(data), preload: false);
player.play();
});
});
}
MyCustomSource
came from the Just Audio pub.dev listing, and it looks like this:
// Feed your own stream of bytes into the player
class MyCustomSource extends StreamAudioSource {
final List<int> bytes;
MyCustomSource(this.bytes);
@override
Future<StreamAudioResponse> request([int? start, int? end]) async {
start ??= 0;
end ??= bytes.length;
return StreamAudioResponse(
sourceLength: bytes.length,
contentLength: end - start,
offset: start,
stream: Stream.value(bytes.sublist(start, end)),
contentType: 'audio/mpeg',
);
}
}
I'm trying to send a Stream<List<int>>
over a socket to stream audio over the internet. Here's the audio sender side:
void recordAudio() async {
print("recording and sampling");
final socket = await Socket.connect(a5atHome, port);
Stream<Uint8List>? stream = await MicStream.microphone(sampleRate: 44100);
socket.addStream(stream!);
StreamSubscription<List<int>> listener = stream.listen((samples) async {
print(samples);
});
}
I'm not sure if something is wrong with the sender side, either. I'm new to using JustAudio and I'm not sure where the error is coming from. Any help would be greatly appreciated.
Edit: By the way, I'm using the mic_stream
pub.dev package to get microphone data in the form of a Stream
CodePudding user response:
Eventually figured it out. Thanks to Ryan Heise for pointing me in the right direction.
The MicStream
package records audio data in the raw PCM format, so I needed to find a package that could play audio in this format too. From this answer, I found someone was looking to do the exact same thing - basically playing audio from a List<int>
of audio data.
The package called flutter_sound
was able to do this for me, per that other answer.
The sending side:
final socket = await Socket.connect(a5atHome, port);
Stream<Uint8List>? stream = await MicStream.microphone(
sampleRate: 44100, audioFormat: AudioFormat.ENCODING_PCM_16BIT);
await socket.addStream(stream!);
and the playing side, which needed the fixing:
FlutterSoundPlayer player = FlutterSoundPlayer();
final server = await ServerSocket.bind(InternetAddress.anyIPv4, port);
final session = await AudioSession.instance;
await session.configure(const AudioSessionConfiguration.speech());
await session.setActive(true);
await player.openPlayer(enableVoiceProcessing: true);
server.listen((socket) async {
await player.startPlayerFromStream(
codec: Codec.pcm16, numChannels: 1, sampleRate: 44100);
socket.listen((Uint8List data) async {
player.foodSink!.add(FoodData(data));
});
});
MicStream
's ENCODING_PCM_16BIT
is the same as flutter_sound
's Codec.pcm16
format. The format matches, and sound is played!