Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/183.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
目前无法在Android上实现无间隙音频循环_Android_Android Audiomanager - Fatal编程技术网

目前无法在Android上实现无间隙音频循环

目前无法在Android上实现无间隙音频循环,android,android-audiomanager,Android,Android Audiomanager,我尝试了几乎所有的方法,但我没能在循环10-15秒的单曲之间实现无间隙音频播放 我尝试过但失败的步骤: 使用不同的音频文件格式.mp3.wav.ogg 设置循环(true): 创建两个MediaPlayer并使用 setOnCompletionListenersame未能无间隙循环 使用setNextMediaPlayer(nextmp)。在完成前两个循环后,我们必须准备并重新开始 mp1.start(); mp1.setNextMediaPlayer(mp2); 更新: @Jeff Mi

我尝试了几乎所有的方法,但我没能在循环10-15秒的单曲之间实现无间隙音频播放

我尝试过但失败的步骤:

  • 使用不同的音频文件格式
    .mp3
    .wav
    .ogg
    设置循环(true)

  • 创建两个MediaPlayer并使用
    setOnCompletionListener
    same未能无间隙循环

  • 使用
    setNextMediaPlayer(nextmp)
    。在完成前两个循环后,我们必须准备并重新开始

    mp1.start();
    mp1.setNextMediaPlayer(mp2);
    
  • 更新: @Jeff Mixon回答的结果: . Jeff Mixon工作正常,但此后只有10或20个循环,由于一些垃圾收集问题,MediaPlayer立即停止,留下如下所示的日志。我真的被困在这里两年了。提前谢谢

    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();
        }
    }