Home | History | Annotate | Download | only in onemedia
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.onemedia;
     17 
     18 import android.content.Context;
     19 import android.content.Intent;
     20 import android.graphics.Bitmap;
     21 import android.media.MediaMetadata;
     22 import android.media.session.MediaSession;
     23 import android.media.session.MediaSession.QueueItem;
     24 import android.media.session.MediaSessionManager;
     25 import android.media.session.PlaybackState;
     26 import android.os.Bundle;
     27 import android.os.RemoteException;
     28 import android.os.SystemClock;
     29 import android.util.Log;
     30 import android.view.KeyEvent;
     31 
     32 import com.android.onemedia.playback.LocalRenderer;
     33 import com.android.onemedia.playback.Renderer;
     34 import com.android.onemedia.playback.RequestUtils;
     35 
     36 import java.util.ArrayList;
     37 import java.util.List;
     38 
     39 public class PlayerSession {
     40     private static final String TAG = "PlayerSession";
     41 
     42     protected MediaSession mSession;
     43     protected Context mContext;
     44     protected Renderer mRenderer;
     45     protected MediaSession.Callback mCallback;
     46     protected Renderer.Listener mRenderListener;
     47     protected MediaMetadata.Builder mMetadataBuilder;
     48     protected ArrayList<MediaSession.QueueItem> mQueue;
     49     protected boolean mUseQueue;
     50 
     51     protected PlaybackState mPlaybackState;
     52     protected Listener mListener;
     53 
     54     private String mContent;
     55 
     56     public PlayerSession(Context context) {
     57         mContext = context;
     58         mRenderer = new LocalRenderer(context, null);
     59         mCallback = new SessionCb();
     60         mRenderListener = new RenderListener();
     61         PlaybackState.Builder psBob = new PlaybackState.Builder();
     62         psBob.setActions(PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY);
     63         mPlaybackState = psBob.build();
     64         mQueue = new ArrayList<MediaSession.QueueItem>();
     65 
     66         mRenderer.registerListener(mRenderListener);
     67 
     68         initMetadata();
     69     }
     70 
     71     public void createSession() {
     72         releaseSession();
     73 
     74         MediaSessionManager man = (MediaSessionManager) mContext
     75                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
     76         Log.d(TAG, "Creating session for package " + mContext.getBasePackageName());
     77 
     78         mSession = new MediaSession(mContext, "OneMedia");
     79         mSession.setCallback(mCallback);
     80         mSession.setPlaybackState(mPlaybackState);
     81         mSession.setFlags(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS
     82                 | MediaSession.FLAG_HANDLES_MEDIA_BUTTONS);
     83         mSession.setActive(true);
     84         updateMetadata();
     85     }
     86 
     87     public void onDestroy() {
     88         releaseSession();
     89         if (mRenderer != null) {
     90             mRenderer.unregisterListener(mRenderListener);
     91             mRenderer.onDestroy();
     92         }
     93     }
     94 
     95     private void releaseSession() {
     96         if (mSession != null) {
     97             mSession.release();
     98             mSession = null;
     99         }
    100     }
    101 
    102     public void setListener(Listener listener) {
    103         mListener = listener;
    104     }
    105 
    106     public MediaSession.Token getSessionToken() {
    107         return mSession.getSessionToken();
    108     }
    109 
    110     public void setContent(Bundle request) {
    111         mRenderer.setContent(request);
    112         mContent = request.getString(RequestUtils.EXTRA_KEY_SOURCE);
    113     }
    114 
    115     public void setNextContent(Bundle request) {
    116         mRenderer.setNextContent(request);
    117     }
    118 
    119     public void setIcon(Bitmap icon) {
    120         mMetadataBuilder.putBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON, icon);
    121         mQueue.clear();
    122         mQueue.add(new QueueItem(mMetadataBuilder.build().getDescription(), 11));
    123         updateMetadata();
    124     }
    125 
    126     private void updateMetadata() {
    127         // This is a mild abuse of metadata and shouldn't be duplicated in real
    128         // code
    129         if (mSession != null && mSession.isActive()) {
    130             mSession.setMetadata(mMetadataBuilder.build());
    131             // Just toggle the queue every time we update for testing
    132             mSession.setQueue(mUseQueue ? mQueue : null);
    133             mSession.setQueueTitle(mUseQueue ? "Queue title" : null);
    134             mUseQueue = !mUseQueue;
    135         }
    136     }
    137 
    138     private void updateState(int newState) {
    139         float rate = newState == PlaybackState.STATE_PLAYING ? 1 : 0;
    140         long position = mRenderer == null ? -1 : mRenderer.getSeekPosition();
    141         PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState);
    142         bob.setState(newState, position, rate, SystemClock.elapsedRealtime());
    143         bob.setErrorMessage(null);
    144         mPlaybackState = bob.build();
    145         mSession.setPlaybackState(mPlaybackState);
    146     }
    147 
    148     private void initMetadata() {
    149         mMetadataBuilder = new MediaMetadata.Builder();
    150         mMetadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE,
    151                 "OneMedia display title");
    152         mMetadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_SUBTITLE,
    153                 "OneMedia display subtitle");
    154 
    155         mQueue.add(new QueueItem(mMetadataBuilder.build().getDescription(), 11));
    156     }
    157 
    158     public interface Listener {
    159         public void onPlayStateChanged(PlaybackState state);
    160     }
    161 
    162     private class RenderListener implements Renderer.Listener {
    163 
    164         @Override
    165         public void onError(int type, int extra, Bundle extras, Throwable error) {
    166             Log.d(TAG, "Sending onError with type " + type + " and extra " + extra);
    167             PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState);
    168             bob.setState(PlaybackState.STATE_ERROR, -1, 0, 0);
    169             if (error != null) {
    170                 bob.setErrorMessage(error.getLocalizedMessage());
    171             }
    172             mPlaybackState = bob.build();
    173             mSession.setPlaybackState(mPlaybackState);
    174             if (mListener != null) {
    175                 mListener.onPlayStateChanged(mPlaybackState);
    176             }
    177         }
    178 
    179         @Override
    180         public void onStateChanged(int newState) {
    181             long position = -1;
    182             if (mRenderer != null) {
    183                 position = mRenderer.getSeekPosition();
    184             }
    185             int pbState;
    186             float rate = 0;
    187             String errorMsg = null;
    188             switch (newState) {
    189                 case Renderer.STATE_ENDED:
    190                 case Renderer.STATE_STOPPED:
    191                     pbState = PlaybackState.STATE_STOPPED;
    192                     break;
    193                 case Renderer.STATE_INIT:
    194                 case Renderer.STATE_PREPARING:
    195                     pbState = PlaybackState.STATE_BUFFERING;
    196                     break;
    197                 case Renderer.STATE_ERROR:
    198                     pbState = PlaybackState.STATE_ERROR;
    199                     break;
    200                 case Renderer.STATE_PAUSED:
    201                     pbState = PlaybackState.STATE_PAUSED;
    202                     break;
    203                 case Renderer.STATE_PLAYING:
    204                     pbState = PlaybackState.STATE_PLAYING;
    205                     rate = 1;
    206                     break;
    207                 default:
    208                     pbState = PlaybackState.STATE_ERROR;
    209                     errorMsg = "unknown state";
    210                     break;
    211             }
    212             PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState);
    213             bob.setState(pbState, position, rate, SystemClock.elapsedRealtime());
    214             bob.setErrorMessage(errorMsg);
    215             mPlaybackState = bob.build();
    216             mSession.setPlaybackState(mPlaybackState);
    217             if (mListener != null) {
    218                 mListener.onPlayStateChanged(mPlaybackState);
    219             }
    220         }
    221 
    222         @Override
    223         public void onBufferingUpdate(int percent) {
    224         }
    225 
    226         @Override
    227         public void onFocusLost() {
    228             Log.d(TAG, "Focus lost, changing state to " + Renderer.STATE_PAUSED);
    229             long position = mRenderer == null ? -1 : mRenderer.getSeekPosition();
    230             PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState);
    231             bob.setState(PlaybackState.STATE_PAUSED, position, 0, SystemClock.elapsedRealtime());
    232             bob.setErrorMessage(null);
    233             mPlaybackState = bob.build();
    234             mSession.setPlaybackState(mPlaybackState);
    235             if (mListener != null) {
    236                 mListener.onPlayStateChanged(mPlaybackState);
    237             }
    238         }
    239 
    240         @Override
    241         public void onNextStarted() {
    242         }
    243 
    244     }
    245 
    246     private class SessionCb extends MediaSession.Callback {
    247         @Override
    248         public void onPlay() {
    249             mRenderer.onPlay();
    250         }
    251 
    252         @Override
    253         public void onPause() {
    254             mRenderer.onPause();
    255         }
    256     }
    257 }
    258