Open mrj976 opened 4 years ago
Multiple streams with the same type of media require multiple renderers to play them at the same time. By default, ExoPlayer's DefaultRenderersFactory
provides one MediaCodecAudioRenderer
and potentially some extension audio renderers. So it's actually surprising that two of the audio files play in parallel already.
You could in theory provide multiple MediaCodecAudioRenderers
in a RenderersFactory
you pass in to ExoPlayerFactory
. However, audio renderers also function as the media clock and the player fails if multiple media clocks are provided. You can circumvent this problem by subclassing MediaCodecAudioRenderer
and returning null from getMediaClock
. I haven't tested this, but this would probably allow the parallel playback. Note however, that there won't be any time synchronization between the renderers and the audio files may drift apart.
If your app is doing nothing else with ExoPlayer and all the files are local, you can also consider using SoundPool
without any ExoPlayer integration.
Multiple streams with the same type of media require multiple renderers to play them at the same time. By default, ExoPlayer's
DefaultRenderersFactory
provides oneMediaCodecAudioRenderer
and potentially some extension audio renderers. So it's actually surprising that two of the audio files play in parallel already.You could in theory provide multiple
MediaCodecAudioRenderers
in aRenderersFactory
you pass in toExoPlayerFactory
. However, audio renderers also function as the media clock and the player fails if multiple media clocks are provided. You can circumvent this problem by subclassingMediaCodecAudioRenderer
and returning null fromgetMediaClock
. I haven't tested this, but this would probably allow the parallel playback. Note however, that there won't be any time synchronization between the renderers and the audio files may drift apart.
Thanks I have 6 audio files Can you send me an example?
If your app is doing nothing else with ExoPlayer and all the files are local, you can also consider using
SoundPool
without any ExoPlayer integration.
I want play a video with 6 audio files So I used ExoPlayer Is there any other way to solve this problem? Use another library
The way I described above seems to work with the added complication of needing a custom TrackSelector
implementation that links tracks to audio renderers.
Please note that the renderers are not actively synchronized to each other, so depending on your alignment requirements between these streams, this may be a problem. You will also need to select the video track in the track selector if you want to enable it.
Code I used for testing:
-----MediaSource-----
mediaSource = new MergingMediaSource(source1, ..., source4);
----RendersFactory-----
RenderersFactory renderersFactory = new DefaultRenderersFactory(this) {
@Override
protected void buildAudioRenderers(Context context, int extensionRendererMode,
MediaCodecSelector mediaCodecSelector,
@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
boolean playClearSamplesWithoutKeys, boolean enableDecoderFallback,
AudioProcessor[] audioProcessors, Handler eventHandler,
AudioRendererEventListener eventListener, ArrayList<Renderer> out) {
super.buildAudioRenderers(context, extensionRendererMode, mediaCodecSelector,
drmSessionManager, playClearSamplesWithoutKeys, enableDecoderFallback,
audioProcessors, eventHandler, eventListener, out);
out.add(new AudioRendererWithoutClock(context, mediaCodecSelector));
out.add(new AudioRendererWithoutClock(context, mediaCodecSelector));
out.add(new AudioRendererWithoutClock(context, mediaCodecSelector));
}
};
with the following class:
private static final class AudioRendererWithoutClock extends MediaCodecAudioRenderer {
public AudioRendererWithoutClock(Context context,
MediaCodecSelector mediaCodecSelector) {
super(context, mediaCodecSelector);
}
@Override
public MediaClock getMediaClock() {
return null;
}
}
---- TrackSelector ----
TrackSelector trackSelector = new TrackSelector() {
@Override
public TrackSelectorResult selectTracks(RendererCapabilities[] rendererCapabilities,
TrackGroupArray trackGroups, MediaPeriodId periodId, Timeline timeline)
throws ExoPlaybackException {
Queue<Integer> audioRenderers = new ArrayDeque<>();
RendererConfiguration[] configs = new RendererConfiguration[rendererCapabilities.length];
TrackSelection[] selections = new TrackSelection[rendererCapabilities.length];
for (int i = 0; i < rendererCapabilities.length; i++) {
if(rendererCapabilities[i].getTrackType() == C.TRACK_TYPE_AUDIO) {
audioRenderers.add(i);
}
}
for (int i = 0; i < trackGroups.length; i++) {
if (MimeTypes.isAudio(trackGroups.get(i).getFormat(0).sampleMimeType)) {
Integer index = audioRenderers.poll();
if (index != null) {
selections[index] = new FixedTrackSelection(trackGroups.get(i), 0);
configs[index] = RendererConfiguration.DEFAULT;
}
}
}
return new TrackSelectorResult(configs, selections, new Object());
}
@Override
public void onSelectionActivated(Object info) {
}
};
---- Player ----
player =
new SimpleExoPlayer.Builder(/* context= */ this, renderersFactory)
.setTrackSelector(trackSelector)
.build();
player.prepare(mediaSource);
The way I described above seems to work with the added complication of needing a custom
TrackSelector
implementation that links tracks to audio renderers.Please note that the renderers are not actively synchronized to each other, so depending on your alignment requirements between these streams, this may be a problem. You will also need to select the video track in the track selector if you want to enable it.
Code I used for testing:
-----MediaSource----- mediaSource = new MergingMediaSource(source1, ..., source4); ----RendersFactory----- RenderersFactory renderersFactory = new DefaultRenderersFactory(this) { @Override protected void buildAudioRenderers(Context context, int extensionRendererMode, MediaCodecSelector mediaCodecSelector, @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager, boolean playClearSamplesWithoutKeys, boolean enableDecoderFallback, AudioProcessor[] audioProcessors, Handler eventHandler, AudioRendererEventListener eventListener, ArrayList<Renderer> out) { super.buildAudioRenderers(context, extensionRendererMode, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys, enableDecoderFallback, audioProcessors, eventHandler, eventListener, out); out.add(new AudioRendererWithoutClock(context, mediaCodecSelector)); out.add(new AudioRendererWithoutClock(context, mediaCodecSelector)); out.add(new AudioRendererWithoutClock(context, mediaCodecSelector)); } }; with the following class: private static final class AudioRendererWithoutClock extends MediaCodecAudioRenderer { public AudioRendererWithoutClock(Context context, MediaCodecSelector mediaCodecSelector) { super(context, mediaCodecSelector); } @Override public MediaClock getMediaClock() { return null; } } ---- TrackSelector ---- TrackSelector trackSelector = new TrackSelector() { @Override public TrackSelectorResult selectTracks(RendererCapabilities[] rendererCapabilities, TrackGroupArray trackGroups, MediaPeriodId periodId, Timeline timeline) throws ExoPlaybackException { Queue<Integer> audioRenderers = new ArrayDeque<>(); RendererConfiguration[] configs = new RendererConfiguration[rendererCapabilities.length]; TrackSelection[] selections = new TrackSelection[rendererCapabilities.length]; for (int i = 0; i < rendererCapabilities.length; i++) { if(rendererCapabilities[i].getTrackType() == C.TRACK_TYPE_AUDIO) { audioRenderers.add(i); configs[i] = RendererConfiguration.DEFAULT; } } for (int i = 0; i < trackGroups.length; i++) { if (MimeTypes.isAudio(trackGroups.get(i).getFormat(0).sampleMimeType)) { Integer index = audioRenderers.poll(); if (index != null) { selections[index] = new FixedTrackSelection(trackGroups.get(i), 0); } } } return new TrackSelectorResult(configs, selections, new Object()); } @Override public void onSelectionActivated(Object info) { } }; ---- Player ---- player = new SimpleExoPlayer.Builder(/* context= */ this, renderersFactory) .setTrackSelector(trackSelector) .build(); player.prepare(mediaSource);
Thank you I used your code but there is error in this section:
player =
new SimpleExoPlayer.Builder(/* context= */ this, renderersFactory)
.setTrackSelector(trackSelector)
.build();
In above code ".Builder" is red and show this message: " Cannot resolve symbol 'Builder' "
In my MediaSources: mediasource1 is video file mediasource2 , mediasource3 , mediasource4, mediasource5, mediasource6, mediasource7 are audio files
what should I do?
The builder is only available in the latest ExoPlayer version. You can use ExoPlayerFactory
instead where you can set your own track selector and renderers factory.
The builder is only available in the latest ExoPlayer version. You can use
ExoPlayerFactory
instead where you can set your own track selector and renderers factory.
Thank you for your sample code and your help
I used exoplayer with 2.10.7 version and its latest version of exoplayer. but show this message: " Cannot resolve symbol 'Builder' " again.
implementation 'com.google.android.exoplayer:exoplayer:2.10.7'
I solved this error with this code:
Player = ExoPlayerFactory.newSimpleInstance(this, renderersFactory, trackSelector);
with your code i can play multiple audio files but dont show video.
My code in media source dection:
Uri uri1 = Uri.parse(video_path);
Uri uri2 = Uri.parse(audio_path1);
Uri uri3 = Uri.parse(audio_path2);
Uri uri4 = Uri.parse(audio_path3);
MediaSource mediaSource1 = buildMediaSource(uri1);
MediaSource mediaSource2 = buildMediaSource(uri2);
MediaSource mediaSource3 = buildMediaSource(uri3);
MediaSource mediaSource4 = buildMediaSource(uri4);
MergingMediaSource mediaSource = new MergingMediaSource(mediaSource1, mediaSource2, mediaSource3, mediaSource4);
what should I do for play video with this audio files in same time?
I used exoplayer with 2.10.7 version and its latest version of exoplayer. but show this message: " Cannot resolve symbol 'Builder' " again.
Yes, sorry, this will only be part of 2.11.0 (once released). Your alternative is correct.
i can play multiple audio files but dont show video
As pointed out above, you also need to select the video track in the TrackSelector
implementation. Search for a renderer index that supports C.TRACK_TYPE_VIDEO
and find a track where MimeTypes.isVideo
returns true, and then create a new FixedTrackSelection
similar to what I've done with the audio tracks in my example.
Note that writing you own TrackSelector
is quite an advanced customization, so I won't dive any deeper with code examples.
complication of needing a custom TrackSelector
This turned out to be quite complicated and I'll use this issue to track an enhancement for DefaultTrackSelector
that allows selecting multiple renderers of the same type (e.g. multiple video outputs, multiple audio renderers, etc.). But it's low-priority for now.
I used exoplayer with 2.10.7 version and its latest version of exoplayer. but show this message: " Cannot resolve symbol 'Builder' " again.
Yes, sorry, this will only be part of 2.11.0 (once released). Your alternative is correct.
i can play multiple audio files but dont show video
As pointed out above, you also need to select the video track in the
TrackSelector
implementation. Search for a renderer index that supportsC.TRACK_TYPE_VIDEO
and find a track whereMimeTypes.isVideo
returns true, and then create a newFixedTrackSelection
similar to what I've done with the audio tracks in my example.Note that writing you own
TrackSelector
is quite an advanced customization, so I won't dive any deeper with code examples.complication of needing a custom TrackSelector
This turned out to be quite complicated and I'll use this issue to track an enhancement for
DefaultTrackSelector
that allows selecting multiple renderers of the same type (e.g. multiple video outputs, multiple audio renderers, etc.). But it's low-priority for now.
Thanks my friend I searched in internet and use alot of ways with your sample code but dont work for me Can you send me sample code for play a video with 4 or 6 audio files simultaneously.
Thanks
I used exoplayer with 2.10.7 version and its latest version of exoplayer. but show this message: " Cannot resolve symbol 'Builder' " again.
Yes, sorry, this will only be part of 2.11.0 (once released). Your alternative is correct.
i can play multiple audio files but dont show video
As pointed out above, you also need to select the video track in the
TrackSelector
implementation. Search for a renderer index that supportsC.TRACK_TYPE_VIDEO
and find a track whereMimeTypes.isVideo
returns true, and then create a newFixedTrackSelection
similar to what I've done with the audio tracks in my example.Note that writing you own
TrackSelector
is quite an advanced customization, so I won't dive any deeper with code examples.complication of needing a custom TrackSelector
This turned out to be quite complicated and I'll use this issue to track an enhancement for
DefaultTrackSelector
that allows selecting multiple renderers of the same type (e.g. multiple video outputs, multiple audio renderers, etc.). But it's low-priority for now.
Thank you
I found my answer with your help
But i want change my mediaSources in every play dynamically.
For example:
I want in every play Exoplayer, add or remove one or more mediaSource in this code:
MergingMediaSource mediaSource = new MergingMediaSource(mediaSource1, mediaSource2, mediaSource3, mediaSource4);
I want change and play exoplayer again without exit activity and release exoplayer.
i just added C.TRACK_TYPE_VIDEO
TrackSelector trackSelector1 = new TrackSelector() {
@Override
public TrackSelectorResult selectTracks(RendererCapabilities[] rendererCapabilities,
TrackGroupArray trackGroups, MediaSource.MediaPeriodId periodId, Timeline timeline)
throws ExoPlaybackException {
Queue
@Override
public void onSelectionActivated(Object info) {
}
};
and problem solved audio and video working properly fine without black screen
The way I described above seems to work with the added complication of needing a custom
TrackSelector
implementation that links tracks to audio renderers. Please note that the renderers are not actively synchronized to each other, so depending on your alignment requirements between these streams, this may be a problem. You will also need to select the video track in the track selector if you want to enable it. Code I used for testing:-----MediaSource----- mediaSource = new MergingMediaSource(source1, ..., source4); ----RendersFactory----- RenderersFactory renderersFactory = new DefaultRenderersFactory(this) { @Override protected void buildAudioRenderers(Context context, int extensionRendererMode, MediaCodecSelector mediaCodecSelector, @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager, boolean playClearSamplesWithoutKeys, boolean enableDecoderFallback, AudioProcessor[] audioProcessors, Handler eventHandler, AudioRendererEventListener eventListener, ArrayList<Renderer> out) { super.buildAudioRenderers(context, extensionRendererMode, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys, enableDecoderFallback, audioProcessors, eventHandler, eventListener, out); out.add(new AudioRendererWithoutClock(context, mediaCodecSelector)); out.add(new AudioRendererWithoutClock(context, mediaCodecSelector)); out.add(new AudioRendererWithoutClock(context, mediaCodecSelector)); } }; with the following class: private static final class AudioRendererWithoutClock extends MediaCodecAudioRenderer { public AudioRendererWithoutClock(Context context, MediaCodecSelector mediaCodecSelector) { super(context, mediaCodecSelector); } @Override public MediaClock getMediaClock() { return null; } } ---- TrackSelector ---- TrackSelector trackSelector = new TrackSelector() { @Override public TrackSelectorResult selectTracks(RendererCapabilities[] rendererCapabilities, TrackGroupArray trackGroups, MediaPeriodId periodId, Timeline timeline) throws ExoPlaybackException { Queue<Integer> audioRenderers = new ArrayDeque<>(); RendererConfiguration[] configs = new RendererConfiguration[rendererCapabilities.length]; TrackSelection[] selections = new TrackSelection[rendererCapabilities.length]; for (int i = 0; i < rendererCapabilities.length; i++) { if(rendererCapabilities[i].getTrackType() == C.TRACK_TYPE_AUDIO) { audioRenderers.add(i); configs[i] = RendererConfiguration.DEFAULT; } } for (int i = 0; i < trackGroups.length; i++) { if (MimeTypes.isAudio(trackGroups.get(i).getFormat(0).sampleMimeType)) { Integer index = audioRenderers.poll(); if (index != null) { selections[index] = new FixedTrackSelection(trackGroups.get(i), 0); } } } return new TrackSelectorResult(configs, selections, new Object()); } @Override public void onSelectionActivated(Object info) { } }; ---- Player ---- player = new SimpleExoPlayer.Builder(/* context= */ this, renderersFactory) .setTrackSelector(trackSelector) .build(); player.prepare(mediaSource);
Thank you I used your code but there is error in this section:
player = new SimpleExoPlayer.Builder(/* context= */ this, renderersFactory) .setTrackSelector(trackSelector) .build();
In above code ".Builder" is red and show this message: " Cannot resolve symbol 'Builder' "
In my MediaSources: mediasource1 is video file mediasource2 , mediasource3 , mediasource4, mediasource5, mediasource6, mediasource7 are audio files
what should I do?
Can I switch between the video track and the audio track?
I had the same code suggested here in order to play multiple tracks at the same time. But now after updating to ExoPlayer 2.17, it stopped working. The following is the error I can see:
E/ExoPlayerImplInternal: Playback error
com.google.android.exoplayer2.ExoPlaybackException: Unexpected runtime error
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:624)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:237)
at android.os.HandlerThread.run(HandlerThread.java:67)
Caused by: java.lang.IllegalStateException
at com.google.android.exoplayer2.util.Assertions.checkState(Assertions.java:84)
at com.google.android.exoplayer2.source.ProgressiveMediaPeriod.selectTracks(ProgressiveMediaPeriod.java:283)
at com.google.android.exoplayer2.source.MergingMediaPeriod.selectTracks(MergingMediaPeriod.java:153)
at com.google.android.exoplayer2.source.MaskingMediaPeriod.selectTracks(MaskingMediaPeriod.java:186)
at com.google.android.exoplayer2.MediaPeriodHolder.applyTrackSelection(MediaPeriodHolder.java:296)
at com.google.android.exoplayer2.MediaPeriodHolder.applyTrackSelection(MediaPeriodHolder.java:259)
at com.google.android.exoplayer2.MediaPeriodHolder.handlePrepared(MediaPeriodHolder.java:193)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handlePeriodPrepared(ExoPlayerImplInternal.java:2247)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:517)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:237)
at android.os.HandlerThread.run(HandlerThread.java:67)
Any suggestions on what can be causing this and if there's a quick fix?
Thanks
ในวันที่ พฤ. 10 มี.ค. 2022 10:54 น. ziad-halabi9 @.***> เขียนว่า:
I had the same code suggested here in order to play multiple tracks at the same time. But now after updating to ExoPlayer 2.17, it stopped working. The following is the error I can see:
E/ExoPlayerImplInternal: Playback error
com.google.android.exoplayer2.ExoPlaybackException: Unexpected runtime error at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:624) at android.os.Handler.dispatchMessage(Handler.java:103) at android.os.Looper.loop(Looper.java:237) at android.os.HandlerThread.run(HandlerThread.java:67) Caused by: java.lang.IllegalStateException at com.google.android.exoplayer2.util.Assertions.checkState(Assertions.java:84) at com.google.android.exoplayer2.source.ProgressiveMediaPeriod.selectTracks(ProgressiveMediaPeriod.java:283) at com.google.android.exoplayer2.source.MergingMediaPeriod.selectTracks(MergingMediaPeriod.java:153) at com.google.android.exoplayer2.source.MaskingMediaPeriod.selectTracks(MaskingMediaPeriod.java:186) at com.google.android.exoplayer2.MediaPeriodHolder.applyTrackSelection(MediaPeriodHolder.java:296) at com.google.android.exoplayer2.MediaPeriodHolder.applyTrackSelection(MediaPeriodHolder.java:259) at com.google.android.exoplayer2.MediaPeriodHolder.handlePrepared(MediaPeriodHolder.java:193) at com.google.android.exoplayer2.ExoPlayerImplInternal.handlePeriodPrepared(ExoPlayerImplInternal.java:2247) at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:517) at android.os.Handler.dispatchMessage(Handler.java:103) at android.os.Looper.loop(Looper.java:237) at android.os.HandlerThread.run(HandlerThread.java:67)
Any suggestions on what can be causing this and if there's a quick fix?
— Reply to this email directly, view it on GitHub https://github.com/google/ExoPlayer/issues/6589#issuecomment-1064210292, or unsubscribe https://github.com/notifications/unsubscribe-auth/AWY6HDK3XGTR67ZSANJGR33U7ILMNANCNFSM4JFSEOEA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
You are receiving this because you are subscribed to this thread.Message ID: @.***>
E/ExoPlayerImplInternal: Playback error com.google.android.exoplayer2.ExoPlaybackException: Unexpected runtime error at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:624) at android.os.Handler.dispatchMessage(Handler.java:103) at android.os.Looper.loop(Looper.java:237) at android.os.HandlerThread.run(HandlerThread.java:67) Caused by: java.lang.IllegalStateException at com.google.android.exoplayer2.util.Assertions.checkState(Assertions.java:84) at com.google.android.exoplayer2.source.ProgressiveMediaPeriod.selectTracks(ProgressiveMediaPeriod.java:283) at com.google.android.exoplayer2.source.MergingMediaPeriod.selectTracks(MergingMediaPeriod.java:153) at com.google.android.exoplayer2.source.MaskingMediaPeriod.selectTracks(MaskingMediaPeriod.java:186) at com.google.android.exoplayer2.MediaPeriodHolder.applyTrackSelection(MediaPeriodHolder.java:296) at com.google.android.exoplayer2.MediaPeriodHolder.applyTrackSelection(MediaPeriodHolder.java:259) at com.google.android.exoplayer2.MediaPeriodHolder.handlePrepared(MediaPeriodHolder.java:193) at com.google.android.exoplayer2.ExoPlayerImplInternal.handlePeriodPrepared(ExoPlayerImplInternal.java:2247) at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:517) at android.os.Handler.dispatchMessage(Handler.java:103) at android.os.Looper.loop(Looper.java:237) at android.os.HandlerThread.run(HandlerThread.java:67)
ขอคำชี้แจง
I want play multi sound in same time(simultaneously) in exoplayer but it only play mediaSource1 and mediaSource2. I want play all mediaSources at the same time(simultaneously)
My code with exoplayer is:
please help me thanks