I need help with playing multiple audio tracks at the same time in Android
.
我需要在Android系统中同时播放多个音轨的帮助。
I am supposed to play three audio tracks at the exact same time using Android.Media.MediaPlayer
.
我应该使用android . mediaplayer同时播放三段音轨。
Yesterday I managed to make it work doing so :
昨天我成功地做到了:
MediaPlayer track1 = MediaPlayer.create(this, R.raw.track1);
MediaPlayer track2 = MediaPlayer.create(this, R.raw.track2);
MediaPlayer track3 = MediaPlayer.create(this, R.raw.track3);
As you can see, I have three distincts instances of MediaPlaye
r here.
如您所见,我在这里有三个不同的MediaPlayer实例。
Because I am asked to, I need to have these MediaPlayer
being played in a background thread.
因为我被要求,我需要在后台线程中播放这些MediaPlayer。
Here is the part where I start the MediaPlayers
:
这是我开始MediaPlayers的部分:
//let's suppose this code snippet is in a run() method inside a Thread (which is the case)
track1.start();
track2.start();
track3.start();
If I say yesterday, it's because the next day, it did not work as supposed to.
如果我说昨天,那是因为第二天,它并没有像我想象的那样工作。
Indeed, starting a MediaPlayer seems to stop any previous playing MediaPlayer.
实际上,启动MediaPlayer似乎会停止之前的任何MediaPlayer。
I tested in debugger mode : clearly, track2.start()
stops track1's MediaPlayer and following the same pattern, track3.start()
stops tack2's MediaPlayer.
我在调试模式中进行了测试:显然,track2.start()停止了track1的MediaPlayer,并且遵循相同的模式,track3.start()停止了拦截2的MediaPlayer。
So at the end, only track3 is being played, I cannot hear any of the previous tracks, whatever the volume settings are whereas I could cleary hear all of them before : it is supposed to create some sort an ambiance.
所以在最后,只有track3在播放,我听不到任何先前的音轨,无论音量设置是什么,而我可以清晰地听到所有的音轨:它应该创造某种氛围。
Of course, changing the order in which the tracks are started does not change anything : only the last track will be heard.
当然,改变轨道开始的顺序不会改变任何事情:只有最后一个轨道会被听到。
If I say "heard" it is because in debugger mode, checking the property MediaPlayer.isPlaying
is returning true
: all three players are saying they are playing but only one can be heard... !
如果我说“听见”是因为在调试器模式下,检查属性MediaPlayer。我的梦想成真了:三名球员都说他们在比赛,但只有一名球员能被听到……!
Why the change ? Why did it work once to stop working afterwards ?
为什么改变?为什么它会在之后停止工作?
NOTE:
注意:
- the audio files have all the same duration which is approximately about 15 minutes
- 音频文件的持续时间相同,大约15分钟
- the audio files were
.mp3
files compressed into.acc
files (from320kbps
to144kbps
) - 音频文件是.mp3文件压缩成.acc文件(从320kbps到144kbps)
- I am working under
Xamarin Studio
inC#
but for clarety purpouse I will stick to smallJava
code snippets. - 我在c#的Xamarin工作室工作,但是对于clarety purpouse,我将坚持使用小的Java代码片段。
EDIT 1
编辑1
According to this Play two mp3 song at the same time my solution should be working, right ?
根据这首歌的播放情况,我的解决方案应该是可行的,对吗?
5 个解决方案
#1
8
I achieved what you're looking for using a CyclicBarrier instance and an inner class implementation.
我实现了您所期望的使用循环屏障实例和内部类实现。
Example:
例子:
public enum MP_COMMAND {
START,
STOP,
PAUSE
}
/**
* Uses threads to execute synced commands for the current video media player and
* background music player in tandem.
*/
public void syncedCommand(MediaPlayer player1, MediaPlayer player2, MP_COMMAND command) {
final CyclicBarrier commandBarrier = new CyclicBarrier(2);
new Thread(new SyncedCommandService(commandBarrier, player1, command)).start();
new Thread(new SyncedCommandService(commandBarrier, player2, command)).start();
}
/**
* Inner class that starts a given media player synchronously
* with other threads utilizing SyncedStartService
*/
private class SyncedCommandService implements Runnable {
private final CyclicBarrier mCommandBarrier;
private MediaPlayerTest.MP_COMMAND mCommand;
private MediaPlayer mMediaPlayer;
public SyncedCommandService(CyclicBarrier barrier, MediaPlayer player, MediaPlayerTest.MP_COMMAND command) {
mCommandBarrier = barrier;
mMediaPlayer = player;
mCommand = command;
}
@Override public void run() {
try {
mCommandBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
switch (mCommand) {
case START:
mMediaPlayer.start();
break;
case STOP:
mMediaPlayer.stop();
break;
case PAUSE:
mMediaPlayer.pause();
break;
default:
break;
}
}
}
You'd utilize it like so:
你可以这样利用它:
syncedCommand(mCurrentVideoPlayer, mBackgroundMusic, MP_COMMAND.START);
If you had the requirement that it be usable for any number of media players, you could easily implement it - my requirements just call for two.
如果您要求它对任意数量的媒体播放器都可用,那么您可以轻松地实现它——我的要求是只需要两个。
I realize this question is old, but this page is where I found myself while searching for a solution, so I hope this helps anyone stuck on this issue in the future.
我意识到这个问题已经过时了,但是这个页面是我在寻找解决方案的时候发现的,所以我希望这能帮助在未来遇到这个问题的人。
#2
2
Well, I believe I found what I could name "a temporary solution".
嗯,我相信我找到了一种我可以称之为“临时解决方案”的方法。
MediaPlayer track1 = MediaPlayer.create(this, R.raw.track1);
track1.start();
MediaPlayer track2 = MediaPlayer.create(this, R.raw.track2);
track2.start();
MediaPlayer track3 = MediaPlayer.create(this, R.raw.track3);
track3.start();
The problem with this is that the create()
method creates a noticeable gap when the songs are being played.
这样做的问题是create()方法在播放歌曲时产生了一个明显的空白。
So this is not it.
所以这不是它。
After a while, I tried the following :
过了一会儿,我尝试了以下方法:
MediaPlayer track1 = MediaPlayer.create(this, R.raw.track1);
track1.start();
track1.pause();
MediaPlayer track2 = MediaPlayer.create(this, R.raw.track2);
track2.start();
track2.pause();
MediaPlayer track3 = MediaPlayer.create(this, R.raw.track3);
track3.start();
track3.pause();
// resuming...
track1.start();
track2.start();
track3.start();
That whay, the songs are more synchronous. I can still hear a very small gap but it is way better. I found this solution quite strange as well as ugly.
无论如何,歌曲更同步。我仍然能听到一个很小的差距,但它要好得多。我发现这个解决方案既奇怪又丑陋。
Unless someone has another idea, I will stick with that solution.
除非有人有别的想法,否则我将坚持这个解决方案。
#3
1
As Andrey Nikishaev already wrote in a comment, it seems like some devices have problems using multiple MediaPlayers at the same time. While only one was playing on my Nexus 5, it worked on my Moto G4 (but still having short breaks during playback). Both running with Android 6.0.1.
正如Andrey Nikishaev在评论中所写的,似乎有些设备同时使用多个mediaplayer有问题。当只有一个人在我的Nexus 5上玩时,它在我的Moto G4上工作(但在回放时仍然有短暂的休息)。两者都运行Android 6.0.1。
I suggest to use the ExoPlayer for this use-case instead. It worked fine for me, at least on my two devices.
我建议在这个用例中使用ExoPlayer。至少在我的两个设备上,它对我来说还不错。
#4
0
I converted my mp3 in ogg file audio (using Audacity) and I am been able to use 2 Mediaplayer istances and listen the audio mixed.
我在ogg文件音频中转换了我的mp3(使用Audacity),我能够使用两个Mediaplayer istance并听混合的音频。
I didn't try is it is possible for more than 3.
我没试过是否有可能超过3个。
#5
0
hi try below code it will work it the song wont stop you just need to select the song from spinner and click on start button, then select next song from spinner and click start it will work.
嗨,试试下面的代码它会工作的歌曲不会停止你只需要从spinner中选择歌曲然后点击开始按钮,然后从spinner中选择next歌曲然后点击开始它就会工作。
public class MainActivity extends AppCompatActivity {
Spinner sp;
Button bstart;
MediaPlayer mp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sp=(Spinner)findViewById(R.id.sp);
String [] mys={"demo","democheap","demorehana"};
ArrayAdapter<String> data=new ArrayAdapter<String>(this,R.layout.support_simple_spinner_dropdown_item,mys);
sp.setAdapter(data);
}
public void code(View v)
{
if(sp.getSelectedItem().toString().equals("demo"))
{
mp=MediaPlayer.create(this,R.raw.demo);
}
else if(sp.getSelectedItem().toString().equals("democheap"))
{
mp=MediaPlayer.create(this,R.raw.democheap);
}
else if(sp.getSelectedItem().toString().equals("demorehana"))
{
mp=MediaPlayer.create(this,R.raw.demorehana);
}
if(v.getId()==R.id.bstart)
{
mp.start();
}
}
}
#1
8
I achieved what you're looking for using a CyclicBarrier instance and an inner class implementation.
我实现了您所期望的使用循环屏障实例和内部类实现。
Example:
例子:
public enum MP_COMMAND {
START,
STOP,
PAUSE
}
/**
* Uses threads to execute synced commands for the current video media player and
* background music player in tandem.
*/
public void syncedCommand(MediaPlayer player1, MediaPlayer player2, MP_COMMAND command) {
final CyclicBarrier commandBarrier = new CyclicBarrier(2);
new Thread(new SyncedCommandService(commandBarrier, player1, command)).start();
new Thread(new SyncedCommandService(commandBarrier, player2, command)).start();
}
/**
* Inner class that starts a given media player synchronously
* with other threads utilizing SyncedStartService
*/
private class SyncedCommandService implements Runnable {
private final CyclicBarrier mCommandBarrier;
private MediaPlayerTest.MP_COMMAND mCommand;
private MediaPlayer mMediaPlayer;
public SyncedCommandService(CyclicBarrier barrier, MediaPlayer player, MediaPlayerTest.MP_COMMAND command) {
mCommandBarrier = barrier;
mMediaPlayer = player;
mCommand = command;
}
@Override public void run() {
try {
mCommandBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
switch (mCommand) {
case START:
mMediaPlayer.start();
break;
case STOP:
mMediaPlayer.stop();
break;
case PAUSE:
mMediaPlayer.pause();
break;
default:
break;
}
}
}
You'd utilize it like so:
你可以这样利用它:
syncedCommand(mCurrentVideoPlayer, mBackgroundMusic, MP_COMMAND.START);
If you had the requirement that it be usable for any number of media players, you could easily implement it - my requirements just call for two.
如果您要求它对任意数量的媒体播放器都可用,那么您可以轻松地实现它——我的要求是只需要两个。
I realize this question is old, but this page is where I found myself while searching for a solution, so I hope this helps anyone stuck on this issue in the future.
我意识到这个问题已经过时了,但是这个页面是我在寻找解决方案的时候发现的,所以我希望这能帮助在未来遇到这个问题的人。
#2
2
Well, I believe I found what I could name "a temporary solution".
嗯,我相信我找到了一种我可以称之为“临时解决方案”的方法。
MediaPlayer track1 = MediaPlayer.create(this, R.raw.track1);
track1.start();
MediaPlayer track2 = MediaPlayer.create(this, R.raw.track2);
track2.start();
MediaPlayer track3 = MediaPlayer.create(this, R.raw.track3);
track3.start();
The problem with this is that the create()
method creates a noticeable gap when the songs are being played.
这样做的问题是create()方法在播放歌曲时产生了一个明显的空白。
So this is not it.
所以这不是它。
After a while, I tried the following :
过了一会儿,我尝试了以下方法:
MediaPlayer track1 = MediaPlayer.create(this, R.raw.track1);
track1.start();
track1.pause();
MediaPlayer track2 = MediaPlayer.create(this, R.raw.track2);
track2.start();
track2.pause();
MediaPlayer track3 = MediaPlayer.create(this, R.raw.track3);
track3.start();
track3.pause();
// resuming...
track1.start();
track2.start();
track3.start();
That whay, the songs are more synchronous. I can still hear a very small gap but it is way better. I found this solution quite strange as well as ugly.
无论如何,歌曲更同步。我仍然能听到一个很小的差距,但它要好得多。我发现这个解决方案既奇怪又丑陋。
Unless someone has another idea, I will stick with that solution.
除非有人有别的想法,否则我将坚持这个解决方案。
#3
1
As Andrey Nikishaev already wrote in a comment, it seems like some devices have problems using multiple MediaPlayers at the same time. While only one was playing on my Nexus 5, it worked on my Moto G4 (but still having short breaks during playback). Both running with Android 6.0.1.
正如Andrey Nikishaev在评论中所写的,似乎有些设备同时使用多个mediaplayer有问题。当只有一个人在我的Nexus 5上玩时,它在我的Moto G4上工作(但在回放时仍然有短暂的休息)。两者都运行Android 6.0.1。
I suggest to use the ExoPlayer for this use-case instead. It worked fine for me, at least on my two devices.
我建议在这个用例中使用ExoPlayer。至少在我的两个设备上,它对我来说还不错。
#4
0
I converted my mp3 in ogg file audio (using Audacity) and I am been able to use 2 Mediaplayer istances and listen the audio mixed.
我在ogg文件音频中转换了我的mp3(使用Audacity),我能够使用两个Mediaplayer istance并听混合的音频。
I didn't try is it is possible for more than 3.
我没试过是否有可能超过3个。
#5
0
hi try below code it will work it the song wont stop you just need to select the song from spinner and click on start button, then select next song from spinner and click start it will work.
嗨,试试下面的代码它会工作的歌曲不会停止你只需要从spinner中选择歌曲然后点击开始按钮,然后从spinner中选择next歌曲然后点击开始它就会工作。
public class MainActivity extends AppCompatActivity {
Spinner sp;
Button bstart;
MediaPlayer mp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sp=(Spinner)findViewById(R.id.sp);
String [] mys={"demo","democheap","demorehana"};
ArrayAdapter<String> data=new ArrayAdapter<String>(this,R.layout.support_simple_spinner_dropdown_item,mys);
sp.setAdapter(data);
}
public void code(View v)
{
if(sp.getSelectedItem().toString().equals("demo"))
{
mp=MediaPlayer.create(this,R.raw.demo);
}
else if(sp.getSelectedItem().toString().equals("democheap"))
{
mp=MediaPlayer.create(this,R.raw.democheap);
}
else if(sp.getSelectedItem().toString().equals("demorehana"))
{
mp=MediaPlayer.create(this,R.raw.demorehana);
}
if(v.getId()==R.id.bstart)
{
mp.start();
}
}
}