1a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim/* 2a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Copyright (C) 2015 The Android Open Source Project 3a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * 4a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Licensed under the Apache License, Version 2.0 (the "License"); 5a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * you may not use this file except in compliance with the License. 6a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * You may obtain a copy of the License at 7a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * 8a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * http://www.apache.org/licenses/LICENSE-2.0 9a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * 10a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Unless required by applicable law or agreed to in writing, software 11a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * distributed under the License is distributed on an "AS IS" BASIS, 12a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * See the License for the specific language governing permissions and 14a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * limitations under the License. 15a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 16a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 17a907614755847b2630561a1e5949b2b416600d97Sungsoo Limpackage com.example.android.supportv4.media; 18a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 19a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.content.BroadcastReceiver; 20a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.content.Context; 21a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.content.Intent; 22a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.content.IntentFilter; 23a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.media.AudioManager; 24a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.media.MediaPlayer; 25a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.media.session.PlaybackState; 26a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.net.wifi.WifiManager; 27a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.os.PowerManager; 28a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.support.v4.media.MediaMetadataCompat; 29a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.text.TextUtils; 30a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.util.Log; 31a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 32a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport com.example.android.supportv4.media.model.MusicProvider; 33a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport com.example.android.supportv4.media.utils.MediaIDHelper; 34a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 35a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport java.io.IOException; 36a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 37a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport static android.media.MediaPlayer.OnCompletionListener; 38a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport static android.media.MediaPlayer.OnErrorListener; 39a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport static android.media.MediaPlayer.OnPreparedListener; 40a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport static android.media.MediaPlayer.OnSeekCompleteListener; 41a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport static android.support.v4.media.session.MediaSessionCompat.QueueItem; 42a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 43a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim/** 44a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * A class that implements local media playback using {@link android.media.MediaPlayer} 45a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 46a907614755847b2630561a1e5949b2b416600d97Sungsoo Limpublic class Playback implements AudioManager.OnAudioFocusChangeListener, 47a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim OnCompletionListener, OnErrorListener, OnPreparedListener, OnSeekCompleteListener { 48a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 49a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final String TAG = "Playback"; 50a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 51a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // The volume we set the media player to when we lose audio focus, but are 52a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // allowed to reduce the volume instead of stopping playback. 53a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public static final float VOLUME_DUCK = 0.2f; 54a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // The volume we set the media player when we have audio focus. 55a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public static final float VOLUME_NORMAL = 1.0f; 56a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 57a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // we don't have audio focus, and can't duck (play at a low volume) 58a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final int AUDIO_NO_FOCUS_NO_DUCK = 0; 59a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // we don't have focus, but can duck (play at a low volume) 60a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final int AUDIO_NO_FOCUS_CAN_DUCK = 1; 61a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // we have full audio focus 62a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final int AUDIO_FOCUSED = 2; 63a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 64a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private final MediaBrowserServiceSupport mService; 65a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private final WifiManager.WifiLock mWifiLock; 66a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private int mState; 67a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private boolean mPlayOnFocusGain; 68a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private Callback mCallback; 69a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private MusicProvider mMusicProvider; 70a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private volatile boolean mAudioNoisyReceiverRegistered; 71a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private volatile int mCurrentPosition; 72a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private volatile String mCurrentMediaId; 73a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 74a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // Type of audio focus we have: 75a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private int mAudioFocus = AUDIO_NO_FOCUS_NO_DUCK; 76a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private AudioManager mAudioManager; 77a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private MediaPlayer mMediaPlayer; 78a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 79a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private IntentFilter mAudioNoisyIntentFilter = 80a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY); 81a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 82a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private BroadcastReceiver mAudioNoisyReceiver = new BroadcastReceiver() { 83a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim @Override 84a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void onReceive(Context context, Intent intent) { 85a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) { 86a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "Headphones disconnected."); 87a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (isPlaying()) { 88a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Intent i = new Intent(context, MediaBrowserServiceSupport.class); 89a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim i.setAction(MediaBrowserServiceSupport.ACTION_CMD); 90a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim i.putExtra(MediaBrowserServiceSupport.CMD_NAME, MediaBrowserServiceSupport.CMD_PAUSE); 91a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mService.startService(i); 92a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 93a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 94a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 95a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim }; 96a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 97a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public Playback(MediaBrowserServiceSupport service, MusicProvider musicProvider) { 98a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim this.mService = service; 99a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim this.mMusicProvider = musicProvider; 100a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim this.mAudioManager = (AudioManager) service.getSystemService(Context.AUDIO_SERVICE); 101a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // Create the Wifi lock (this does not acquire the lock, this just creates it) 102a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim this.mWifiLock = ((WifiManager) service.getSystemService(Context.WIFI_SERVICE)) 103a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .createWifiLock(WifiManager.WIFI_MODE_FULL, "sample_lock"); 104a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 105a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 106a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void start() { 107a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 108a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 109a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void stop(boolean notifyListeners) { 110a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mState = PlaybackState.STATE_STOPPED; 111a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (notifyListeners && mCallback != null) { 112a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mCallback.onPlaybackStatusChanged(mState); 113a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 114a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mCurrentPosition = getCurrentStreamPosition(); 115a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // Give up Audio focus 116a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim giveUpAudioFocus(); 117a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim unregisterAudioNoisyReceiver(); 118a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // Relax all resources 119a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim relaxResources(true); 120a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mWifiLock.isHeld()) { 121a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mWifiLock.release(); 122a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 123a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 124a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 125a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void setState(int state) { 126a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim this.mState = state; 127a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 128a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 129a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public int getState() { 130a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return mState; 131a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 132a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 133a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public boolean isConnected() { 134a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return true; 135a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 136a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 137a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public boolean isPlaying() { 138a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return mPlayOnFocusGain || (mMediaPlayer != null && mMediaPlayer.isPlaying()); 139a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 140a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 141a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public int getCurrentStreamPosition() { 142a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return mMediaPlayer != null ? 143a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.getCurrentPosition() : mCurrentPosition; 144a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 145a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 146a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void play(QueueItem item) { 147a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mPlayOnFocusGain = true; 148a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim tryToGetAudioFocus(); 149a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim registerAudioNoisyReceiver(); 150a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String mediaId = item.getDescription().getMediaId(); 151a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim boolean mediaHasChanged = !TextUtils.equals(mediaId, mCurrentMediaId); 152a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mediaHasChanged) { 153a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mCurrentPosition = 0; 154a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mCurrentMediaId = mediaId; 155a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 156a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 157a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mState == PlaybackState.STATE_PAUSED && !mediaHasChanged && mMediaPlayer != null) { 158a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim configMediaPlayerState(); 159a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } else { 160a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mState = PlaybackState.STATE_STOPPED; 161a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim relaxResources(false); // release everything except MediaPlayer 162a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim MediaMetadataCompat track = mMusicProvider.getMusic( 163a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim MediaIDHelper.extractMusicIDFromMediaID(item.getDescription().getMediaId())); 164a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 165a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String source = track.getString(MusicProvider.CUSTOM_METADATA_TRACK_SOURCE); 166a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 167a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim try { 168a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim createMediaPlayerIfNeeded(); 169a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 170a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mState = PlaybackState.STATE_BUFFERING; 171a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 172a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 173a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.setDataSource(source); 174a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 175a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // Starts preparing the media player in the background. When 176a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // it's done, it will call our OnPreparedListener (that is, 177a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // the onPrepared() method on this class, since we set the 178a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // listener to 'this'). Until the media player is prepared, 179a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // we *cannot* call start() on it! 180a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.prepareAsync(); 181a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 182a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // If we are streaming from the internet, we want to hold a 183a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // Wifi lock, which prevents the Wifi radio from going to 184a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // sleep while the song is playing. 185a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mWifiLock.acquire(); 186a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 187a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mCallback != null) { 188a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mCallback.onPlaybackStatusChanged(mState); 189a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 190a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 191a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } catch (IOException ex) { 192a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.e(TAG, "Exception playing song", ex); 193a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mCallback != null) { 194a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mCallback.onError(ex.getMessage()); 195a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 196a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 197a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 198a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 199a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 200a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void pause() { 201a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mState == PlaybackState.STATE_PLAYING) { 202a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // Pause media player and cancel the 'foreground service' state. 203a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mMediaPlayer != null && mMediaPlayer.isPlaying()) { 204a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.pause(); 205a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mCurrentPosition = mMediaPlayer.getCurrentPosition(); 206a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 207a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // while paused, retain the MediaPlayer but give up audio focus 208a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim relaxResources(false); 209a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim giveUpAudioFocus(); 210a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 211a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mState = PlaybackState.STATE_PAUSED; 212a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mCallback != null) { 213a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mCallback.onPlaybackStatusChanged(mState); 214a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 215a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim unregisterAudioNoisyReceiver(); 216a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 217a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 218a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void seekTo(int position) { 219a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "seekTo called with " + position); 220a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 221a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mMediaPlayer == null) { 222a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // If we do not have a current media player, simply update the current position 223a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mCurrentPosition = position; 224a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } else { 225a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mMediaPlayer.isPlaying()) { 226a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mState = PlaybackState.STATE_BUFFERING; 227a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 228a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.seekTo(position); 229a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mCallback != null) { 230a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mCallback.onPlaybackStatusChanged(mState); 231a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 232a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 233a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 234a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 235a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void setCallback(Callback callback) { 236a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim this.mCallback = callback; 237a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 238a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 239a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 240a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Try to get the system audio focus. 241a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 242a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private void tryToGetAudioFocus() { 243a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "tryToGetAudioFocus"); 244a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mAudioFocus != AUDIO_FOCUSED) { 245a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim int result = mAudioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, 246a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim AudioManager.AUDIOFOCUS_GAIN); 247a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { 248a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mAudioFocus = AUDIO_FOCUSED; 249a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 250a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 251a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 252a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 253a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 254a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Give up the audio focus. 255a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 256a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private void giveUpAudioFocus() { 257a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "giveUpAudioFocus"); 258a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mAudioFocus == AUDIO_FOCUSED) { 259a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mAudioManager.abandonAudioFocus(this) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { 260a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mAudioFocus = AUDIO_NO_FOCUS_NO_DUCK; 261a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 262a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 263a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 264a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 265a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 266a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Reconfigures MediaPlayer according to audio focus settings and 267a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * starts/restarts it. This method starts/restarts the MediaPlayer 268a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * respecting the current audio focus state. So if we have focus, it will 269a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * play normally; if we don't have focus, it will either leave the 270a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * MediaPlayer paused or set it to a low volume, depending on what is 271a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * allowed by the current focus settings. This method assumes mPlayer != 272a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * null, so if you are calling it, you have to do so from a context where 273a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * you are sure this is the case. 274a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 275a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private void configMediaPlayerState() { 276a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "configMediaPlayerState. mAudioFocus=" + mAudioFocus); 277a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mAudioFocus == AUDIO_NO_FOCUS_NO_DUCK) { 278a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // If we don't have audio focus and can't duck, we have to pause, 279a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mState == PlaybackState.STATE_PLAYING) { 280a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim pause(); 281a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 282a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } else { // we have audio focus: 283a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mAudioFocus == AUDIO_NO_FOCUS_CAN_DUCK) { 284a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.setVolume(VOLUME_DUCK, VOLUME_DUCK); // we'll be relatively quiet 285a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } else { 286a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mMediaPlayer != null) { 287a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.setVolume(VOLUME_NORMAL, VOLUME_NORMAL); // we can be loud again 288a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } // else do something for remote client. 289a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 290a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // If we were playing when we lost focus, we need to resume playing. 291a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mPlayOnFocusGain) { 292a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) { 293a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG,"configMediaPlayerState startMediaPlayer. seeking to " 294a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim + mCurrentPosition); 295a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mCurrentPosition == mMediaPlayer.getCurrentPosition()) { 296a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.start(); 297a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mState = PlaybackState.STATE_PLAYING; 298a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } else { 299a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.seekTo(mCurrentPosition); 300a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mState = PlaybackState.STATE_BUFFERING; 301a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 302a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 303a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mPlayOnFocusGain = false; 304a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 305a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 306a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mCallback != null) { 307a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mCallback.onPlaybackStatusChanged(mState); 308a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 309a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 310a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 311a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 312a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Called by AudioManager on audio focus changes. 313a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Implementation of {@link android.media.AudioManager.OnAudioFocusChangeListener} 314a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 315a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim @Override 316a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void onAudioFocusChange(int focusChange) { 317a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "onAudioFocusChange. focusChange=" + focusChange); 318a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { 319a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // We have gained focus: 320a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mAudioFocus = AUDIO_FOCUSED; 321a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 322a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS || 323a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT || 324a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { 325a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // We have lost focus. If we can duck (low playback volume), we can keep playing. 326a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // Otherwise, we need to pause the playback. 327a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim boolean canDuck = focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK; 328a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mAudioFocus = canDuck ? AUDIO_NO_FOCUS_CAN_DUCK : AUDIO_NO_FOCUS_NO_DUCK; 329a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 330a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // If we are playing, we need to reset media player by calling configMediaPlayerState 331a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // with mAudioFocus properly set. 332a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mState == PlaybackState.STATE_PLAYING && !canDuck) { 333a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // If we don't have audio focus and can't duck, we save the information that 334a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // we were playing, so that we can resume playback once we get the focus back. 335a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mPlayOnFocusGain = true; 336a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 337a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } else { 338a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.e(TAG, "onAudioFocusChange: Ignoring unsupported focusChange: " + focusChange); 339a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 340a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim configMediaPlayerState(); 341a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 342a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 343a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 344a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Called when MediaPlayer has completed a seek 345a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * 346a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * @see android.media.MediaPlayer.OnSeekCompleteListener 347a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 348a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim @Override 349a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void onSeekComplete(MediaPlayer mp) { 350a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "onSeekComplete from MediaPlayer:" + mp.getCurrentPosition()); 351a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mCurrentPosition = mp.getCurrentPosition(); 352a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mState == PlaybackState.STATE_BUFFERING) { 353a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.start(); 354a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mState = PlaybackState.STATE_PLAYING; 355a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 356a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mCallback != null) { 357a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mCallback.onPlaybackStatusChanged(mState); 358a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 359a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 360a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 361a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 362a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Called when media player is done playing current song. 363a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * 364a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * @see android.media.MediaPlayer.OnCompletionListener 365a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 366a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim @Override 367a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void onCompletion(MediaPlayer player) { 368a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "onCompletion from MediaPlayer"); 369a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // The media player finished playing the current song, so we go ahead 370a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // and start the next. 371a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mCallback != null) { 372a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mCallback.onCompletion(); 373a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 374a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 375a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 376a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 377a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Called when media player is done preparing. 378a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * 379a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * @see android.media.MediaPlayer.OnPreparedListener 380a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 381a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim @Override 382a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void onPrepared(MediaPlayer player) { 383a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "onPrepared from MediaPlayer"); 384a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // The media player is done preparing. That means we can start playing if we 385a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // have audio focus. 386a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim configMediaPlayerState(); 387a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 388a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 389a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 390a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Called when there's an error playing media. When this happens, the media 391a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * player goes to the Error state. We warn the user about the error and 392a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * reset the media player. 393a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * 394a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * @see android.media.MediaPlayer.OnErrorListener 395a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 396a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim @Override 397a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public boolean onError(MediaPlayer mp, int what, int extra) { 398a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.e(TAG, "Media player error: what=" + what + ", extra=" + extra); 399a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mCallback != null) { 400a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mCallback.onError("MediaPlayer error " + what + " (" + extra + ")"); 401a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 402a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return true; // true indicates we handled the error 403a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 404a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 405a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 406a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Makes sure the media player exists and has been reset. This will create 407a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * the media player if needed, or reset the existing media player if one 408a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * already exists. 409a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 410a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private void createMediaPlayerIfNeeded() { 411a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "createMediaPlayerIfNeeded. needed? " + (mMediaPlayer==null)); 412a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mMediaPlayer == null) { 413a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer = new MediaPlayer(); 414a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 415a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // Make sure the media player will acquire a wake-lock while 416a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // playing. If we don't do that, the CPU might go to sleep while the 417a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // song is playing, causing playback to stop. 418a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.setWakeMode(mService.getApplicationContext(), 419a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim PowerManager.PARTIAL_WAKE_LOCK); 420a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 421a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // we want the media player to notify us when it's ready preparing, 422a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // and when it's done playing: 423a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.setOnPreparedListener(this); 424a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.setOnCompletionListener(this); 425a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.setOnErrorListener(this); 426a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.setOnSeekCompleteListener(this); 427a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } else { 428a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.reset(); 429a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 430a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 431a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 432a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 433a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Releases resources used by the service for playback. This includes the 434a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * "foreground service" status, the wake locks and possibly the MediaPlayer. 435a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * 436a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * @param releaseMediaPlayer Indicates whether the Media Player should also 437a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * be released or not 438a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 439a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private void relaxResources(boolean releaseMediaPlayer) { 440a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "relaxResources. releaseMediaPlayer=" + releaseMediaPlayer); 441a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 442a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mService.stopForeground(true); 443a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 444a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // stop and release the Media Player, if it's available 445a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (releaseMediaPlayer && mMediaPlayer != null) { 446a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.reset(); 447a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer.release(); 448a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMediaPlayer = null; 449a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 450a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 451a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // we can also release the Wifi lock, if we're holding it 452a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mWifiLock.isHeld()) { 453a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mWifiLock.release(); 454a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 455a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 456a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 457a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private void registerAudioNoisyReceiver() { 458a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (!mAudioNoisyReceiverRegistered) { 459a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mService.registerReceiver(mAudioNoisyReceiver, mAudioNoisyIntentFilter); 460a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mAudioNoisyReceiverRegistered = true; 461a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 462a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 463a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 464a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private void unregisterAudioNoisyReceiver() { 465a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mAudioNoisyReceiverRegistered) { 466a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mService.unregisterReceiver(mAudioNoisyReceiver); 467a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mAudioNoisyReceiverRegistered = false; 468a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 469a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 470a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 471a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim interface Callback { 472a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 473a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * On current music completed. 474a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 475a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim void onCompletion(); 476a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 477a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * on Playback status changed 478a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Implementations can use this callback to update 479a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * playback state on the media sessions. 480a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 481a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim void onPlaybackStatusChanged(int state); 482a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 483a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 484a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * @param error to be added to the PlaybackState 485a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 486a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim void onError(String error); 487a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 488a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 489a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 490a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim} 491