Android Open Source - akuplayer A Ku Player Service






From Project

Back to project page akuplayer.

License

The source code is released under:

Copyright (c) 2014, Dmitry Kuznetsov aka kudzmi All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditi...

If you think the Android project akuplayer listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
Copyright (c) 2014, Dmitry Kuznetsov aka kudzmi
All rights reserved.//from  w w w. j av  a 2 s. co m

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.kudzmi.akuplayer.player;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.widget.Toast;


import com.kudzmi.akuplayer.Audio;
import com.kudzmi.akuplayer.PrefStorage;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;

/**
 * MediaPlayer
 * @author Dmitry Kuznetsov aka kudzmi
 * @version 1.0
 */
public class AKuPlayerService extends Service  implements   MediaPlayer.OnCompletionListener,
                                                            MediaPlayer.OnPreparedListener,
                                                            MediaPlayer.OnBufferingUpdateListener,
                                                            MediaPlayer.OnSeekCompleteListener {
    private final String DBG_LABLE = " = AKuPlayer =";

    private MediaPlayer mPlayer;
    private AudioManager am;
    private WifiManager.WifiLock wifiLock;

    private Long currentTrackId = -1L;
    private int currentTrackPos = 0, mBufferPos = 0;

    private List<Audio> mTrackList;
    private List<Audio> mTrackListShuffled;
    private boolean isPaused = false;

    private boolean mIsRepeat = false, mIsShuffle = false;


    private PrefStorage prefs;

    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            switch(action){
                case BroadcastCommander.UI2SRV_EVENT_PL:
                    TrackList tl = (TrackList) intent.getSerializableExtra(BroadcastCommander.MESSAGE_EXTRA);
                    processPlayList(tl);
                    break;
                case BroadcastCommander.UI2SRV_EVENT_CMD:
                    PlayerCommand pcmd = (PlayerCommand) intent.getSerializableExtra(BroadcastCommander.MESSAGE_EXTRA);
                    processCommand(pcmd);
                    break;
                case BroadcastCommander.UI2SRV_EVENT_CMD_SEEK:
                    PlayerSeekCommand pscmd = (PlayerSeekCommand) intent.getSerializableExtra(BroadcastCommander.MESSAGE_EXTRA);
                    processSeekCommand(pscmd);
                    break;
            }

        }
    };

    public AKuPlayerService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        throw new UnsupportedOperationException("Not yet implemented");
    }



    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            sendCurrentPlayerStatus();
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        mTrackList = new ArrayList<>();
        prefs = PrefStorage.getInstance(this);
        am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        Log.d(DBG_LABLE, "CREATED!");

        initMediaPlayer();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BroadcastCommander.UI2SRV_EVENT_CMD);
        intentFilter.addAction(BroadcastCommander.UI2SRV_EVENT_CMD_SEEK);
        intentFilter.addAction(BroadcastCommander.UI2SRV_EVENT_PL);
        LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, intentFilter);



    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if(mReceiver != null)
            LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
        if(mPlayer != null) {
            mPlayer.release();
            mPlayer = null;
        }
        releaseAudioFocus();
        releaseWiFiLock();
        Log.d(DBG_LABLE, "DESTROYED!");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    private void startUpdateThread(){
        Thread thread = new Thread() {
            @Override
            public void run() {
                Log.d(DBG_LABLE, "update thread STARTED");
                while(mPlayer != null && mPlayer.isPlaying()){
                    mHandler.sendMessage(Message.obtain());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                Log.d(DBG_LABLE, "update thread STOPED");
            }
        };
        thread.start();
    }

    private boolean requestAudioFocus(){
        // Request audio focus for playback
        int result = am.requestAudioFocus(afChangeListener,
                // Use the music stream.
                AudioManager.STREAM_MUSIC,
                // Request permanent focus.
                AudioManager.AUDIOFOCUS_GAIN);

        if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
            //am.registerMediaButtonEventReceiver(RemoteControlReceiver);
            // Start playback.

            return true;
        }

        return false;
    }

    private void releaseAudioFocus(){
        am.abandonAudioFocus(afChangeListener);
    }

    private void initMediaPlayer(){
        mPlayer = new MediaPlayer();
        mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mPlayer.setOnPreparedListener(this);
        mPlayer.setOnCompletionListener(this);
        mPlayer.setOnBufferingUpdateListener(this);
        mPlayer.setOnSeekCompleteListener(this);
        mPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
    }

    private void acquireWiFiLock(){
        if(wifiLock == null)
            wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
                    .createWifiLock(WifiManager.WIFI_MODE_FULL, "AKuPlayerWiFiLock");
        wifiLock.acquire();
    }

    private void releaseWiFiLock(){
        if(wifiLock != null && wifiLock.isHeld())
            wifiLock.release();
    }


    private void sendCurrentPlayerStatus(){
        String trackTitle = "";
        if(mIsShuffle){
            trackTitle = mTrackListShuffled.get(currentTrackPos).name;
        }else{
            trackTitle = mTrackList.get(currentTrackPos).name;
        }

        int duration = 0;
        int currentPos = 0;

        if(mPlayer != null && mPlayer.isPlaying()){
            duration = mPlayer.getDuration()/1000;
            currentPos = mPlayer.getCurrentPosition()/1000;
        }
        PlayerStatus ps = new PlayerStatus( duration, currentPos, mBufferPos, trackTitle);
        ps.setCurrentTrackId(currentTrackId);
        if(mPlayer != null & mPlayer.isPlaying()) ps.setPlaying(true);
        else ps.setPlaying(false);

        BroadcastCommander.sendStatus(this, ps);
    }

    private void processPlayList(TrackList tl){
        mTrackList = tl.getTracks();
        //currentTrackId = tl.getStartTrackId();
        isPaused = false;
        mPlayer.reset();
    }

    private void processSeekCommand(PlayerSeekCommand cmd){
        if(cmd.isSeeking()){
            int pos = (int) (((float)cmd.getSeekpos() / 100)*mPlayer.getDuration());
            mPlayer.seekTo(pos);
        }
    }

    private void processCommand(PlayerCommand cmd){
        mIsRepeat = cmd.isRepeat();
        mIsShuffle = cmd.isShuffle();
        if(mIsShuffle) makeRandomList();

        if(cmd.isToPause()){
            doPause();
        }

        if(cmd.isToPlay()){
            if(isPaused){
                doPlay(null);
            }else{
                currentTrackId = cmd.getStartTrackId();
                doPlay(getTrack(currentTrackId));
            }
        }

        if(cmd.isToPrev()){
            doPrev();
        }

        if(cmd.isToNext()){
            doNext();
        }
    }

    /**
     * Get track URI by ID
     * @param id track's ID
     * @return track URL or file path
     */
    private String getTrack(long id){
        Iterator<Audio> it;
        if(!mIsShuffle)it = mTrackList.iterator();
        else it = mTrackListShuffled.iterator();
        int i = 0;
        while (it.hasNext()){
            Audio a = it.next();
            if(a.audio_id == id){
                currentTrackPos = i;
                return a.file;
            }
            i++;
        }

        return null;
    }


    /**
     * Get track URI by it's position
     * @param pos track's position in the track list
     * @return track URL or file path
     */
    private String getTrack(int pos){
        if(mIsShuffle){
            currentTrackId = mTrackListShuffled.get(pos).audio_id;
            return mTrackListShuffled.get(pos).file;
        }else{
            currentTrackId = mTrackList.get(pos).audio_id;
            return mTrackList.get(pos).file;
        }

    }

    private void doPlay(String url){
        Log.d(DBG_LABLE, "doPlay: "+url);
        Log.d(DBG_LABLE, "doPlay ID: "+currentTrackId);
        acquireWiFiLock();
        if(isPaused){
            mPlayer.start();
            startUpdateThread();
        }else try {
                mPlayer.setDataSource(url);
                mPlayer.prepareAsync();
            } catch (IOException e) {
                e.printStackTrace();
                Toast.makeText(this,
                        "Problems with track: "+url, Toast.LENGTH_SHORT).show();
            }

        isPaused = false;


    }

    private void doPause(){
        isPaused = true;
        mPlayer.pause();
        releaseWiFiLock();
    }


    /**
     * Completelu stop the player
     * If track list ends, or the app lost audio focus
     */
    private void doStop(){
        isPaused = false;
        mPlayer.stop();
        mPlayer.reset();
        releaseAudioFocus();
        sendCurrentPlayerStatus();
        releaseWiFiLock();

    }

    private void doPrev(){
        if(mIsRepeat){
            if(currentTrackPos == 0)
                currentTrackPos = mTrackList.size();
        }

        if(currentTrackPos > 0){
            isPaused = false;
            mPlayer.stop(); mPlayer.reset();
            doPlay(getTrack(--currentTrackPos));
        }
    }

    private void doNext(){
        if(mIsRepeat){
            if(currentTrackPos == mTrackList.size()-1)
                currentTrackPos = -1;
        }

        if(currentTrackPos < mTrackList.size()-1){
            isPaused = false;
            mPlayer.stop(); mPlayer.reset();
            doPlay(getTrack(++currentTrackPos));
        }else{ // if there is nothing to play
            doStop();
        }

    }

    /* Listeners */

    @Override
    public void onCompletion(MediaPlayer mediaPlayer) {
        doNext();
    }

    @Override
    public void onPrepared(MediaPlayer mediaPlayer) {
        requestAudioFocus();
        mediaPlayer.start();
        startUpdateThread();
    }

    @Override
    public void onBufferingUpdate(MediaPlayer mediaPlayer, int i) {
        mBufferPos = i;

    }


    /* tools */

    AudioManager.OnAudioFocusChangeListener afChangeListener = new AudioManager.OnAudioFocusChangeListener() {
        public void onAudioFocusChange(int focusChange) {

            switch (focusChange) {
                case AudioManager.AUDIOFOCUS_GAIN:
                    // resume playback
                    if (mPlayer == null) initMediaPlayer();
                    if(isPaused){
                        mPlayer.start();
                        startUpdateThread();
                        isPaused = false;
                    }
                    mPlayer.setVolume(1.0f, 1.0f);
                    break;

                case AudioManager.AUDIOFOCUS_LOSS:
                    // Lost focus for an unbounded amount of time: stop playback and release media player
                    doStop();
                    break;

                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                    // Lost focus for a short time, but we have to stop
                    // playback. We don't release the media player because playback
                    // is likely to resume
                    doPause();
                    break;

                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                    // Lost focus for a short time, but it's ok to keep playing
                    // at an attenuated level
                    if (mPlayer.isPlaying()) mPlayer.setVolume(0.1f, 0.1f);
                    break;
            }



            if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT){
                doPause();
            } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
                if(isPaused) {
                    mPlayer.start();
                    startUpdateThread();
                }
            } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
                //am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
                doStop();

            }
        }
    };

    private void makeRandomList(){
        Set<Integer> tmp = new HashSet<>();
        Random rnd = new Random(System.currentTimeMillis());
        mTrackListShuffled = new ArrayList<>();
        while(mTrackListShuffled.size() < mTrackList.size()){
            int pos = rnd.nextInt(mTrackList.size());
            if(tmp.add(pos)){
                mTrackListShuffled.add(mTrackList.get(pos));
            }
        }
    }

    @Override
    public void onSeekComplete(MediaPlayer mediaPlayer) {
        if(mPlayer != null && mPlayer.isPlaying())
            sendCurrentPlayerStatus();
    }
}




Java Source Code List

com.kudzmi.akuplayer.Audio.java
com.kudzmi.akuplayer.MainActivity.java
com.kudzmi.akuplayer.PrefStorage.java
com.kudzmi.akuplayer.SimpleListAdapter.java
com.kudzmi.akuplayer.TrackListAdapter.java
com.kudzmi.akuplayer.player.AKuPlayerService.java
com.kudzmi.akuplayer.player.BroadcastCommander.java
com.kudzmi.akuplayer.player.ItemHighlighter.java
com.kudzmi.akuplayer.player.PlayerCommand.java
com.kudzmi.akuplayer.player.PlayerSeekCommand.java
com.kudzmi.akuplayer.player.PlayerStatus.java
com.kudzmi.akuplayer.player.TrackList.java