android 跨进程多实例播放demo


客户端进程需要实现,其中notify方法需要service 跨进程调用,通知客户端播放消息

IMediaPlayerClient.aidl

package com.example.demo;

import com.example.demo.ParcelableParcel;

interface IMediaPlayerClient {
         void notify(int msg, int ext1, int ext2, in ParcelableParcel obj);

}

public class MediaPlayerClientBn extends IMediaPlayerClient.Stub implements
        IMediaDeathNotifier {

// 其中重要的方法

    public void init() {
        this.mLock = new ReentrantLock();
        this.mNotifyLock = new ReentrantLock();
        this.mSignal = this.mLock.newCondition();
        mPlayer = null;
        mListener = null;
        mCookie = null;
        mStreamType = 3 /* TODO AUDIO_STREAM_MUSIC */;
        mAudioAttributesParcel = null;
        mCurrentPosition = -1;
        mSeekPosition = -1;
        mCurrentState = MEDIA_PLAYER_IDLE;
        mPrepareSync = false;
        mPrepareStatus = MediaErrorsNum.NO_ERROR;
        mLoop = false;
        mLeftVolume = mRightVolume = 1.0f;
        mVideoWidth = mVideoHeight = 0;
        mLockThreadId = 0;
        mAudioSessionId = 0;
        /*
         * TODO mAudioSessionId = AudioSystem::newAudioUniqueId();
         * AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
         */
        mSendLevel = 0;
        mRetransmitEndpointValid = false;
    }


    int attachNewPlayer(IMediaPlayer player) {
        Log.i(LOG_TAG, "attachNewPlayer");
        int err = MediaErrorsNum.UNKNOWN_ERROR;
        IMediaPlayer p;
        { // scope for the lock
            mLock.lock();

            if (( 0 == (mCurrentState & MEDIA_PLAYER_IDLE)) || (mCurrentState == MEDIA_PLAYER_STATE_ERROR)) {
                Log.e(LOG_TAG, "attachNewPlayer called in state = "
                        + mCurrentState);
                return MediaErrorsNum.INVALID_OPERATION;
            }

            clear_l();
            p = mPlayer;
            mPlayer = player;
            Log.i(LOG_TAG, "mPlayer is "+mPlayer.toString());
            if (player != null) {
                mCurrentState = MEDIA_PLAYER_INITIALIZED;
                err = MediaErrorsNum.NO_ERROR;
            } else {
                Log.e(LOG_TAG, "Unable to create media player");
            }
            mLock.unlock();
        }

        if (p != null) {
            try {
                p.disconnect();
            } catch (RemoteException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        return err;
    }

//获得getRemoteMediaPlayerServiceInstance,创建IMediaPlayer,并且使得

IMediaPlayer 和IMediaPlayerClient 实例一一对应,互相引用。 并且用MediaDeathNotifier

通知service 的生命周期。

    public int setDataSource(final IMediaHTTPService httpService, String url,
            final HashMap<String, String> headers) {
        mAudioSessionId ++;
        int err = MediaErrorsNum.BAD_VALUE;
        Log.i(LOG_TAG, "setDataSource(" + url + ")");
        try {

            if (url != null) {
                IMyMediaPlayerService service;

/*                service = MediaDeathNotifier.getMediaPlayerService();*/
                service = MediaPlayer_Surface_iadl_MultThread_TestBase.getRemoteMediaPlayerServiceInstance();

                if (service != null) {
                    IMediaPlayer player = (service
                            .create(this, mAudioSessionId));
                    if ((MediaErrorsNum.NO_ERROR != doSetRetransmitEndpoint(player))
                            || (MediaErrorsNum.NO_ERROR != player
                                    .setDataSource(httpService, url, null/* TODO */))) {
                        player = null;
                    }
                    err = attachNewPlayer(player);
                }
            }
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return err;
    }

//prepare

    public int prepare() {

        Log.i(LOG_TAG, "prepare()");
        mLock.lock();
        mLockThreadId = (int) Thread.currentThread().getId();
        if (mPrepareSync) {
            mLockThreadId = 0;
            return MediaErrorsNum.EALREADY;
        }
        mPrepareSync = true;
        int ret = MediaErrorsNum.NO_ERROR;
        try {
            ret = prepareAsync_l();
        } catch (RemoteException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        if (ret != MediaErrorsNum.NO_ERROR) {
            mLockThreadId = 0;
            return ret;
        }

        if (mPrepareSync) {
            try {

                mSignal.await();

            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } // wait for prepare done
            mPrepareSync = false;
        }
        Log.i(LOG_TAG, "prepare complete - status= " + mPrepareStatus);
        mLockThreadId = 0;
        mLock.unlock();
        return mPrepareStatus;
    }

    private int prepareAsync_l() throws RemoteException {
        if ((mPlayer != null)&& (mCurrentState & (MediaPlayerClientBn.MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED)) != 0) {
            Log.i(LOG_TAG,"mCurrentState is MEDIA_PLAYER_INITIALIZED or MEDIA_PLAYER_STOPPED");
            if (mAudioAttributesParcel != null) {
                mPlayer.setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES,
                        ParcelableParcel.CREATOR
                                .createFromParcel(mAudioAttributesParcel));
            } else {
                mPlayer.setAudioStreamType(mStreamType);
            }
            mCurrentState = MEDIA_PLAYER_PREPARING;

            return mPlayer.prepareAsync();
        }
        Log.i(LOG_TAG, "prepareAsync called in state = " + mCurrentState);
        return MediaErrorsNum.INVALID_OPERATION;

    }

// start play

    public int start() {
        Log.i(LOG_TAG, "start()");

        int ret = MediaErrorsNum.NO_ERROR;
        mLock.lock();

        mLockThreadId = Thread.currentThread().getId();

        if ((mCurrentState & MEDIA_PLAYER_STARTED) == 1) {
            ret = MediaErrorsNum.NO_ERROR;
        } else if ((mPlayer != null)&& ((mCurrentState & (MEDIA_PLAYER_PREPARED| MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED)) != 0)) {
            try {
                mPlayer.setLooping(mLoop);

                mPlayer.setVolume(mLeftVolume, mRightVolume);
                mPlayer.setAuxEffectSendLevel(mSendLevel);
                mCurrentState = MEDIA_PLAYER_STARTED;
                ret = mPlayer.start();
            } catch (RemoteException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if (ret != MediaErrorsNum.NO_ERROR) {
                mCurrentState = MEDIA_PLAYER_STATE_ERROR;
            } else {
                if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
                    Log.i(LOG_TAG,
                            "playback completed immediately following start()");
                }
            }
        } else {
            Log.e(LOG_TAG, "start called in state " + mCurrentState);
            ret = MediaErrorsNum.INVALID_OPERATION;
        }

        mLockThreadId = 0;
        mLock.unlock();
        return ret;
    }


// 消息传递

   @Override
    public void notify(int msg, int ext1, int ext2, ParcelableParcel obj)
            throws RemoteException {
        // TODO Auto-generated method stub
        
        Log.i(LOG_TAG,"message received msg=%d, ext1=%d, ext2=%d"+msg+":"+ext1+":"+ ext2);
            boolean send = true;
            boolean locked = false;
        
            // TODO: In the future, we might be on the same thread if the app is
            // running in the same process as the media server. In that case,
            // this will deadlock.
            //
            // The threadId hack below works around this for the care of prepare,
            // seekTo and start within the same process.
            // FIXME: Remember, this is a hack, it's not even a hack that is applied
            // consistently for all use-cases, this needs to be revisited.
            if (mLockThreadId != Thread.currentThread().getId()) {
                mLock.lock();
                locked = true;
            }
        
            // Allows calls from JNI in idle state to notify errors
            if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == null) {
                Log.i(LOG_TAG,"notify(%d, %d, %d) callback on disconnected mediaplayer :"+msg+":"+ext1+":"+ext2);
                if (locked) mLock.unlock();   // release the lock when done.
                return;
            }
        
            switch (msg) {
            case MEDIA_NOP: // interface test message
                break;
            case MEDIA_PREPARED:
                Log.i(LOG_TAG,"prepared");
                mCurrentState = MEDIA_PLAYER_PREPARED;
                if (mPrepareSync) {
                    Log.i(LOG_TAG,"signal application thread");
                    mPrepareSync = false;
                    mPrepareStatus = MediaErrorsNum.NO_ERROR;
                    mSignal.signal();
                }
                break;
            case MEDIA_PLAYBACK_COMPLETE:
                Log.i(LOG_TAG,"playback complete");
                if (mCurrentState == MEDIA_PLAYER_IDLE) {
                    Log.e(LOG_TAG,"playback complete in idle state");
                }
                if (!mLoop) {
                    mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
                }
                break;
            case MEDIA_ERROR:
                // Always log errors.
                // ext1: Media framework error code.
                // ext2: Implementation dependant error code.
                Log.e(LOG_TAG,"error (%d, %d)"+":"+ext1+":"+ ext2);
                mCurrentState = MEDIA_PLAYER_STATE_ERROR;
                if (mPrepareSync)
                {
                    Log.i(LOG_TAG,"signal application thread");
                    mPrepareSync = false;
                    mPrepareStatus = ext1;
                    mSignal.signal();
                    send = false;
                }
                break;
            case MEDIA_INFO:
                // ext1: Media framework error code.
                // ext2: Implementation dependant error code.
                if (ext1 != MEDIA_INFO_VIDEO_TRACK_LAGGING) {
                    Log.w(LOG_TAG,"info/warning (%d, %d)"+":"+ext1+":"+ ext2);
                }
                break;
            case MEDIA_SEEK_COMPLETE:
                Log.i(LOG_TAG,"Received seek complete");
                if (mSeekPosition != mCurrentPosition) {
                    Log.i(LOG_TAG,"Executing queued seekTo(%d) "+mSeekPosition);
                    mSeekPosition = -1;
                    seekTo_l(mCurrentPosition);
                }
                else {
                    Log.i(LOG_TAG,"All seeks complete - return to regularly scheduled program");
                    mCurrentPosition = mSeekPosition = -1;
                }
                break;
            case MEDIA_BUFFERING_UPDATE:
                Log.i(LOG_TAG,"buffering %d"+ ext1);
                break;
            case MEDIA_SET_VIDEO_SIZE:
                Log.i(LOG_TAG,"New video size %d x %d"+":"+ext1+":"+ ext2);
                mVideoWidth = ext1;
                mVideoHeight = ext2;
                break;
            case MEDIA_TIMED_TEXT:
                Log.i(LOG_TAG,"Received timed text message");
                break;
            case MEDIA_SUBTITLE_DATA:
                Log.i(LOG_TAG,"Received subtitle data message");
                break;
            case MEDIA_META_DATA:
                Log.i(LOG_TAG,"Received timed metadata message");
                break;
            default:
                Log.i(LOG_TAG,"unrecognized message: (%d, %d, %d) :"+ msg+":"+ext1+":"+ ext2);
                break;
            }
        
            MediaPlayerListener listener = mListener;
            if (locked) mLock.unlock();
        
            // this prevents re-entrant calls into client code
            if ((listener != null) && send) {
                mNotifyLock.lock();
                Log.i(LOG_TAG,"callback application");
                listener.notify(msg, ext1, ext2, null == obj?null:obj.getParcel());
                mNotifyLock.unlock();
            }

    }

}




IMyMediaPlayerService.aidl

package com.example.demo;


import com.example.demo.IMediaPlayer;
import com.example.demo.IMediaPlayerClient;
import com.example.demo.IOMX;
import com.example.demo.ICrypto;
import com.example.demo.IDrm;
import com.example.demo.IHDCP;
import com.example.demo.IMediaCodecList;


import android.view.Surface;

interface IMyMediaPlayerService {


        IMediaPlayer create(in IMediaPlayerClient client,  int audioSessionId);

        IOMX            getOMX();
        ICrypto         makeCrypto();
        IDrm            makeDrm();
        IHDCP           makeHDCP( boolean createEncryptionModule);
        IMediaCodecList getCodecList();
}

public class MyMediaPlayerService extends Service {
    private static final String LOG_TAG = MyMediaPlayerService.class.getName()
            + "";

    public static void instantiate() {
        Log.i(LOG_TAG, "instantiate call");
    }

    // For battery usage tracking purpose
    class BatteryUsageInfo {
        // how many streams are being played by one UID
        int refCount;
        // a temp variable to store the duration(ms) of audio codecs
        // when we start a audio codec, we minus the system time from
        // audioLastTime
        // when we pause it, we add the system time back to the audioLastTime
        // so after the pause, audioLastTime = pause time - start time
        // if multiple audio streams are played (or recorded), then
        // audioLastTime
        // = the total playing time of all the streams
        int audioLastTime;
        // when all the audio streams are being paused, we assign audioLastTime
        // to
        // this variable, so this value could be provided to the battery app
        // in the next pullBatteryData call
        int audioTotalTime;

        int videoLastTime;
        int videoTotalTime;
    };

    HashMap<Integer, BatteryUsageInfo> mBatteryData = null;

    private static final int SPEAKER = 0;
    private static final int OTHER_AUDIO_DEVICE = 1;
    private static final int SPEAKER_AND_OTHER = 2;
    private static final int NUM_AUDIO_DEVICES = 3;

 

    //

    ReentrantLock mLock = new ReentrantLock();
    Vector<SoftReference<MediaPlayerBn>> mClients = new Vector<SoftReference<MediaPlayerBn>>();
    int mNextConnId = 0;
    AtomicInteger tmp = new AtomicInteger(mNextConnId);
    IOMX mOMX;
    ICrypto mCrypto;

    @SuppressLint("NewApi")
    private final IMyMediaPlayerService.Stub mBinder = new IMyMediaPlayerService.Stub() {
// 创建与IMediaPlayerClient相对的IMediaPlayer,互粉并加入一个软引用向量管理对应关系。
        @Override
        public IMediaPlayer create(IMediaPlayerClient client, int audioSessionId)
                throws RemoteException {
            // TODO Auto-generated method stub

            long pid = Binder.getCallingPid();

            int connId = tmp.getAndIncrement();

            MediaPlayerBn c = new MediaPlayerBn(MyMediaPlayerService.this, pid,
                    connId, client, audioSessionId, Binder.getCallingUid());

            Log.i(LOG_TAG, "Create new client("+connId+") from pid "+pid+", uid "+getCallingUid()+", ");

            SoftReference<MediaPlayerBn> w = new SoftReference<MediaPlayerBn>(c);
            {
                mLock.lock();
                mClients.add(w);
                mLock.unlock();
            }
            return c;
        }

 }

}

IMediaPlayer.aidl:

package com.example.demo;

import android.view.Surface;
import com.example.demo.IMediaHTTPService;
import com.example.demo.AudioPlaybackRate;
import com.example.demo.AVSyncSettings;
import com.example.demo.ParcelableParcel;
import android.os.Messenger;
 

interface IMediaPlayer  {
        //void playLoadedVideo_iadl(in  Surface  surface);
        
 void            disconnect();

int        setDataSource(in IMediaHTTPService httpService, String url, String header /*HashMap<String,String> headers*/);

//int        setDataSource(int fd, long offset, long length);
//int        setDataSource(in  IStreamSource source);
//int        setDataSource(in  IDataSource source);
int        setVideoSurfaceTexture(in  Surface  surface);
int        prepareAsync();
int        start();
int        stop();
int        pause();
int        isPlaying(boolean state);
int        setPlaybackSettings(in  AudioPlaybackRate rate);
int        getPlaybackSettings(in  AudioPlaybackRate rate /* nonnull */);
int        setSyncSettings(in AVSyncSettings sync, float videoFpsHint);
int        getSyncSettings(in AVSyncSettings sync /* nonnull */,     float videoFps /* nonnull */);
int        seekTo(int msec) ;
int        getCurrentPosition(int msec);
int        getDuration(int msec);
int        reset();
/*typedef enum {
 
    AUDIO_STREAM_DEFAULT          = -1,
    AUDIO_STREAM_MIN              = 0,
    AUDIO_STREAM_VOICE_CALL       = 0,
    AUDIO_STREAM_SYSTEM           = 1,
    AUDIO_STREAM_RING             = 2,
    AUDIO_STREAM_MUSIC            = 3,
    AUDIO_STREAM_ALARM            = 4,
    AUDIO_STREAM_NOTIFICATION     = 5,
    AUDIO_STREAM_BLUETOOTH_SCO    = 6,
    AUDIO_STREAM_ENFORCED_AUDIBLE = 7,
    AUDIO_STREAM_DTMF             = 8,
    AUDIO_STREAM_TTS              = 9,  
    AUDIO_STREAM_BOOT              = 10,
    AUDIO_STREAM_VIBSPK            = 11,
    AUDIO_STREAM_ACCESSIBILITY    = 12,
    AUDIO_STREAM_REROUTING        = 13,
    AUDIO_STREAM_PATCH            = 14,
    AUDIO_STREAM_PUBLIC_CNT       = AUDIO_STREAM_VIBSPK + 1,
    AUDIO_STREAM_CNT              = AUDIO_STREAM_PATCH + 1,
} audio_stream_type_t;*/
int        setAudioStreamType(/*audio_stream_type_t type*/int type);
int        setLooping(boolean loop) ;
int        setVolume(float leftVolume, float rightVolume) ;
int        setAuxEffectSendLevel(float level);
int        attachAuxEffect(int effectId) ;
int        setParameter(int key,in ParcelableParcel request);
int        getParameter(int key,in  ParcelableParcel reply);
int        setRetransmitEndpoint0(String endpoint /*const struct sockaddr_in* endpoint*/);
int        getRetransmitEndpoint1(String endpoint /*struct sockaddr_in* endpoint*/);
int        setNextPlayer(in IMediaPlayer next);


int        setMetadataFilter(in ParcelableParcel filter);


int        getMetadata(boolean update_only,   boolean apply_filter,in ParcelableParcel metadata);
 

}



package com.example.demo;

import java.io.IOException;
import java.lang.ref.SoftReference;
import java.util.concurrent.locks.ReentrantLock;

import android.annotation.SuppressLint;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnInfoListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnSeekCompleteListener;
import android.media.MediaPlayer.OnVideoSizeChangedListener;
import android.os.Binder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
import android.view.Surface;

@SuppressLint("NewApi")
public class MediaPlayerBn extends IMediaPlayer.Stub {
    private static final String LOG_TAG = MediaPlayerBn.class.getName();

    private static final int NO_INIT = 0;
    private static final int AUDIO_ATTRIBUTES_TAGS_MAX_SIZE = 64/* TODO */;

    class audio_attributes_t {
        /*
         * TODO audio_content_type_t content_type; audio_usage_t usage;
         * audio_source_t source; audio_flags_mask_t flags; char
         * tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE]; UTF8
         */
    };

    ReentrantLock mLock;
    /* MediaPlayerBase mPlayer; */
    MediaPlayer mPlayer;
    MyMediaPlayerService mService;
    IMediaPlayerClient mClient;
    AudioOutput mAudioOutput;
    int mPid;
    int mStatus;
    boolean mLoop;
    int mConnId;
    int mAudioSessionId;
    audio_attributes_t mAudioAttributes;
    long mUID;
    Surface mConnectedWindow;
    Binder mConnectedWindowBinder;
    String mRetransmitEndpoint;
    boolean mRetransmitEndpointValid;
    MediaPlayerBn mNextClient;

    // Metadata filters.
    /* media::Metadata::Filter */Object mMetadataAllow; // protected by mLock
    /* media::Metadata::Filter */Object mMetadataDrop; // protected by mLock

    // Metadata updated. For each MEDIA_INFO_METADATA_UPDATE
    // notification we try to update mMetadataUpdated which is a
    // set: no duplicate.
    // getMetadata clears this set.
    /* media::Metadata::Filter */Object mMetadataUpdated; // protected by mLock

    /*
     * TODO #if CALLBACK_ANTAGONIZER Antagonizer* mAntagonizer; #endif
     */

    Object mAntagonizer;
    OnErrorListener mErrorListener = new MediaPlayer.OnErrorListener() {
        
        @Override
        public boolean onError(MediaPlayer mp, int what, int extra) {
            // TODO Auto-generated method stub
            MediaPlayerBn.this.notify(MediaPlayerBn.this, 100, what, extra, null);
            return false;
        }
    };
    OnInfoListener  mInfoListener = new MediaPlayer.OnInfoListener() {
        
        @Override
        public boolean onInfo(MediaPlayer mp, int what, int extra) {
            // TODO Auto-generated method stub
            MediaPlayerBn.this.notify(MediaPlayerBn.this, 200, what, extra, null);
            return false;
        }
    };
    OnBufferingUpdateListener  mBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() {
        
        @Override
        public void onBufferingUpdate(MediaPlayer mp, int percent) {
            // TODO Auto-generated method stub
            MediaPlayerBn.this.notify(MediaPlayerBn.this, 3, 3, percent, null);
        }
    };
    OnCompletionListener  mCompletionListener = new MediaPlayer.OnCompletionListener() {
        
        @Override
        public void onCompletion(MediaPlayer mp) {
            // TODO Auto-generated method stub
            MediaPlayerBn.this.notify(MediaPlayerBn.this, 2, 2, 0, null);
        }
    };
    
    OnPreparedListener  mPreparedListener = new MediaPlayer.OnPreparedListener() {
        
        @Override
        public void onPrepared(MediaPlayer mp) {
            // TODO Auto-generated method stub
            Log.i(LOG_TAG,"mPreparedListener.onPrepared() ");
            MediaPlayerBn.this.notify(MediaPlayerBn.this, 1, 1, 0, null);
        }
    };
    OnSeekCompleteListener  mSeekCompleteListener = new MediaPlayer.OnSeekCompleteListener() {
        
        @Override
        public void onSeekComplete(MediaPlayer mp) {
            // TODO Auto-generated method stub
            MediaPlayerBn.this.notify(MediaPlayerBn.this, 4, 4, 0, null);
        }
    };
    OnVideoSizeChangedListener  mVideoSizeChangedListener = new MediaPlayer.OnVideoSizeChangedListener() {
        
        @Override
        public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
            // TODO Auto-generated method stub
            MediaPlayerBn.this.notify(MediaPlayerBn.this, 5, 5, 0, null);
        }
    };
    public MediaPlayerBn(MyMediaPlayerService service, long pid, int connId,
            IMediaPlayerClient client, int audioSessionId, long uid) {
        Log.i(LOG_TAG, "Client(%d) constructor" + connId);
        mPid = (int) pid;
        mConnId = connId;
        mService = service;
        mClient = client;
        mLoop = false;
        mStatus = NO_INIT;
        mAudioSessionId = audioSessionId;
        mUID = uid;
        mRetransmitEndpointValid = false;
        mAudioAttributes = null;
        mLock = new ReentrantLock();
        Log.i(LOG_TAG, "create Antagonizer is null");
        mAntagonizer = null;
        mPlayer = new MediaPlayer();
        mPlayer.setOnErrorListener(mErrorListener);
        mPlayer.setOnInfoListener(mInfoListener);
        mPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
        mPlayer.setOnCompletionListener(mCompletionListener);
        mPlayer.setOnPreparedListener(mPreparedListener);
        mPlayer.setOnSeekCompleteListener(mSeekCompleteListener);
        mPlayer.setOnVideoSizeChangedListener(mVideoSizeChangedListener);
    }

    public void desdroy() {
        Log.i(LOG_TAG, "Client(%d) destructor pid = %d" + mConnId + ":" + mPid);
        mAudioOutput = null;
        SoftReference<MediaPlayerBn> client = new SoftReference<MediaPlayerBn>(
                this);
        try {
            disconnect();
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

// destory 的时候删除引用

        mService.removeClient(client);

        if (mAudioAttributes != null) {
            /* TODO free(mAudioAttributes); */
            mAudioAttributes = null;
        }
    }


    @Override
    public void disconnect() throws RemoteException {
        // TODO Auto-generated method stub
        Log.i(LOG_TAG, "disconnect(%d) from pid %d" + mConnId + ":" + mPid);

        // grab local reference and clear main reference to prevent future
        // access to object
        MediaPlayer p;
        {
            mLock.lock();
            p = mPlayer;
            mLock.unlock();
        }
        mPlayer = null;

        // clear the notification to prevent callbacks to dead client
        // and reset the player. We assume the player will serialize
        // access to itself if necessary.
        if (p != null) {
            /* TODO p.setNotifyCallback(0, 0); */
            p.reset();
        }
        /* TODOdisconnectNativeWindow(); */

        /* TODO IPCThreadState::self()->flushCommands(); */
    }

    @Override
    public int setDataSource(IMediaHTTPService httpService, String url,
            String header) throws RemoteException {
        // TODO Auto-generated method stub

        Log.i(LOG_TAG, "setDataSource(%s) " + url);

        try {

            mPlayer.setDataSource(url);
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return 0;

    }

}


客户端多实例调用

/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.example.demo;

import java.io.IOException;
import java.util.logging.Logger;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

@SuppressLint("NewApi")
public class MediaPlayer_Surface_iadl_MultThread_TestBase extends Activity  {

    private static final String LOG_TAG = MediaPlayer_Surface_iadl_MultThread_TestBase.class
            .getName() + "liyl add";
    protected static final int SLEEP_TIME = 1000;
    protected static final int LONG_SLEEP_TIME = 6000;
    protected static final int STREAM_RETRIES = 1;
    protected static boolean sUseScaleToFitMode = false;



    /*
     * protected Monitor mOnVideoSizeChangedCalled = new Monitor(); protected
     * Monitor mOnVideoRenderingStartCalled = new Monitor(); protected Monitor
     * mOnBufferingUpdateCalled = new Monitor(); protected Monitor
     * mOnPrepareCalled = new Monitor(); protected Monitor mOnSeekCompleteCalled
     * = new Monitor(); protected Monitor mOnCompletionCalled = new Monitor();
     * protected Monitor mOnInfoCalled = new Monitor(); protected Monitor
     * mOnErrorCalled = new Monitor();
     */

    protected SurfaceHolder mSurfaceHolder1 = null;
    protected SurfaceHolder mSurfaceHolder2 = null;

    private SurfaceHolder mHolder1;
    private SurfaceHolder mHolder2;
    
    protected MediaPlayer_Surface_iadl_MultThread_TestBase mActivity;

    private boolean mIsRemoteBound = false;

    private static IMyMediaPlayerService mRemoteService = null;
    
    private MediaPlayerClientWrapper mPlayerWrapper1;
    private MediaPlayerClientWrapper mPlayerWrapper2;
    
    public static IMyMediaPlayerService getRemoteMediaPlayerServiceInstance() {
        if(mRemoteService == null) {
            Log.e(LOG_TAG,"not should be here!!!");
            return mRemoteService;
        }
        return mRemoteService;
    }
    
    protected class MediaPlayerClientWrapper implements MediaPlayerListener {
        public MediaPlayerClientWrapper() {
            super();
            this.mPlayerClient = new MediaPlayerClientBn();
        }

        private MediaPlayerClientBn mPlayerClient;
        
        public MediaPlayerClientBn getmPlayerClient() {
            return mPlayerClient;
        }
        @Override
        public void notify(int msg, int ext1, int ext2, Parcel obj) {
            // TODO Auto-generated method stub
            Log.e(LOG_TAG,"msg = "+msg+" ext1 = "+ext1+" ext2 = "+ext2+" obj = "+obj);
            if(msg == 1/*MEDIA_PREPARED*/) {
            mPlayerClient.start();
            }
        }
        public void desdroy() {
            this.mPlayerClient = null;
        }
        
    }
    



    private ServiceConnection mRemoteConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // TODO Auto-generated method stub
            mRemoteService = IMyMediaPlayerService.Stub.asInterface(service);
            Log.i(LOG_TAG,"mRemoteService == null is "+(mRemoteService == null));
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub
            mRemoteService = null;
        }
    };

    public MediaPlayer_Surface_iadl_MultThread_TestBase() {
        super();
    }

    protected void setUp() {
        mSurfaceHolder1 = getSurfaceHolder1();
        mSurfaceHolder2 = getSurfaceHolder2();

        if (!mIsRemoteBound) {


            Intent mIntent = new Intent();
            mIntent.setAction("com.example.demo.IMyMediaPlayerService");//你定义的service的action
            mIntent.setPackage(getPackageName());//这里你需要设置你应用的包名
            //startService(mIntent);


            bindService(mIntent,
                    mRemoteConnection, Context.BIND_AUTO_CREATE);
            mIsRemoteBound = !mIsRemoteBound;
        }
        mPlayerWrapper1 = new MediaPlayerClientWrapper();
        mPlayerWrapper2 = new MediaPlayerClientWrapper();
        mPlayerWrapper1.getmPlayerClient().setListener(mPlayerWrapper1);
        mPlayerWrapper2.getmPlayerClient().setListener(mPlayerWrapper2);
    }

    public SurfaceHolder getSurfaceHolder1() {
        return mHolder1;
    }
    public SurfaceHolder getSurfaceHolder2() {
        return mHolder2;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);

        setContentView(R.layout.mediaplayermultsurface);

        mActivity = this;

        SurfaceView surfaceV1 = (SurfaceView) findViewById(R.id.surface1);
        mHolder1 = surfaceV1.getHolder();
        SurfaceView surfaceV2 = (SurfaceView) findViewById(R.id.surface2);
        mHolder2 = surfaceV2.getHolder();

        setUp();

    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        tearDown();

    }

    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();

        if(mRemoteService == null) {
            Log.w(LOG_TAG,"mRemoteService is null");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        mSurfaceHolder1.addCallback(new SurfaceHolder.Callback() {

            @Override
            public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
                    int arg3) {
                // TODO Auto-generated method stub
                mSurfaceHolder1 = arg0;
            }

            @Override
            public void surfaceCreated(SurfaceHolder arg0) {
                // TODO Auto-generated method stub
                try {
                    
                    
                    mPlayerWrapper1.getmPlayerClient().setDataSource(null,"http://10.154.250.32:8081/share/mediatest/normal/hls/1080p/desc.m3u8", null);
                    mPlayerWrapper1.getmPlayerClient().setVideoSurfaceTexture(mActivity.getSurfaceHolder1()
                            .getSurface());
                    mPlayerWrapper1.getmPlayerClient().prepare();


                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder arg0) {
                // TODO Auto-generated method stub
                mSurfaceHolder1 = null;
            }

        });
 
        mSurfaceHolder2.addCallback(new SurfaceHolder.Callback() {

            @Override
            public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
                    int arg3) {
                // TODO Auto-generated method stub
                mSurfaceHolder2 = arg0;
            }

            @Override
            public void surfaceCreated(SurfaceHolder arg0) {
                // TODO Auto-generated method stub
                try {


                    
                    
                    mPlayerWrapper2.getmPlayerClient().setDataSource(null,"http://10.154.250.32:8081/share/mediatest/normal/hls/1080p/desc.m3u8", null);
                    mPlayerWrapper2.getmPlayerClient().setVideoSurfaceTexture(mActivity.getSurfaceHolder2()
                            .getSurface());
                    mPlayerWrapper2.getmPlayerClient().prepare();


                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder arg0) {
                // TODO Auto-generated method stub
                mSurfaceHolder2 = null;
            }

        });
        
            Log.w(LOG_TAG,"Sleep 5 s");
/*            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }*/



    }
    private void clear() {
        mPlayerWrapper1.desdroy();
        mPlayerWrapper2.desdroy();
    }
    protected void tearDown() {
        clear();
        if (!mIsRemoteBound) {
            unbindService(mRemoteConnection);
            mIsRemoteBound = !mIsRemoteBound;
        }

    }



    // //

   



}

转载于:https://my.oschina.net/u/269082/blog/647380

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值