107c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik/*
207c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * Copyright (C) 2014 The Android Open Source Project
307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik *
407c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * Licensed under the Apache License, Version 2.0 (the "License");
507c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * you may not use this file except in compliance with the License.
607c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * You may obtain a copy of the License at
707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik *
807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik *      http://www.apache.org/licenses/LICENSE-2.0
907c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik *
1007c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * Unless required by applicable law or agreed to in writing, software
1107c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * distributed under the License is distributed on an "AS IS" BASIS,
1207c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * See the License for the specific language governing permissions and
1407c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * limitations under the License.
1507c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik */
16bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikpackage com.android.onemedia.playback;
17bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
18bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport org.apache.http.Header;
19bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport org.apache.http.HttpResponse;
20bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport org.apache.http.client.methods.HttpGet;
21bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
22bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.content.Context;
23bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.media.AudioManager;
24bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.media.AudioManager.OnAudioFocusChangeListener;
25bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.media.MediaPlayer;
26bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.media.MediaPlayer.OnBufferingUpdateListener;
27bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.media.MediaPlayer.OnCompletionListener;
28bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.media.MediaPlayer.OnErrorListener;
29bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.media.MediaPlayer.OnPreparedListener;
30bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.net.Uri;
31bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.net.http.AndroidHttpClient;
32bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.os.AsyncTask;
33bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.os.Bundle;
34bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.os.Handler;
35bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.util.Log;
36bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.view.SurfaceHolder;
37bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
38bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport java.io.IOException;
39bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport java.util.Map;
40bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
41bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik/**
42bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik * Helper class for wrapping a MediaPlayer and doing a lot of the default work
43bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik * to play audio. This class is not currently thread safe and all calls to it
44bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik * should be made on the same thread.
45bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik */
46bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikpublic class LocalRenderer extends Renderer implements OnPreparedListener,
47bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        OnBufferingUpdateListener, OnCompletionListener, OnErrorListener,
48bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        OnAudioFocusChangeListener {
49bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private static final String TAG = "MediaPlayerManager";
501e55375c96cadb8ef7aa12008e2be754969e1294Joe Onorato    private static final boolean DEBUG = false;
51bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private static long sDebugInstanceId = 0;
52bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
53bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private static final String[] SUPPORTED_FEATURES = {
54bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            FEATURE_SET_CONTENT,
55bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            FEATURE_SET_NEXT_CONTENT,
56bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            FEATURE_PLAY,
57bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            FEATURE_PAUSE,
58bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            FEATURE_NEXT,
59bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            FEATURE_PREVIOUS,
60bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            FEATURE_SEEK_TO,
61bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            FEATURE_STOP
62bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    };
63bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
64bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
65bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * These are the states where it is valid to call play directly on the
66bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * MediaPlayer.
67bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
68bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private static final int CAN_PLAY = STATE_READY | STATE_PAUSED | STATE_ENDED;
69bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
70bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * These are the states where we expect the MediaPlayer to be ready in the
71bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * future, so we can set a flag to start playing when it is.
72bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
73bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private static final int CAN_READY_PLAY = STATE_INIT | STATE_PREPARING;
74bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
75bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * The states when it is valid to call pause on the MediaPlayer.
76bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
77bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private static final int CAN_PAUSE = STATE_PLAYING;
78bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
79bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * The states where it is valid to call seek on the MediaPlayer.
80bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
81bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private static final int CAN_SEEK = STATE_READY | STATE_PLAYING | STATE_PAUSED | STATE_ENDED;
82bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
83bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * The states where we expect the MediaPlayer to be ready in the future and
84bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * can store a seek position to set later.
85bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
86bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private static final int CAN_READY_SEEK = STATE_INIT | STATE_PREPARING;
87bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
88bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * The states where it is valid to call stop on the MediaPlayer.
89bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
90bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private static final int CAN_STOP = STATE_READY | STATE_PLAYING | STATE_PAUSED | STATE_ENDED;
91bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
92bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * The states where it is valid to get the current play position and the
93bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * duration from the MediaPlayer.
94bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
95bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private static final int CAN_GET_POSITION = STATE_READY | STATE_PLAYING | STATE_PAUSED;
96bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
97bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
98bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
99bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private class PlayerContent {
100bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        public final String source;
101bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        public final Map<String, String> headers;
102bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
103bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        public PlayerContent(String source, Map<String, String> headers) {
104bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            this.source = source;
105bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            this.headers = headers;
106bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
107bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
108bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
109bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private class AsyncErrorRetriever extends AsyncTask<HttpGet, Void, Void> {
110bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        private final long errorId;
111bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        private boolean closeHttpClient;
112bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
113bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        public AsyncErrorRetriever(long errorId) {
114bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            this.errorId = errorId;
115bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            closeHttpClient = false;
116bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
117bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
118bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        public boolean cancelRequestLocked(boolean closeHttp) {
119bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            closeHttpClient = closeHttp;
120bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            return this.cancel(false);
121bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
122bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
123bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        @Override
124bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        protected Void doInBackground(HttpGet[] params) {
125bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            synchronized (mErrorLock) {
126bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                if (isCancelled() || mHttpClient == null) {
127bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    if (mErrorRetriever == this) {
128bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                        mErrorRetriever = null;
129bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    }
130bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    return null;
131bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                }
132bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                mSafeToCloseClient = false;
133bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            }
134bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            final PlaybackError error = new PlaybackError();
135bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            try {
136bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                HttpResponse response = mHttpClient.execute(params[0]);
137bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                synchronized (mErrorLock) {
138bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    if (mErrorId != errorId || mError == null) {
139bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                        // A new error has occurred, abort
140bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                        return null;
141bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    }
142bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    error.type = mError.type;
143bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    error.extra = mError.extra;
144bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    error.errorMessage = mError.errorMessage;
145bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                }
146bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                final int code = response.getStatusLine().getStatusCode();
147bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                if (code >= 300) {
148bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    error.extra = code;
149bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                }
150bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                final Bundle errorExtras = new Bundle();
151bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                Header[] headers = response.getAllHeaders();
152bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                if (headers != null && headers.length > 0) {
153bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    for (Header header : headers) {
154bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                        errorExtras.putString(header.getName(), header.getValue());
155bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    }
156bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    error.errorExtras = errorExtras;
157bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                }
158bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            } catch (IOException e) {
159bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                Log.e(TAG, "IOException requesting from server, unable to get more exact error");
160bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            } finally {
161bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                synchronized (mErrorLock) {
162bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    mSafeToCloseClient = true;
163bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    if (mErrorRetriever == this) {
164bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                        mErrorRetriever = null;
165bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    }
166bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    if (isCancelled()) {
167bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                        if (closeHttpClient) {
168bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                            mHttpClient.close();
169bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                            mHttpClient = null;
170bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                        }
171bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                        return null;
172bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    }
173bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                }
174bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            }
175bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mHandler.post(new Runnable() {
176bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    @Override
177bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                public void run() {
178bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    synchronized (mErrorLock) {
179bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                        if (mErrorId == errorId) {
180bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                            setError(error.type, error.extra, error.errorExtras, null);
181bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                        }
182bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    }
183bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                }
184bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            });
185bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            return null;
186bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
187bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
188bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
189bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private int mState = STATE_INIT;
190bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
191bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private AudioManager mAudioManager;
192bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private MediaPlayer mPlayer;
193bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private PlayerContent mContent;
194bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private MediaPlayer mNextPlayer;
195bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private PlayerContent mNextContent;
196bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private SurfaceHolder mHolder;
197bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private SurfaceHolder.Callback mHolderCB;
198bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private Context mContext;
199bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
200bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private Handler mHandler = new Handler();
201bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
202bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private AndroidHttpClient mHttpClient = AndroidHttpClient.newInstance("TUQ");
203bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    // The ongoing error request thread if there is one. This should only be
204bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    // modified while mErrorLock is held.
205bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private AsyncErrorRetriever mErrorRetriever;
206bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    // This is set to false while a server request is being made to retrieve
207bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    // the current error. It should only be set while mErrorLock is held.
208bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private boolean mSafeToCloseClient = true;
209bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private final Object mErrorLock = new Object();
210bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    // A tracking id for the current error. This should only be modified while
211bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    // mErrorLock is held.
212bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private long mErrorId = 0;
213bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    // The current error state of this player. This is cleared when the state
214bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    // leaves an error state and set when it enters one. This should only be
215bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    // modified when mErrorLock is held.
216bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private PlaybackError mError;
217bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
218bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private boolean mPlayOnReady;
219bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private int mSeekOnReady;
220bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private boolean mHasAudioFocus;
221bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private long mDebugId = sDebugInstanceId++;
222bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
223bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public LocalRenderer(Context context, Bundle params) {
224bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        super(context, params);
225bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        mContext = context;
226bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
227bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
228bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
229bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
230bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    protected void initFeatures(Bundle params) {
231bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        for (String feature : SUPPORTED_FEATURES) {
232bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mFeatures.add(feature);
233bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
234bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
235bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
236bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
237bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * Call this when completely finished with the MediaPlayerManager to have it
238bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * clean up. The instance may not be used again after this is called.
239bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
240bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
241bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public void onDestroy() {
242bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        synchronized (mErrorLock) {
243bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            if (DEBUG) {
244bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                Log.d(TAG, "onDestroy, error retriever? " + mErrorRetriever + " safe to close? "
245bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                        + mSafeToCloseClient + " client? " + mHttpClient);
246bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            }
247bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            if (mErrorRetriever != null) {
248bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                mErrorRetriever.cancelRequestLocked(true);
249bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                mErrorRetriever = null;
250bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            }
251bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            // Increment the error id to ensure no errors are sent after this
252bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            // point.
253bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mErrorId++;
254bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            if (mSafeToCloseClient) {
255bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                mHttpClient.close();
256bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                mHttpClient = null;
257bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            }
258bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
259bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
260bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
261bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
262bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public void onPrepared(MediaPlayer player) {
263bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (!isCurrentPlayer(player)) {
264bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            return;
265bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
266bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        setState(STATE_READY);
267bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (DEBUG) {
268bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            Log.d(TAG, mDebugId + ": Finished preparing, seekOnReady is " + mSeekOnReady);
269bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
270bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (mSeekOnReady >= 0) {
271bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            onSeekTo(mSeekOnReady);
272bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mSeekOnReady = -1;
273bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
274bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (mPlayOnReady) {
275bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            player.start();
276bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            setState(STATE_PLAYING);
277bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
278bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
279bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
280bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
281bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public void onBufferingUpdate(MediaPlayer player, int percent) {
282bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (!isCurrentPlayer(player)) {
283bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            return;
284bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
285bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        pushOnBufferingUpdate(percent);
286bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
287bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
288bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
289bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public void onCompletion(MediaPlayer player) {
290bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (!isCurrentPlayer(player)) {
291bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            return;
292bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
293bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (DEBUG) {
294bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            Log.d(TAG, mDebugId + ": Completed item. Have next item? " + (mNextPlayer != null));
295bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
296bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (mNextPlayer != null) {
297bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            if (mPlayer != null) {
298bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                mPlayer.release();
299bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            }
300bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mPlayer = mNextPlayer;
301bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mContent = mNextContent;
302bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mNextPlayer = null;
303bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mNextContent = null;
304bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            pushOnNextStarted();
305bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            return;
306bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
307bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        setState(STATE_ENDED);
308bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
309bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
310bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
311bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public boolean onError(MediaPlayer player, int what, int extra) {
312bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (!isCurrentPlayer(player)) {
313bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            return false;
314bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
315bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (DEBUG) {
316bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            Log.d(TAG, mDebugId + ": Entered error state, what: " + what + " extra: " + extra);
317bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
318bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        synchronized (mErrorLock) {
319bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            ++mErrorId;
320bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mError = new PlaybackError();
321bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mError.type = what;
322bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mError.extra = extra;
323bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
324bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
325bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (what == MediaPlayer.MEDIA_ERROR_UNKNOWN && extra == MediaPlayer.MEDIA_ERROR_IO
326bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                && mContent != null && mContent.source.startsWith("http")) {
327bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            HttpGet request = new HttpGet(mContent.source);
328bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            if (mContent.headers != null) {
329bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                for (String key : mContent.headers.keySet()) {
330bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    request.addHeader(key, mContent.headers.get(key));
331bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                }
332bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            }
333bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            synchronized (mErrorLock) {
334bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                if (mErrorRetriever != null) {
335bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    mErrorRetriever.cancelRequestLocked(false);
336bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                }
337bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                mErrorRetriever = new AsyncErrorRetriever(mErrorId);
338bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                mErrorRetriever.execute(request);
339bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            }
340bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        } else {
341bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            setError(what, extra, null, null);
342bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
343bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return true;
344bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
345bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
346bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
347bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public void onAudioFocusChange(int focusChange) {
348bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        // TODO figure out appropriate logic for handling focus loss at the TUQ
349bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        // level.
350bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        switch (focusChange) {
351bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
352bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
353bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                if (mState == STATE_PLAYING) {
354bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    onPause();
355bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    mPlayOnReady = true;
356bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                }
357bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                mHasAudioFocus = false;
358bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                break;
359bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            case AudioManager.AUDIOFOCUS_LOSS:
360bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                if (mState == STATE_PLAYING) {
361bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    onPause();
362bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    mPlayOnReady = false;
363bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                }
364bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                pushOnFocusLost();
365bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                mHasAudioFocus = false;
366bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                break;
367bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            case AudioManager.AUDIOFOCUS_GAIN:
368bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                mHasAudioFocus = true;
369bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                if (mPlayOnReady) {
370bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    onPlay();
371bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                }
372bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                break;
373bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            default:
374bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                Log.d(TAG, "Unknown focus change event " + focusChange);
375bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                break;
376bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
377bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
378bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
379bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
380bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public void setContent(Bundle request) {
381bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        setContent(request, null);
382bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
383bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
384bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
385bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * Prepares the player for the given playback request. If the holder is null
386bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * it is assumed this is an audio only source. If playOnReady is set to true
387bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * the media will begin playing as soon as it can.
38807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik     *
38907c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik     * @see RequestUtils for the set of valid keys.
390bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
391bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public void setContent(Bundle request, SurfaceHolder holder) {
392bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        String source = request.getString(RequestUtils.EXTRA_KEY_SOURCE);
393bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        Map<String, String> headers = null; // request.mHeaders;
394bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        boolean playOnReady = true; // request.mPlayOnReady;
395bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (DEBUG) {
396bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            Log.d(TAG, mDebugId + ": Settings new content. Have a player? " + (mPlayer != null)
397bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    + " have a next player? " + (mNextPlayer != null));
398bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
399bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        cleanUpPlayer();
400bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        setState(STATE_PREPARING);
401bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        mPlayOnReady = playOnReady;
402bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        mSeekOnReady = -1;
403bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        final MediaPlayer newPlayer = new MediaPlayer();
404bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
405bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        requestAudioFocus();
406bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
407bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        mPlayer = newPlayer;
408bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        mContent = new PlayerContent(source, headers);
409bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        try {
410bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            if (headers != null) {
411bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                Uri sourceUri = Uri.parse(source);
412bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                newPlayer.setDataSource(mContext, sourceUri, headers);
413bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            } else {
414bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                newPlayer.setDataSource(source);
415bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            }
416bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        } catch (Exception e) {
417bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            setError(Listener.ERROR_LOAD_FAILED, 0, null, e);
418bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            return;
419bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
420bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (isHolderReady(holder, newPlayer)) {
421bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            preparePlayer(newPlayer, true);
422bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
423bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
424bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
425bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
426bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public void setNextContent(Bundle request) {
427bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        String source = request.getString(RequestUtils.EXTRA_KEY_SOURCE);
428bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        Map<String, String> headers = null; // request.mHeaders;
429bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
430bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        // TODO support video
431bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
432bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (DEBUG) {
433bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            Log.d(TAG, mDebugId + ": Setting next content. Have player? " + (mPlayer != null)
434bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    + " have next player? " + (mNextPlayer != null));
435bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
436bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
437bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (mPlayer == null) {
438bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            // The manager isn't being used to play anything, don't try to
439bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            // set a next.
440bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            return;
441bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
442bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (mNextPlayer != null) {
443bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            // Before setting up the new one clear out the old one and release
444bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            // it to ensure it doesn't play.
445bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mPlayer.setNextMediaPlayer(null);
446bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mNextPlayer.release();
447bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mNextPlayer = null;
448bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mNextContent = null;
449bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
450bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (source == null) {
451bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            // If there's no new content we're done
452bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            return;
453bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
454bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        final MediaPlayer newPlayer = new MediaPlayer();
455bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
456bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        try {
457bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            if (headers != null) {
458bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                Uri sourceUri = Uri.parse(source);
459bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                newPlayer.setDataSource(mContext, sourceUri, headers);
460bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            } else {
461bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                newPlayer.setDataSource(source);
462bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            }
463bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        } catch (Exception e) {
464bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            newPlayer.release();
465bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            // Don't return an error until we get to this item in playback
466bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            return;
467bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
468bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
469bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (preparePlayer(newPlayer, false)) {
470bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mPlayer.setNextMediaPlayer(newPlayer);
471bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mNextPlayer = newPlayer;
472bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mNextContent = new PlayerContent(source, headers);
473bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
474bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
475bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
476bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private void requestAudioFocus() {
477bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        int result = mAudioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
478bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                AudioManager.AUDIOFOCUS_GAIN);
479bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        mHasAudioFocus = result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
480bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
481bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
482bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
483bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * Start the player if possible or queue it to play when ready. If the
484bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * player is in a state where it will never be ready returns false.
485bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     *
486bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * @return true if the content was started or will be started later
487bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
488bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
489bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public boolean onPlay() {
490bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        MediaPlayer player = mPlayer;
491bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (player != null && mState == STATE_PLAYING) {
492bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            // already playing, just return
493bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            return true;
494bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
495bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (!mHasAudioFocus) {
496bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            requestAudioFocus();
497bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
498bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (player != null && canPlay()) {
499bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            player.start();
500bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            setState(STATE_PLAYING);
501bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        } else if (canReadyPlay()) {
502bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mPlayOnReady = true;
503bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        } else if (!isPlaying()) {
504bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            return false;
505bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
506bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return true;
507bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
508bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
509bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
510bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * Pause the player if possible or set it to not play when ready. If the
511bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * player is in a state where it will never be ready returns false.
512bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     *
513bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * @return true if the content was paused or will wait to play when ready
514bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     *         later
515bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
516bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
517bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public boolean onPause() {
518bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        MediaPlayer player = mPlayer;
5198ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        // If the user paused us make sure we won't start playing again until
5208ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        // asked to
5218ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        mPlayOnReady = false;
522bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (player != null && (mState & CAN_PAUSE) != 0) {
523bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            player.pause();
524bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            setState(STATE_PAUSED);
525bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        } else if (!isPaused()) {
526bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            return false;
527bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
528bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return true;
529bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
530bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
531bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
532bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * Seek to a given position in the media. If the seek succeeded or will be
533bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * performed when loading is complete returns true. If the position is not
534bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * in range or the player will never be ready returns false.
535bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     *
536bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * @param position The position to seek to in milliseconds
537bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * @return true if playback was moved or will be moved when ready
538bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
539bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
540bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public boolean onSeekTo(int position) {
541bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        MediaPlayer player = mPlayer;
542bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (player != null && (mState & CAN_SEEK) != 0) {
543bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            if (position < 0 || position >= getDuration()) {
544bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                return false;
545bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            } else {
546bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                if (mState == STATE_ENDED) {
547bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    player.start();
548bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    player.pause();
549bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    setState(STATE_PAUSED);
550bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                }
551bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                player.seekTo(position);
552bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            }
553bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        } else if ((mState & CAN_READY_SEEK) != 0) {
554bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mSeekOnReady = position;
555bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        } else {
556bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            return false;
557bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
558bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return true;
559bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
560bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
561bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
562bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * Stop the player. It cannot be used again until
563bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * {@link #setContent(String, boolean)} is called.
564bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     *
565bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * @return true if stopping the player succeeded
566bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
567bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
568bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public boolean onStop() {
569bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        cleanUpPlayer();
570bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        setState(STATE_STOPPED);
571bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return true;
572bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
573bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
574bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public boolean isPlaying() {
575bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return mState == STATE_PLAYING;
576bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
577bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
578bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public boolean isPaused() {
579bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return mState == STATE_PAUSED;
580bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
581bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
582bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
583bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public long getSeekPosition() {
584bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return ((mState & CAN_GET_POSITION) == 0) ? -1 : mPlayer.getCurrentPosition();
585bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
586bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
587bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
588bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public long getDuration() {
589bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return ((mState & CAN_GET_POSITION) == 0) ? -1 : mPlayer.getDuration();
590bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
591bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
592bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private boolean canPlay() {
593bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return ((mState & CAN_PLAY) != 0) && mHasAudioFocus;
594bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
595bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
596bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private boolean canReadyPlay() {
597bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return (mState & CAN_PLAY) != 0 || (mState & CAN_READY_PLAY) != 0;
598bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
599bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
600bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
601bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * Sends a state update if the listener exists
602bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
603bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private void setState(int state) {
604bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (state == mState) {
605bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            return;
606bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
607bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        Log.d(TAG, "Entering state " + state + " from state " + mState);
608bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        mState = state;
609bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (state != STATE_ERROR) {
610bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            // Don't notify error here, it'll get sent via onError
611bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            pushOnStateChanged(state);
612bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
613bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
614bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
615bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private boolean preparePlayer(final MediaPlayer player, boolean current) {
616bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        player.setOnPreparedListener(this);
617bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        player.setOnBufferingUpdateListener(this);
618bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        player.setOnCompletionListener(this);
619bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        player.setOnErrorListener(this);
620bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        try {
621bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            player.prepareAsync();
622bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            if (current) {
623bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                setState(STATE_PREPARING);
624bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            }
625bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        } catch (IllegalStateException e) {
626bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            if (current) {
627bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                setError(Listener.ERROR_PREPARE_ERROR, 0, null, e);
628bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            }
629bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            return false;
630bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
631bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return true;
632bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
633bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
634bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
635bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * @param extra
636bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * @param e
637bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
638bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private void setError(int type, int extra, Bundle extras, Exception e) {
639bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        setState(STATE_ERROR);
640bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        pushOnError(type, extra, extras, e);
641bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        cleanUpPlayer();
642bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return;
643bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
644bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
645bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
646bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * Checks if the holder is ready and either sets up a callback to wait for
647bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * it or sets it directly. If
648bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     *
649bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * @param holder
650bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * @param player
651bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * @return
652bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
653bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private boolean isHolderReady(final SurfaceHolder holder, final MediaPlayer player) {
654bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        mHolder = holder;
655bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (holder != null) {
656bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            if (holder.getSurface() != null && holder.getSurface().isValid()) {
657bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                player.setDisplay(holder);
658bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                return true;
659bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            } else {
660bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                Log.w(TAG, "Holder not null, waiting for it to be ready");
661bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                // If the holder isn't ready yet add a callback to set the
662bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                // holder when it's ready.
663bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                SurfaceHolder.Callback cb = new SurfaceHolder.Callback() {
664bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                        @Override
665bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    public void surfaceDestroyed(SurfaceHolder arg0) {
666bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    }
667bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
668bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                        @Override
669bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    public void surfaceCreated(SurfaceHolder arg0) {
670bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                        if (player.equals(mPlayer)) {
671bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                            player.setDisplay(arg0);
672bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                            preparePlayer(player, true);
673bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                        }
674bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    }
675bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
676bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                        @Override
677bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
678bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    }
679bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                };
680bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                mHolderCB = cb;
681bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                holder.addCallback(cb);
682bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                return false;
683bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            }
684bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
685bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return true;
686bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
687bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
688bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private void cleanUpPlayer() {
689bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (DEBUG) {
690bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            Log.d(TAG, mDebugId + ": Cleaning up current player");
691bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
692bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        synchronized (mErrorLock) {
693bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mError = null;
694bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            if (mErrorRetriever != null) {
695bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                mErrorRetriever.cancelRequestLocked(false);
696bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                // Don't set to null as we may need to cancel again with true if
697bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                // the object gets destroyed.
698bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            }
699bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
700bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        mAudioManager.abandonAudioFocus(this);
701bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
702bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        SurfaceHolder.Callback cb = mHolderCB;
703bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        mHolderCB = null;
704bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        SurfaceHolder holder = mHolder;
705bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        mHolder = null;
706bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (holder != null && cb != null) {
707bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            holder.removeCallback(cb);
708bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
709bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
710bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        MediaPlayer player = mPlayer;
711bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        mPlayer = null;
712bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (player != null) {
713bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            player.reset();
714bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            player.release();
715bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
716bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
717bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
718bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private boolean isCurrentPlayer(MediaPlayer player) {
719bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return player.equals(mPlayer);
720bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
721bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik}
722