目前无法在Android上实现无间隙音频循环
我尝试了几乎所有的方法,但我没能在循环10-15秒的单曲之间实现无间隙音频播放 我尝试过但失败的步骤:目前无法在Android上实现无间隙音频循环,android,android-audiomanager,Android,Android Audiomanager,我尝试了几乎所有的方法,但我没能在循环10-15秒的单曲之间实现无间隙音频播放 我尝试过但失败的步骤: 使用不同的音频文件格式.mp3.wav.ogg 设置循环(true): 创建两个MediaPlayer并使用 setOnCompletionListenersame未能无间隙循环 使用setNextMediaPlayer(nextmp)。在完成前两个循环后,我们必须准备并重新开始 mp1.start(); mp1.setNextMediaPlayer(mp2); 更新: @Jeff Mi
.mp3
.wav
.ogg
设置循环(true)
:
setOnCompletionListener
same未能无间隙循环setNextMediaPlayer(nextmp)
。在完成前两个循环后,我们必须准备并重新开始
mp1.start();
mp1.setNextMediaPlayer(mp2);
E/MediaPlayer(24311): error (1, -38)
E/MediaPlayer(23256): Error(1,-1007)
E/MediaPlayer(23546): Error (1,-2147483648)
难看的概念验证代码,但你会明白:
// Will need this in the callbacks
final AssetFileDescriptor afd = getResources().openRawResourceFd(R.raw.sample);
// Build and start first player
final MediaPlayer player1 = MediaPlayer.create(this, R.raw.sample);
player1.start();
// Ready second player
final MediaPlayer player2 = MediaPlayer.create(this, R.raw.sample);
player1.setNextMediaPlayer(player2);
player1.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
// When player1 completes, we reset it, and set up player2 to go back to player1 when it's done
mediaPlayer.reset();
try {
mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
mediaPlayer.prepare();
} catch (Exception e) {
e.printStackTrace();
}
player2.setNextMediaPlayer(player1);
}
});
player2.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
// Likewise, when player2 completes, we reset it and tell it player1 to user player2 after it's finished again
mediaPlayer.reset();
try {
mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
mediaPlayer.prepare();
} catch (Exception e) {
e.printStackTrace();
}
player1.setNextMediaPlayer(player2);
}
});
// This loop repeats itself endlessly in this fashion without gaps
这在API 19设备和5秒128Kbps MP3上对我很有效。循环中没有间隙。类似的方法应该可以工作。在res.raw目录中保留同一文件的两个副本。请注意,这只是一个POC,而不是一个优化的代码。我刚刚测试了这个,它正在按预期工作。让我知道你的想法
public class MainActivity extends Activity {
MediaPlayer mp1;
MediaPlayer mp2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mp1 = MediaPlayer.create(MainActivity.this, R.raw.demo);
mp2 = MediaPlayer.create(MainActivity.this, R.raw.demo2);
mp1.start();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
int duration = mp1.getDuration();
while (mp1.isPlaying() || mp2.isPlaying()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
duration = duration - 100;
if (duration < 1000) {
if (mp1.isPlaying()) {
mp2.start();
mp1.reset();
mp1 = MediaPlayer.create(MainActivity.this,
R.raw.demo);
duration = mp2.getDuration();
} else {
mp1.start();
mp2.reset();
mp2 = MediaPlayer.create(MainActivity.this,
R.raw.demo2);
duration = mp1.getDuration();
}
}
}
}
});
thread.start();
}
}
公共类MainActivity扩展活动{
MediaPlayer mp1;
MediaPlayer mp2;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mp1=MediaPlayer.create(MainActivity.this,R.raw.demo);
mp2=MediaPlayer.create(MainActivity.this,R.raw.demo2);
mp1.start();
Thread Thread=新线程(new Runnable(){
@凌驾
公开募捐{
int duration=mp1.getDuration();
而(mp1.isplay()| | mp2.isplay()){
试一试{
睡眠(100);
}捕捉(中断异常e){
e、 printStackTrace();
}
持续时间=持续时间-100;
如果(持续时间<1000){
if(mp1.isPlaying()){
mp2.start();
mp1.reset();
mp1=MediaPlayer.create(MainActivity.this,
R.raw.demo);
duration=mp2.getDuration();
}否则{
mp1.start();
mp2.reset();
mp2=MediaPlayer.create(MainActivity.this,
R.raw.demo2);
duration=mp1.getDuration();
}
}
}
}
});
thread.start();
}
}
我建议您使用API而不是MediaPlayer
从官方文件:
SoundPool类管理和播放音频资源
应用程序
可以通过设置非零循环来循环声音
价值值-1会导致声音永远循环。在这种情况下,,
应用程序必须显式调用stop()函数来停止
声音。任何其他非零值都会导致声音重复
指定的次数,例如,值为3会使声音播放
总共4次
通过我所做的测试,查看如何使用
声音池的实际示例,此解决方案运行良好,超过150个循环,13秒160 kbps MP3,没有任何问题:
public class LoopMediaPlayer {
public static final String TAG = LoopMediaPlayer.class.getSimpleName();
private Context mContext = null;
private int mResId = 0;
private int mCounter = 1;
private MediaPlayer mCurrentPlayer = null;
private MediaPlayer mNextPlayer = null;
public static LoopMediaPlayer create(Context context, int resId) {
return new LoopMediaPlayer(context, resId);
}
private LoopMediaPlayer(Context context, int resId) {
mContext = context;
mResId = resId;
mCurrentPlayer = MediaPlayer.create(mContext, mResId);
mCurrentPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mCurrentPlayer.start();
}
});
createNextMediaPlayer();
}
private void createNextMediaPlayer() {
mNextPlayer = MediaPlayer.create(mContext, mResId);
mCurrentPlayer.setNextMediaPlayer(mNextPlayer);
mCurrentPlayer.setOnCompletionListener(onCompletionListener);
}
private MediaPlayer.OnCompletionListener onCompletionListener = new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
mediaPlayer.release();
mCurrentPlayer = mNextPlayer;
createNextMediaPlayer();
Log.d(TAG, String.format("Loop #%d", ++mCounter));
}
};
}
要使用LoopMediaPlayer,只需调用:
LoopMediaPlayer.create(context, R.raw.sample);
至少到了KitKat,(对于这个问题)是我发现的唯一一个允许大(>1Mb未压缩)音频样本无间隙循环的解决方案。我试过:
- .setLooping(true):即使使用经过完美修剪的.WAV示例(),也会产生交替循环噪声或暂停李>
- :无帧格式,因此比MP3更好,但MediaPlayer仍会发出交替播放的效果;及
- :可能适用于小的声音样本,但是
只需在我的项目中包含Maestrini的LoopMediaPlayer
类,然后将我的MediaPlayer.create()
调用替换为LoopMediaPlayer.create()
调用,我就可以确保.OGG示例无缝循环<因此,code>LoopMediaPlayer
是一个非常实用和透明的解决方案
但这种透明性回避了一个问题:一旦我将我的MediaPlayer
调用交换为LoopMediaPlayer
调用,我的实例如何调用MediaPlayer
方法,例如。isPlaying
、.pause
或setVolume
下面是我对此问题的解决方案。也许比我更精通Java的人可以改进它(我欢迎他们的意见),但到目前为止,我发现这是一个可靠的解决方案
我对Maestrini的类所做的唯一更改(除了Lint建议的一些调整)如下代码末尾所示;其余的我都包含在上下文中。我的新增功能是在LoopMediaPlayer
中通过调用mCurrentPlayer
实现MediaPlayer
的几种方法
警告:虽然我实现了下面的MediaPlayer
的几种有用方法,但我并没有实现所有这些方法。因此,如果您希望调用。attachauxeeffect
,您需要按照我添加的内容,自己将其作为方法添加到LoopMediaPlayer
。确保复制这些方法的原始接口(即参数、抛出和返回):
出于某种原因,我发现我的“OnCompletion”事件在尝试循环8秒时总是在晚些时候触发一小部分秒
LoopMediaPlayer.create(context, R.raw.sample);
public class LoopMediaPlayer {
private static final String TAG = LoopMediaPlayer.class.getSimpleName();
private Context mContext = null;
private int mResId = 0;
private int mCounter = 1;
private MediaPlayer mCurrentPlayer = null;
private MediaPlayer mNextPlayer = null;
public static LoopMediaPlayer create(Context context, int resId) {
return new LoopMediaPlayer(context, resId);
}
private LoopMediaPlayer(Context context, int resId) {
mContext = context;
mResId = resId;
mCurrentPlayer = MediaPlayer.create(mContext, mResId);
mCurrentPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mCurrentPlayer.start();
}
});
createNextMediaPlayer();
}
private void createNextMediaPlayer() {
mNextPlayer = MediaPlayer.create(mContext, mResId);
mCurrentPlayer.setNextMediaPlayer(mNextPlayer);
mCurrentPlayer.setOnCompletionListener(onCompletionListener);
}
private final MediaPlayer.OnCompletionListener onCompletionListener = new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
mediaPlayer.release();
mCurrentPlayer = mNextPlayer;
createNextMediaPlayer();
Log.d(TAG, String.format("Loop #%d", ++mCounter));
}
};
// code-read additions:
public boolean isPlaying() throws IllegalStateException {
return mCurrentPlayer.isPlaying();
}
public void setVolume(float leftVolume, float rightVolume) {
mCurrentPlayer.setVolume(leftVolume, rightVolume);
}
public void start() throws IllegalStateException {
mCurrentPlayer.start();
}
public void stop() throws IllegalStateException {
mCurrentPlayer.stop();
}
public void pause() throws IllegalStateException {
mCurrentPlayer.pause();
}
public void release() {
mCurrentPlayer.release();
mNextPlayer.release();
}
public void reset() {
mCurrentPlayer.reset();
}
}
private HandlerThread SongLooperThread = new HandlerThread("SongLooperThread");
private Handler SongLooperHandler;
public void startSongLooperThread(){
SongLooperThread.start();
Looper looper = SongLooperThread.getLooper();
SongLooperHandler = new Handler(looper){
@Override
public void handleMessage(Message msg){
//do whatever...
}
}
}
public void stopSongLooperThread(){
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2){
SongLooperThread.quit();
} else {
SongLooperThread.quitSafely();
}
}`
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
startSongLooperThread();
activeSongResID = R.raw.some_loop;
activeMP = MediaPlayer.create(getApplicationContext(), activeSongResID);
activeSongMilliseconds = activeMP.getDuration();
queuedMP = MediaPlayer.create(getApplicationContext(),activeSongResID);
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
stopSongLooperThread();
activeMP.release();
queuedMP.release();
activeMP = null;
queuedMP = null;
}
private void swapActivePlayers(){
Log.v("SongLooperService","MediaPlayer swap started....");
queuedMP.start();
//Immediately get the Duration of the current track, then queue the next swap.
activeSongMilliseconds = queuedMP.getDuration();
SongLooperHandler.postDelayed(timedQueue,activeSongMilliseconds);
Log.v("SongLooperService","Next call queued...");
activeMP.release();
//Swap your active and queued MPs...
Log.v("SongLooperService","MediaPlayers swapping....");
MediaPlayer temp = activeMP;
activeMP = queuedMP;
queuedMP = temp;
//Prepare your now invalid queuedMP...
queuedMP = MediaPlayer.create(getApplicationContext(),activeSongResID);
Log.v("SongLooperService","MediaPlayer swapped.");
}
private Runnable startMP = new Runnable(){
public void run(){
activeMP.start();
SongLooperHandler.postDelayed(timedQueue,activeSongMilliseconds);
}
};
private Runnable timedQueue = new Runnable(){
public void run(){
swapActivePlayers();
}
};
...
SongLooperHandler.post(startMP);
...
Uri.parse("file:///android_asset/" + path)
public class LoopMediaPlayer {
private static final String TAG = LoopMediaPlayer.class.getSimpleName();
private Context mContext = null;
private int mResId = 0;
private int mCounter = 1;
private AssetFileDescriptor mAfd = null;
private File mFile = null;
private MediaPlayer mCurrentPlayer = null;
private MediaPlayer mNextPlayer = null;
public static LoopMediaPlayer create(Context context, int resId) {
return new LoopMediaPlayer(context, resId);
}
public LoopMediaPlayer(Context context, File file){
mContext = context;
mFile = file;
try {
mCurrentPlayer = new MediaPlayer();
mCurrentPlayer.setLooping(false);
mCurrentPlayer.setDataSource(file.getAbsolutePath());
mCurrentPlayer.prepareAsync();
mCurrentPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mCurrentPlayer.start();
mCurrentPlayer.setOnCompletionListener(onCompletionListener);
createNextMediaPlayer();
}
});
} catch (Exception e) {
Log.e("media", e.getLocalizedMessage());
}
}
public LoopMediaPlayer(Context context, AssetFileDescriptor afd){
mAfd = afd;
mContext = context;
try {
mCurrentPlayer = new MediaPlayer();
mCurrentPlayer.setLooping(false);
mCurrentPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
mCurrentPlayer.prepareAsync();
mCurrentPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mCurrentPlayer.start();
mCurrentPlayer.setOnCompletionListener(onCompletionListener);
createNextMediaPlayer();
}
});
} catch (Exception e) {
Log.e("media", e.getLocalizedMessage());
}
}
private LoopMediaPlayer(Context context, int resId) {
mContext = context;
mResId = resId;
mCurrentPlayer = MediaPlayer.create(mContext, mResId);
mCurrentPlayer.setLooping(false);
mCurrentPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mCurrentPlayer.start();
mCurrentPlayer.setOnCompletionListener(onCompletionListener);
createNextMediaPlayer();
}
});
mCurrentPlayer.prepareAsync();
}
private void createNextMediaPlayer() {
try{
if(mAfd != null){
mNextPlayer = new MediaPlayer();
mNextPlayer.setDataSource(mAfd.getFileDescriptor(), mAfd.getStartOffset(), mAfd.getLength());
mNextPlayer.prepareAsync();
mNextPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mCurrentPlayer.setNextMediaPlayer(mNextPlayer);
}
});
}
else if(mFile!=null){
mNextPlayer = new MediaPlayer();
mNextPlayer.setDataSource(mFile.getAbsolutePath());
mNextPlayer.prepareAsync();
mNextPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mCurrentPlayer.setNextMediaPlayer(mNextPlayer);
}
});
}
else {
mNextPlayer = MediaPlayer.create(mContext, mResId);
mNextPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mCurrentPlayer.setNextMediaPlayer(mNextPlayer);
}
});
}
} catch (Exception e) {
}
}
private final MediaPlayer.OnCompletionListener onCompletionListener = new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
mediaPlayer.release();
mCurrentPlayer = mNextPlayer;
mCurrentPlayer.setOnCompletionListener(onCompletionListener);
createNextMediaPlayer();
Log.d("LoopMediaPlayer", String.format("Loop #%d", ++mCounter));
}
};
// code-read additions:
public boolean isPlaying() throws IllegalStateException {
return mCurrentPlayer.isPlaying();
}
public void setVolume(float leftVolume, float rightVolume) {
mCurrentPlayer.setVolume(leftVolume, rightVolume);
}
public void start() throws IllegalStateException {
mCurrentPlayer.start();
}
public void stop() throws IllegalStateException {
mCurrentPlayer.stop();
}
public void pause() throws IllegalStateException {
mCurrentPlayer.pause();
}
public void release() {
mCurrentPlayer.release();
mNextPlayer.release();
}
public void reset() {
mCurrentPlayer.reset();
}
}
public class LoopMediaPlayer extends MediaPlayer {
private static final String TAG = LoopMediaPlayer.class.getSimpleName();
private Context mContext = null;
private Uri mMediaUri = null;
private int mCounter = 1;
private MediaPlayer mCurrentPlayer = null;
private MediaPlayer mNextPlayer = null;
private Float mLeftVolume;
private Float mRightVolume;
public static LoopMediaPlayer create(Context context, Uri mediaUri) {
try {
return new LoopMediaPlayer(context, mediaUri);
}
catch (Exception e) {
throw new RuntimeException("Unable to create media player", e);
}
}
private LoopMediaPlayer(Context context, Uri mediaUri) throws IOException {
mContext = context;
mMediaUri = mediaUri;
mCurrentPlayer = new MediaPlayer();
mCurrentPlayer.setDataSource(mContext, mMediaUri);
mCurrentPlayer.prepare();
createNextMediaPlayer();
}
private void createNextMediaPlayer() {
try {
mNextPlayer = new MediaPlayer();
mNextPlayer.setDataSource(mContext, mMediaUri);
if (mLeftVolume != null && mRightVolume != null) {
mNextPlayer.setVolume(mLeftVolume, mRightVolume);
}
mNextPlayer.prepare();
mCurrentPlayer.setNextMediaPlayer(mNextPlayer);
mCurrentPlayer.setOnCompletionListener(onCompletionListener);
}
catch (Exception e) {
Log.e(TAG, "Problem creating next media player", e);
}
}
private MediaPlayer.OnCompletionListener onCompletionListener = new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
mediaPlayer.release();
mCurrentPlayer = mNextPlayer;
createNextMediaPlayer();
Log.d(TAG, String.format("Loop #%d", ++mCounter));
}
};
@Override
public void prepare() throws IllegalStateException {
// no-op, internal media-players are prepared when they are created.
}
@Override
public boolean isPlaying() throws IllegalStateException {
return mCurrentPlayer.isPlaying();
}
@Override
public void setVolume(float leftVolume, float rightVolume) {
mCurrentPlayer.setVolume(leftVolume, rightVolume);
mNextPlayer.setVolume(leftVolume, rightVolume);
mLeftVolume = leftVolume;
mRightVolume = rightVolume;
}
@Override
public void start() throws IllegalStateException {
mCurrentPlayer.start();
}
@Override
public void stop() throws IllegalStateException {
mCurrentPlayer.stop();
}
@Override
public void pause() throws IllegalStateException {
mCurrentPlayer.pause();
}
@Override
public void release() {
mCurrentPlayer.release();
mNextPlayer.release();
}
@Override
public void reset() {
mCurrentPlayer.reset();
}
}