• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.bluetooth.avrcpcontroller;
18 
19 import android.bluetooth.BluetoothDevice;
20 import android.net.Uri;
21 import android.os.SystemClock;
22 import android.support.v4.media.session.MediaSessionCompat;
23 import android.support.v4.media.session.PlaybackStateCompat;
24 import android.util.Log;
25 
26 import java.util.Arrays;
27 
28 /*
29  * Contains information about remote player
30  */
31 class AvrcpPlayer {
32     private static final String TAG = AvrcpPlayer.class.getSimpleName();
33 
34     public static final int DEFAULT_ID = -1;
35 
36     public static final int TYPE_UNKNOWN = -1;
37     public static final int TYPE_AUDIO = 0;
38     public static final int TYPE_VIDEO = 1;
39     public static final int TYPE_BROADCASTING_AUDIO = 2;
40     public static final int TYPE_BROADCASTING_VIDEO = 3;
41 
42     public static final int SUB_TYPE_UNKNOWN = -1;
43     public static final int SUB_TYPE_AUDIO_BOOK = 0;
44     public static final int SUB_TYPE_PODCAST = 1;
45 
46     public static final int FEATURE_PLAY = 40;
47     public static final int FEATURE_STOP = 41;
48     public static final int FEATURE_PAUSE = 42;
49     public static final int FEATURE_REWIND = 44;
50     public static final int FEATURE_FAST_FORWARD = 45;
51     public static final int FEATURE_FORWARD = 47;
52     public static final int FEATURE_PREVIOUS = 48;
53     public static final int FEATURE_BROWSING = 59;
54     public static final int FEATURE_NOW_PLAYING = 65;
55 
56     private final BluetoothDevice mDevice;
57     private int mPlayStatus = PlaybackStateCompat.STATE_NONE;
58     private long mPlayTime = PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN;
59     private float mPlaySpeed = 1;
60     private final int mId;
61     private String mName = "";
62     private byte[] mPlayerFeatures = new byte[16];
63     private long mAvailableActions = PlaybackStateCompat.ACTION_PREPARE;
64     private AvrcpItem mCurrentTrack;
65     private PlaybackStateCompat mPlaybackStateCompat;
66     private PlayerApplicationSettings mSupportedPlayerApplicationSettings =
67             new PlayerApplicationSettings();
68     private PlayerApplicationSettings mCurrentPlayerApplicationSettings;
69 
AvrcpPlayer( BluetoothDevice device, int id, String name, byte[] playerFeatures, int playStatus)70     private AvrcpPlayer(
71             BluetoothDevice device, int id, String name, byte[] playerFeatures, int playStatus) {
72         mDevice = device;
73         mId = id;
74         mName = name;
75         mPlayerFeatures = Arrays.copyOf(playerFeatures, playerFeatures.length);
76         PlaybackStateCompat.Builder playbackStateBuilder =
77                 new PlaybackStateCompat.Builder().setActions(mAvailableActions);
78         mPlaybackStateCompat = playbackStateBuilder.build();
79         updateAvailableActions();
80         setPlayStatus(playStatus);
81     }
82 
getDevice()83     public BluetoothDevice getDevice() {
84         return mDevice;
85     }
86 
getId()87     public int getId() {
88         return mId;
89     }
90 
getName()91     public String getName() {
92         return mName;
93     }
94 
setPlayTime(int playTime)95     public void setPlayTime(int playTime) {
96         mPlayTime = playTime;
97         mPlaybackStateCompat =
98                 new PlaybackStateCompat.Builder(mPlaybackStateCompat)
99                         .setState(mPlayStatus, mPlayTime, mPlaySpeed)
100                         .build();
101     }
102 
getPlayTime()103     public long getPlayTime() {
104         return mPlayTime;
105     }
106 
setPlayStatus(int playStatus)107     public void setPlayStatus(int playStatus) {
108         if (mPlayTime != PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN) {
109             mPlayTime =
110                     (long)
111                             (mPlayTime
112                                     + mPlaySpeed
113                                             * (SystemClock.elapsedRealtime()
114                                                     - mPlaybackStateCompat
115                                                             .getLastPositionUpdateTime()));
116         }
117         mPlayStatus = playStatus;
118         switch (mPlayStatus) {
119             case PlaybackStateCompat.STATE_STOPPED:
120                 mPlaySpeed = 0;
121                 break;
122             case PlaybackStateCompat.STATE_PLAYING:
123                 mPlaySpeed = 1;
124                 break;
125             case PlaybackStateCompat.STATE_PAUSED:
126                 mPlaySpeed = 0;
127                 break;
128             case PlaybackStateCompat.STATE_FAST_FORWARDING:
129                 mPlaySpeed = 3;
130                 break;
131             case PlaybackStateCompat.STATE_REWINDING:
132                 mPlaySpeed = -3;
133                 break;
134         }
135 
136         mPlaybackStateCompat =
137                 new PlaybackStateCompat.Builder(mPlaybackStateCompat)
138                         .setState(mPlayStatus, mPlayTime, mPlaySpeed)
139                         .build();
140     }
141 
setSupportedPlayerApplicationSettings( PlayerApplicationSettings playerApplicationSettings)142     public void setSupportedPlayerApplicationSettings(
143             PlayerApplicationSettings playerApplicationSettings) {
144         mSupportedPlayerApplicationSettings = playerApplicationSettings;
145         updateAvailableActions();
146     }
147 
setCurrentPlayerApplicationSettings( PlayerApplicationSettings playerApplicationSettings)148     public void setCurrentPlayerApplicationSettings(
149             PlayerApplicationSettings playerApplicationSettings) {
150         Log.d(TAG, "Play application settings changed, settings=" + playerApplicationSettings);
151         mCurrentPlayerApplicationSettings = playerApplicationSettings;
152         MediaSessionCompat session = BluetoothMediaBrowserService.getSession();
153         session.setRepeatMode(
154                 mCurrentPlayerApplicationSettings.getSetting(
155                         PlayerApplicationSettings.REPEAT_STATUS));
156         session.setShuffleMode(
157                 mCurrentPlayerApplicationSettings.getSetting(
158                         PlayerApplicationSettings.SHUFFLE_STATUS));
159     }
160 
getPlayStatus()161     public int getPlayStatus() {
162         return mPlayStatus;
163     }
164 
supportsFeature(int featureId)165     public boolean supportsFeature(int featureId) {
166         int byteNumber = featureId / 8;
167         byte bitMask = (byte) (1 << (featureId % 8));
168         return (mPlayerFeatures[byteNumber] & bitMask) == bitMask;
169     }
170 
supportsSetting(int settingType, int settingValue)171     public boolean supportsSetting(int settingType, int settingValue) {
172         return mSupportedPlayerApplicationSettings.supportsSetting(settingType, settingValue);
173     }
174 
getPlaybackState()175     public PlaybackStateCompat getPlaybackState() {
176         Log.d(TAG, "getPlayBackState state " + mPlayStatus + " time " + mPlayTime);
177         return mPlaybackStateCompat;
178     }
179 
updateCurrentTrack(AvrcpItem update)180     public synchronized void updateCurrentTrack(AvrcpItem update) {
181         if (update != null) {
182             long trackNumber = update.getTrackNumber();
183             mPlaybackStateCompat =
184                     new PlaybackStateCompat.Builder(mPlaybackStateCompat)
185                             .setActiveQueueItemId(trackNumber - 1)
186                             .build();
187         }
188         mCurrentTrack = update;
189     }
190 
notifyImageDownload(String uuid, Uri imageUri)191     public synchronized boolean notifyImageDownload(String uuid, Uri imageUri) {
192         Log.d(TAG, "Got an image download -- uuid=" + uuid + ", uri=" + imageUri);
193         if (uuid == null || imageUri == null || mCurrentTrack == null) return false;
194         if (uuid.equals(mCurrentTrack.getCoverArtUuid())) {
195             mCurrentTrack.setCoverArtLocation(imageUri);
196             Log.d(TAG, "Image UUID '" + uuid + "' was added to current track.");
197             return true;
198         }
199         return false;
200     }
201 
getCurrentTrack()202     public synchronized AvrcpItem getCurrentTrack() {
203         return mCurrentTrack;
204     }
205 
updateAvailableActions()206     private void updateAvailableActions() {
207         mAvailableActions = PlaybackStateCompat.ACTION_PREPARE;
208         if (supportsFeature(FEATURE_PLAY)) {
209             mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_PLAY;
210         }
211         if (supportsFeature(FEATURE_STOP)) {
212             mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_STOP;
213         }
214         if (supportsFeature(FEATURE_PAUSE)) {
215             mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_PAUSE;
216         }
217         if (supportsFeature(FEATURE_REWIND)) {
218             mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_REWIND;
219         }
220         if (supportsFeature(FEATURE_FAST_FORWARD)) {
221             mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_FAST_FORWARD;
222         }
223         if (supportsFeature(FEATURE_FORWARD)) {
224             mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_SKIP_TO_NEXT;
225         }
226         if (supportsFeature(FEATURE_PREVIOUS)) {
227             mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS;
228         }
229         if (mSupportedPlayerApplicationSettings.supportsSetting(
230                 PlayerApplicationSettings.REPEAT_STATUS)) {
231             mAvailableActions |= PlaybackStateCompat.ACTION_SET_REPEAT_MODE;
232         }
233         if (mSupportedPlayerApplicationSettings.supportsSetting(
234                 PlayerApplicationSettings.SHUFFLE_STATUS)) {
235             mAvailableActions |= PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE;
236         }
237         mPlaybackStateCompat =
238                 new PlaybackStateCompat.Builder(mPlaybackStateCompat)
239                         .setActions(mAvailableActions)
240                         .build();
241 
242         Log.d(TAG, "Supported Actions = " + mAvailableActions);
243     }
244 
245     @Override
toString()246     public String toString() {
247         return "<AvrcpPlayer id="
248                 + mId
249                 + " name="
250                 + mName
251                 + " track="
252                 + mCurrentTrack
253                 + " playState="
254                 + AvrcpControllerUtils.playbackStateCompatToString(mPlaybackStateCompat)
255                 + ">";
256     }
257 
258     /** A Builder object for an AvrcpPlayer */
259     public static class Builder {
260         private BluetoothDevice mDevice = null;
261         private int mPlayerId = AvrcpPlayer.DEFAULT_ID;
262         private String mPlayerName = null;
263         private byte[] mSupportedFeatures = new byte[16];
264 
265         private int mPlayStatus = PlaybackStateCompat.STATE_NONE;
266 
267         private AvrcpItem mTrack = null;
268 
269         /**
270          * Set the device that this Player came from
271          *
272          * @param device The BluetoothDevice representing the remote device
273          * @return This object, so you can continue building
274          */
setDevice(BluetoothDevice device)275         public Builder setDevice(BluetoothDevice device) {
276             mDevice = device;
277             return this;
278         }
279 
280         /**
281          * Set the Player ID for this Player
282          *
283          * @param playerId The ID for this player, defined in AVRCP 6.10.2.1
284          * @return This object, so you can continue building
285          */
setPlayerId(int playerId)286         public Builder setPlayerId(int playerId) {
287             mPlayerId = playerId;
288             return this;
289         }
290 
291         /**
292          * Set the name for this Player. This is what users will see when browsing.
293          *
294          * @param name The name for this player, defined in AVRCP 6.10.2.1
295          * @return This object, so you can continue building
296          */
setName(String name)297         public Builder setName(String name) {
298             mPlayerName = name;
299             return this;
300         }
301 
302         /**
303          * Set the entire set of supported features for this Player.
304          *
305          * @param supportedFeatures The feature set for this player, defined in AVRCP 6.10.2.1
306          * @return This object, so you can continue building
307          */
setSupportedFeatures(byte[] supportedFeatures)308         public Builder setSupportedFeatures(byte[] supportedFeatures) {
309             mSupportedFeatures = supportedFeatures;
310             return this;
311         }
312 
313         /**
314          * Set a single features as supported for this Player.
315          *
316          * @param feature The feature for this player, defined in AVRCP 6.10.2.1
317          * @return This object, so you can continue building
318          */
setSupportedFeature(int feature)319         public Builder setSupportedFeature(int feature) {
320             int byteNumber = feature / 8;
321             byte bitMask = (byte) (1 << (feature % 8));
322             mSupportedFeatures[byteNumber] = (byte) (mSupportedFeatures[byteNumber] | bitMask);
323             return this;
324         }
325 
326         /**
327          * Set the initial play status of the Player.
328          *
329          * @param playStatus The play state for this player as a PlaybackStateCompat.STATE_* value
330          * @return This object, so you can continue building
331          */
setPlayStatus(int playStatus)332         public Builder setPlayStatus(int playStatus) {
333             mPlayStatus = playStatus;
334             return this;
335         }
336 
337         /**
338          * Set the initial play status of the Player.
339          *
340          * @param track The initial track for this player
341          * @return This object, so you can continue building
342          */
setCurrentTrack(AvrcpItem track)343         public Builder setCurrentTrack(AvrcpItem track) {
344             mTrack = track;
345             return this;
346         }
347 
build()348         public AvrcpPlayer build() {
349             AvrcpPlayer player =
350                     new AvrcpPlayer(
351                             mDevice, mPlayerId, mPlayerName, mSupportedFeatures, mPlayStatus);
352             player.updateCurrentTrack(mTrack);
353             return player;
354         }
355     }
356 }
357