Loading src/com/android/bluetooth/avrcp/AddressedMediaPlayer.java +23 −12 Original line number Original line Diff line number Diff line Loading @@ -45,15 +45,19 @@ public class AddressedMediaPlayer { private AvrcpMediaRspInterface mMediaInterface; private AvrcpMediaRspInterface mMediaInterface; private List<MediaSession.QueueItem> mNowPlayingList; private List<MediaSession.QueueItem> mNowPlayingList; private long mLastTrackIdSent; public AddressedMediaPlayer(AvrcpMediaRspInterface mediaInterface) { public AddressedMediaPlayer(AvrcpMediaRspInterface mediaInterface) { mNowPlayingList = null; mNowPlayingList = null; mMediaInterface = mediaInterface; mMediaInterface = mediaInterface; mLastTrackIdSent = MediaSession.QueueItem.UNKNOWN_ID; } } void cleanup() { void cleanup() { if (DEBUG) Log.v(TAG, "cleanup"); if (DEBUG) Log.v(TAG, "cleanup"); mNowPlayingList = null; mNowPlayingList = null; mMediaInterface = null; mMediaInterface = null; mLastTrackIdSent = MediaSession.QueueItem.UNKNOWN_ID; } } /* get now playing list from addressed player */ /* get now playing list from addressed player */ Loading Loading @@ -242,22 +246,27 @@ public class AddressedMediaPlayer { mMediaInterface.getTotalNumOfItemsRsp(bdaddr, AvrcpConstants.RSP_NO_ERROR, 0, items.size()); mMediaInterface.getTotalNumOfItemsRsp(bdaddr, AvrcpConstants.RSP_NO_ERROR, 0, items.size()); } } void sendTrackChangeWithId(int trackChangedNT, MediaController mediaController) { boolean sendTrackChangeWithId(boolean requesting, MediaController mediaController) { if (DEBUG) Log.d(TAG, "sendTrackChangeWithId"); if (DEBUG) Log.d(TAG, "sendTrackChangeWithId"); byte[] track; byte[] track; if (mediaController == null) { mMediaInterface.trackChangedRsp(trackChangedNT, AvrcpConstants.NO_TRACK_SELECTED); return; } long qid = MediaSession.QueueItem.UNKNOWN_ID; long qid = MediaSession.QueueItem.UNKNOWN_ID; if (mediaController != null) { PlaybackState state = mediaController.getPlaybackState(); PlaybackState state = mediaController.getPlaybackState(); if (state != null) { qid = state.getActiveQueueItemId(); } /* for any item associated with NowPlaying, uid is queueId */ /* for any item associated with NowPlaying, uid is queueId */ if (state != null) qid = state.getActiveQueueItemId(); } if (!requesting && qid == mLastTrackIdSent) { if (DEBUG) Log.d(TAG, "not sending duplicate track changed id " + qid); return false; } track = ByteBuffer.allocate(AvrcpConstants.UID_SIZE).putLong(qid).array(); track = ByteBuffer.allocate(AvrcpConstants.UID_SIZE).putLong(qid).array(); if (DEBUG) Log.d(TAG, "trackChangedRsp: 0x" + Utils.byteArrayToString(track)); if (DEBUG) Log.d(TAG, "trackChangedRsp: 0x" + Utils.byteArrayToString(track)); int trackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; if (requesting) trackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM; mMediaInterface.trackChangedRsp(trackChangedNT, track); mMediaInterface.trackChangedRsp(trackChangedNT, track); mLastTrackIdSent = qid; return (trackChangedNT == AvrcpConstants.NOTIFICATION_TYPE_CHANGED); } } /* /* Loading Loading @@ -418,11 +427,13 @@ public class AddressedMediaPlayer { break; break; case AvrcpConstants.ATTRID_TRACK_NUM: case AvrcpConstants.ATTRID_TRACK_NUM: attrValue = extras.getString(MediaMetadata.METADATA_KEY_TRACK_NUMBER); attrValue = Long.toString(extras.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER)); break; break; case AvrcpConstants.ATTRID_NUM_TRACKS: case AvrcpConstants.ATTRID_NUM_TRACKS: attrValue = extras.getString(MediaMetadata.METADATA_KEY_NUM_TRACKS); attrValue = Long.toString(extras.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS)); break; break; case AvrcpConstants.ATTRID_GENRE: case AvrcpConstants.ATTRID_GENRE: Loading @@ -430,7 +441,7 @@ public class AddressedMediaPlayer { break; break; case AvrcpConstants.ATTRID_PLAY_TIME: case AvrcpConstants.ATTRID_PLAY_TIME: attrValue = extras.getString(MediaMetadata.METADATA_KEY_DURATION); attrValue = Long.toString(extras.getLong(MediaMetadata.METADATA_KEY_DURATION)); break; break; case AvrcpConstants.ATTRID_COVER_ART: case AvrcpConstants.ATTRID_COVER_ART: Loading src/com/android/bluetooth/avrcp/Avrcp.java +76 −85 Original line number Original line Diff line number Diff line Loading @@ -81,12 +81,11 @@ public final class Avrcp { private PackageManager mPackageManager; private PackageManager mPackageManager; private int mTransportControlFlags; private int mTransportControlFlags; private PlaybackState mCurrentPlayState; private PlaybackState mCurrentPlayState; private long mLastStateUpdate; private int mA2dpState; private int mPlayStatusChangedNT; private int mPlayStatusChangedNT; private int mTrackChangedNT; private int mTrackChangedNT; private int mPlayPosChangedNT; private int mPlayPosChangedNT; private long mTracksPlayed; private long mTracksPlayed; private long mSongLengthMs; private long mPlaybackIntervalMs; private long mPlaybackIntervalMs; private long mLastReportedPosition; private long mLastReportedPosition; private long mNextPosMs; private long mNextPosMs; Loading Loading @@ -235,11 +234,10 @@ public final class Avrcp { private Avrcp(Context context) { private Avrcp(Context context) { mMediaAttributes = new MediaAttributes(null); mMediaAttributes = new MediaAttributes(null); mCurrentPlayState = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE, -1L, 0.0f).build(); mCurrentPlayState = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE, -1L, 0.0f).build(); mA2dpState = BluetoothA2dp.STATE_NOT_PLAYING; mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; mTracksPlayed = 0; mTracksPlayed = 0; mLastStateUpdate = -1L; mSongLengthMs = 0L; mPlaybackIntervalMs = 0L; mPlaybackIntervalMs = 0L; mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; mLastReportedPosition = -1; mLastReportedPosition = -1; Loading Loading @@ -364,24 +362,13 @@ public final class Avrcp { @Override @Override public void onMetadataChanged(MediaMetadata metadata) { public void onMetadataChanged(MediaMetadata metadata) { Log.v(TAG, "MediaController metadata changed"); Log.v(TAG, "MediaController metadata changed"); updateMetadata(metadata); updateCurrentMediaState(); } } @Override @Override public synchronized void onPlaybackStateChanged(PlaybackState state) { public synchronized void onPlaybackStateChanged(PlaybackState state) { if (DEBUG) Log.v(TAG, "onPlaybackStateChanged: state " + state.toString()); if (DEBUG) Log.v(TAG, "onPlaybackStateChanged: state " + state.toString()); updateCurrentMediaState(); updatePlaybackState(state); byte stateBytes = (byte) convertPlayStateToBytes(state.getState()); /* updating play status in global media player list */ MediaPlayerInfo player = getAddressedPlayerInfo(); if (player != null) { player.setPlayStatus(stateBytes); } else { Log.w(TAG, "onPlaybackStateChanged: no addressed player id=" + mCurrAddrPlayerID); } } } @Override @Override Loading Loading @@ -434,7 +421,7 @@ public final class Avrcp { byte[] address = (byte[]) msg.obj; byte[] address = (byte[]) msg.obj; if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_PLAY_STATUS"); if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_PLAY_STATUS"); getPlayStatusRspNative(address, convertPlayStateToPlayStatus(mCurrentPlayState), getPlayStatusRspNative(address, convertPlayStateToPlayStatus(mCurrentPlayState), (int) mSongLengthMs, (int) getPlayPosition()); (int) mMediaAttributes.getLength(), (int) getPlayPosition()); break; break; } } Loading Loading @@ -699,7 +686,8 @@ public final class Avrcp { case MSG_SET_A2DP_AUDIO_STATE: case MSG_SET_A2DP_AUDIO_STATE: if (DEBUG) Log.v(TAG, "MSG_SET_A2DP_AUDIO_STATE:" + msg.arg1); if (DEBUG) Log.v(TAG, "MSG_SET_A2DP_AUDIO_STATE:" + msg.arg1); updateA2dpAudioState(msg.arg1); mA2dpState = msg.arg1; updateCurrentMediaState(); break; break; case MSG_NATIVE_REQ_GET_FOLDER_ITEMS: { case MSG_NATIVE_REQ_GET_FOLDER_ITEMS: { Loading Loading @@ -792,30 +780,22 @@ public final class Avrcp { } } } } private void updateA2dpAudioState(int state) { boolean isPlaying = (state == BluetoothA2dp.STATE_PLAYING); if (isPlaying != isPlayingState(mCurrentPlayState)) { /* if a2dp is streaming, check to make sure music is active */ if (isPlaying && !mAudioManager.isMusicActive()) return; PlaybackState.Builder builder = new PlaybackState.Builder(); if (isPlaying) { builder.setState(PlaybackState.STATE_PLAYING, PlaybackState.PLAYBACK_POSITION_UNKNOWN, 1.0f); } else { builder.setState(PlaybackState.STATE_PAUSED, PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f); } updatePlaybackState(builder.build()); } } private void updatePlaybackState(PlaybackState state) { private void updatePlaybackState(PlaybackState state) { if (state == null) { if (state == null) { state = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE, state = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE, PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f).build(); PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f).build(); } } byte stateBytes = (byte) convertPlayStateToBytes(state.getState()); /* updating play status in global media player list */ MediaPlayerInfo player = getAddressedPlayerInfo(); if (player != null) { player.setPlayStatus(stateBytes); } else { Log.w(TAG, "onPlaybackStateChanged: no addressed player id=" + mCurrAddrPlayerID); } int oldPlayStatus = convertPlayStateToPlayStatus(mCurrentPlayState); int oldPlayStatus = convertPlayStateToPlayStatus(mCurrentPlayState); int newPlayStatus = convertPlayStateToPlayStatus(state); int newPlayStatus = convertPlayStateToPlayStatus(state); Loading @@ -826,7 +806,6 @@ public final class Avrcp { } } mCurrentPlayState = state; mCurrentPlayState = state; mLastStateUpdate = SystemClock.elapsedRealtime(); sendPlayPosNotificationRsp(false); sendPlayPosNotificationRsp(false); Loading @@ -849,7 +828,7 @@ public final class Avrcp { private String mediaNumber; private String mediaNumber; private String mediaTotalNumber; private String mediaTotalNumber; private String genre; private String genre; private String playingTimeMs; private long playingTimeMs; private static final int ATTR_TITLE = 1; private static final int ATTR_TITLE = 1; private static final int ATTR_ARTIST_NAME = 2; private static final int ATTR_ARTIST_NAME = 2; Loading @@ -870,7 +849,7 @@ public final class Avrcp { mediaNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER)); mediaNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER)); mediaTotalNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS)); mediaTotalNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS)); genre = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_GENRE)); genre = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_GENRE)); playingTimeMs = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_DURATION)); playingTimeMs = data.getLong(MediaMetadata.METADATA_KEY_DURATION); // Try harder for the title. // Try harder for the title. title = data.getString(MediaMetadata.METADATA_KEY_TITLE); title = data.getString(MediaMetadata.METADATA_KEY_TITLE); Loading @@ -888,6 +867,11 @@ public final class Avrcp { title = new String(); title = new String(); } } public long getLength() { if (!exists) return 0L; return playingTimeMs; } public boolean equals(MediaAttributes other) { public boolean equals(MediaAttributes other) { if (other == null) if (other == null) return false; return false; Loading @@ -898,13 +882,11 @@ public final class Avrcp { if (exists == false) if (exists == false) return true; return true; return (title.equals(other.title)) && return (title.equals(other.title)) && (artistName.equals(other.artistName)) (artistName.equals(other.artistName)) && && (albumName.equals(other.albumName)) (albumName.equals(other.albumName)) && && (mediaNumber.equals(other.mediaNumber)) (mediaNumber.equals(other.mediaNumber)) && && (mediaTotalNumber.equals(other.mediaTotalNumber)) (mediaTotalNumber.equals(other.mediaTotalNumber)) && && (genre.equals(other.genre)) && (playingTimeMs == other.playingTimeMs); (genre.equals(other.genre)) && (playingTimeMs.equals(other.playingTimeMs)); } } public String getString(int attrId) { public String getString(int attrId) { Loading @@ -925,7 +907,7 @@ public final class Avrcp { case ATTR_GENRE: case ATTR_GENRE: return genre; return genre; case ATTR_PLAYING_TIME_MS: case ATTR_PLAYING_TIME_MS: return playingTimeMs; return Long.toString(playingTimeMs); default: default: return new String(); return new String(); } } Loading @@ -944,40 +926,47 @@ public final class Avrcp { return "[MediaAttributes: none]"; return "[MediaAttributes: none]"; } } return "[MediaAttributes: " + title + " - " + albumName + " by " return "[MediaAttributes: " + title + " - " + albumName + " by " + artistName + " (" + artistName + " (" + mediaNumber + "/" + mediaTotalNumber + ") " + playingTimeMs + " " + mediaNumber + "/" + mediaTotalNumber + ") " + genre + genre + "]"; + "]"; } } } } private void updateMetadata(MediaMetadata data) { private void updateCurrentMediaState() { MediaAttributes oldAttributes = mMediaAttributes; if (mMediaController == null) { mMediaAttributes = new MediaAttributes(data); // Use A2DP state if we don't have a MediaControlller if (data == null) { boolean isPlaying = (mA2dpState == BluetoothA2dp.STATE_PLAYING); mSongLengthMs = 0L; if (isPlaying != isPlayingState(mCurrentPlayState)) { /* if a2dp is streaming, check to make sure music is active */ if (isPlaying && !mAudioManager.isMusicActive()) return; PlaybackState.Builder builder = new PlaybackState.Builder(); if (isPlaying) { builder.setState(PlaybackState.STATE_PLAYING, PlaybackState.PLAYBACK_POSITION_UNKNOWN, 1.0f); } else { } else { mSongLengthMs = data.getLong(MediaMetadata.METADATA_KEY_DURATION); builder.setState(PlaybackState.STATE_PAUSED, PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f); } updatePlaybackState(builder.build()); } // Can't get metadata from A2dp so we're done. return; } } if (!oldAttributes.equals(mMediaAttributes)) { MediaAttributes currentAttributes = mMediaAttributes; PlaybackState newState = mMediaController.getPlaybackState(); // Metadata mMediaAttributes = new MediaAttributes(mMediaController.getMetadata()); if (currentAttributes.equals(mMediaAttributes)) { Log.v(TAG, "MediaAttributes Changed to " + mMediaAttributes.toString()); Log.v(TAG, "MediaAttributes Changed to " + mMediaAttributes.toString()); mTracksPlayed++; mTracksPlayed++; sendTrackChangedRsp(false); if (mTrackChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM) { mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; sendTrackChangedRsp(); } } else { Log.v(TAG, "Updated " + mMediaAttributes.toString() + " but no change!"); } } // Update the play state, which sends play state and play position // notifications if needed. if (mMediaController != null) { updatePlaybackState(mMediaController.getPlaybackState()); updatePlaybackState(mMediaController.getPlaybackState()); } else { updatePlaybackState(null); } } } private void getRcFeaturesRequestFromNative(byte[] address, int features) { private void getRcFeaturesRequestFromNative(byte[] address, int features) { Loading Loading @@ -1021,7 +1010,7 @@ public final class Avrcp { case EVT_TRACK_CHANGED: case EVT_TRACK_CHANGED: Log.v(TAG, "Track changed notification enabled"); Log.v(TAG, "Track changed notification enabled"); mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM; mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM; sendTrackChangedRsp(); sendTrackChangedRsp(true); break; break; case EVT_PLAY_POS_CHANGED: case EVT_PLAY_POS_CHANGED: Loading Loading @@ -1068,22 +1057,25 @@ public final class Avrcp { mHandler.sendMessage(msg); mHandler.sendMessage(msg); } } private void sendTrackChangedRsp() { private void sendTrackChangedRsp(boolean requested) { MediaPlayerInfo info = getAddressedPlayerInfo(); MediaPlayerInfo info = getAddressedPlayerInfo(); if (info != null && !info.isBrowseSupported()) { if (info != null && !info.isBrowseSupported()) { // for players which does not support Browse or when no track is currently selected // for players which does not support Browse or when no track is currently selected trackChangeRspForBrowseUnsupported(); trackChangeRspForBrowseUnsupported(requested); } else { } else { boolean changed = mAddressedMediaPlayer.sendTrackChangeWithId(requested, mMediaController); // for players which support browsing // for players which support browsing mAddressedMediaPlayer.sendTrackChangeWithId(mTrackChangedNT, mMediaController); if (changed) mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; } } } } private void trackChangeRspForBrowseUnsupported() { private void trackChangeRspForBrowseUnsupported(boolean requested) { byte[] track = AvrcpConstants.TRACK_IS_SELECTED; byte[] track = AvrcpConstants.TRACK_IS_SELECTED; if (mTrackChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM if (requested && !mMediaAttributes.exists) { && !mMediaAttributes.exists) { track = AvrcpConstants.NO_TRACK_SELECTED; track = AvrcpConstants.NO_TRACK_SELECTED; } else if (!requested) { mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; } } registerNotificationRspTrackChangeNative(mTrackChangedNT, track); registerNotificationRspTrackChangeNative(mTrackChangedNT, track); } } Loading @@ -1098,7 +1090,9 @@ public final class Avrcp { } } if (isPlayingState(mCurrentPlayState)) { if (isPlayingState(mCurrentPlayState)) { return SystemClock.elapsedRealtime() - mLastStateUpdate + mCurrentPlayState.getPosition(); long sinceUpdate = (SystemClock.elapsedRealtime() - mCurrentPlayState.getLastPositionUpdateTime()); return sinceUpdate + mCurrentPlayState.getPosition(); } } return mCurrentPlayState.getPosition(); return mCurrentPlayState.getPosition(); Loading Loading @@ -2105,13 +2099,12 @@ public final class Avrcp { if (newController != null) { if (newController != null) { mMediaController = newController; mMediaController = newController; mMediaController.registerCallback(mMediaControllerCb, mHandler); mMediaController.registerCallback(mMediaControllerCb, mHandler); updateMetadata(mMediaController.getMetadata()); mAddressedMediaPlayer.updateNowPlayingList(mMediaController.getQueue()); mAddressedMediaPlayer.updateNowPlayingList(mMediaController.getQueue()); } else { } else { updateMetadata(null); mAddressedMediaPlayer.updateNowPlayingList(null); mAddressedMediaPlayer.updateNowPlayingList(null); registerRsp = false; registerRsp = false; } } updateCurrentMediaState(); } } return registerRsp; return registerRsp; } } Loading Loading @@ -2264,10 +2257,8 @@ public final class Avrcp { ProfileService.println(sb, "mTransportControlFlags: " + mTransportControlFlags); ProfileService.println(sb, "mTransportControlFlags: " + mTransportControlFlags); ProfileService.println(sb, "mTracksPlayed: " + mTracksPlayed); ProfileService.println(sb, "mTracksPlayed: " + mTracksPlayed); ProfileService.println(sb, "mCurrentPlayState: " + mCurrentPlayState); ProfileService.println(sb, "mCurrentPlayState: " + mCurrentPlayState); ProfileService.println(sb, "mLastStateUpdate: " + mLastStateUpdate); ProfileService.println(sb, "mPlayStatusChangedNT: " + mPlayStatusChangedNT); ProfileService.println(sb, "mPlayStatusChangedNT: " + mPlayStatusChangedNT); ProfileService.println(sb, "mTrackChangedNT: " + mTrackChangedNT); ProfileService.println(sb, "mTrackChangedNT: " + mTrackChangedNT); ProfileService.println(sb, "mSongLengthMs: " + mSongLengthMs); ProfileService.println(sb, "mPlaybackIntervalMs: " + mPlaybackIntervalMs); ProfileService.println(sb, "mPlaybackIntervalMs: " + mPlaybackIntervalMs); ProfileService.println(sb, "mPlayPosChangedNT: " + mPlayPosChangedNT); ProfileService.println(sb, "mPlayPosChangedNT: " + mPlayPosChangedNT); ProfileService.println(sb, "mNextPosMs: " + mNextPosMs); ProfileService.println(sb, "mNextPosMs: " + mNextPosMs); Loading Loading
src/com/android/bluetooth/avrcp/AddressedMediaPlayer.java +23 −12 Original line number Original line Diff line number Diff line Loading @@ -45,15 +45,19 @@ public class AddressedMediaPlayer { private AvrcpMediaRspInterface mMediaInterface; private AvrcpMediaRspInterface mMediaInterface; private List<MediaSession.QueueItem> mNowPlayingList; private List<MediaSession.QueueItem> mNowPlayingList; private long mLastTrackIdSent; public AddressedMediaPlayer(AvrcpMediaRspInterface mediaInterface) { public AddressedMediaPlayer(AvrcpMediaRspInterface mediaInterface) { mNowPlayingList = null; mNowPlayingList = null; mMediaInterface = mediaInterface; mMediaInterface = mediaInterface; mLastTrackIdSent = MediaSession.QueueItem.UNKNOWN_ID; } } void cleanup() { void cleanup() { if (DEBUG) Log.v(TAG, "cleanup"); if (DEBUG) Log.v(TAG, "cleanup"); mNowPlayingList = null; mNowPlayingList = null; mMediaInterface = null; mMediaInterface = null; mLastTrackIdSent = MediaSession.QueueItem.UNKNOWN_ID; } } /* get now playing list from addressed player */ /* get now playing list from addressed player */ Loading Loading @@ -242,22 +246,27 @@ public class AddressedMediaPlayer { mMediaInterface.getTotalNumOfItemsRsp(bdaddr, AvrcpConstants.RSP_NO_ERROR, 0, items.size()); mMediaInterface.getTotalNumOfItemsRsp(bdaddr, AvrcpConstants.RSP_NO_ERROR, 0, items.size()); } } void sendTrackChangeWithId(int trackChangedNT, MediaController mediaController) { boolean sendTrackChangeWithId(boolean requesting, MediaController mediaController) { if (DEBUG) Log.d(TAG, "sendTrackChangeWithId"); if (DEBUG) Log.d(TAG, "sendTrackChangeWithId"); byte[] track; byte[] track; if (mediaController == null) { mMediaInterface.trackChangedRsp(trackChangedNT, AvrcpConstants.NO_TRACK_SELECTED); return; } long qid = MediaSession.QueueItem.UNKNOWN_ID; long qid = MediaSession.QueueItem.UNKNOWN_ID; if (mediaController != null) { PlaybackState state = mediaController.getPlaybackState(); PlaybackState state = mediaController.getPlaybackState(); if (state != null) { qid = state.getActiveQueueItemId(); } /* for any item associated with NowPlaying, uid is queueId */ /* for any item associated with NowPlaying, uid is queueId */ if (state != null) qid = state.getActiveQueueItemId(); } if (!requesting && qid == mLastTrackIdSent) { if (DEBUG) Log.d(TAG, "not sending duplicate track changed id " + qid); return false; } track = ByteBuffer.allocate(AvrcpConstants.UID_SIZE).putLong(qid).array(); track = ByteBuffer.allocate(AvrcpConstants.UID_SIZE).putLong(qid).array(); if (DEBUG) Log.d(TAG, "trackChangedRsp: 0x" + Utils.byteArrayToString(track)); if (DEBUG) Log.d(TAG, "trackChangedRsp: 0x" + Utils.byteArrayToString(track)); int trackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; if (requesting) trackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM; mMediaInterface.trackChangedRsp(trackChangedNT, track); mMediaInterface.trackChangedRsp(trackChangedNT, track); mLastTrackIdSent = qid; return (trackChangedNT == AvrcpConstants.NOTIFICATION_TYPE_CHANGED); } } /* /* Loading Loading @@ -418,11 +427,13 @@ public class AddressedMediaPlayer { break; break; case AvrcpConstants.ATTRID_TRACK_NUM: case AvrcpConstants.ATTRID_TRACK_NUM: attrValue = extras.getString(MediaMetadata.METADATA_KEY_TRACK_NUMBER); attrValue = Long.toString(extras.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER)); break; break; case AvrcpConstants.ATTRID_NUM_TRACKS: case AvrcpConstants.ATTRID_NUM_TRACKS: attrValue = extras.getString(MediaMetadata.METADATA_KEY_NUM_TRACKS); attrValue = Long.toString(extras.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS)); break; break; case AvrcpConstants.ATTRID_GENRE: case AvrcpConstants.ATTRID_GENRE: Loading @@ -430,7 +441,7 @@ public class AddressedMediaPlayer { break; break; case AvrcpConstants.ATTRID_PLAY_TIME: case AvrcpConstants.ATTRID_PLAY_TIME: attrValue = extras.getString(MediaMetadata.METADATA_KEY_DURATION); attrValue = Long.toString(extras.getLong(MediaMetadata.METADATA_KEY_DURATION)); break; break; case AvrcpConstants.ATTRID_COVER_ART: case AvrcpConstants.ATTRID_COVER_ART: Loading
src/com/android/bluetooth/avrcp/Avrcp.java +76 −85 Original line number Original line Diff line number Diff line Loading @@ -81,12 +81,11 @@ public final class Avrcp { private PackageManager mPackageManager; private PackageManager mPackageManager; private int mTransportControlFlags; private int mTransportControlFlags; private PlaybackState mCurrentPlayState; private PlaybackState mCurrentPlayState; private long mLastStateUpdate; private int mA2dpState; private int mPlayStatusChangedNT; private int mPlayStatusChangedNT; private int mTrackChangedNT; private int mTrackChangedNT; private int mPlayPosChangedNT; private int mPlayPosChangedNT; private long mTracksPlayed; private long mTracksPlayed; private long mSongLengthMs; private long mPlaybackIntervalMs; private long mPlaybackIntervalMs; private long mLastReportedPosition; private long mLastReportedPosition; private long mNextPosMs; private long mNextPosMs; Loading Loading @@ -235,11 +234,10 @@ public final class Avrcp { private Avrcp(Context context) { private Avrcp(Context context) { mMediaAttributes = new MediaAttributes(null); mMediaAttributes = new MediaAttributes(null); mCurrentPlayState = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE, -1L, 0.0f).build(); mCurrentPlayState = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE, -1L, 0.0f).build(); mA2dpState = BluetoothA2dp.STATE_NOT_PLAYING; mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; mTracksPlayed = 0; mTracksPlayed = 0; mLastStateUpdate = -1L; mSongLengthMs = 0L; mPlaybackIntervalMs = 0L; mPlaybackIntervalMs = 0L; mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; mLastReportedPosition = -1; mLastReportedPosition = -1; Loading Loading @@ -364,24 +362,13 @@ public final class Avrcp { @Override @Override public void onMetadataChanged(MediaMetadata metadata) { public void onMetadataChanged(MediaMetadata metadata) { Log.v(TAG, "MediaController metadata changed"); Log.v(TAG, "MediaController metadata changed"); updateMetadata(metadata); updateCurrentMediaState(); } } @Override @Override public synchronized void onPlaybackStateChanged(PlaybackState state) { public synchronized void onPlaybackStateChanged(PlaybackState state) { if (DEBUG) Log.v(TAG, "onPlaybackStateChanged: state " + state.toString()); if (DEBUG) Log.v(TAG, "onPlaybackStateChanged: state " + state.toString()); updateCurrentMediaState(); updatePlaybackState(state); byte stateBytes = (byte) convertPlayStateToBytes(state.getState()); /* updating play status in global media player list */ MediaPlayerInfo player = getAddressedPlayerInfo(); if (player != null) { player.setPlayStatus(stateBytes); } else { Log.w(TAG, "onPlaybackStateChanged: no addressed player id=" + mCurrAddrPlayerID); } } } @Override @Override Loading Loading @@ -434,7 +421,7 @@ public final class Avrcp { byte[] address = (byte[]) msg.obj; byte[] address = (byte[]) msg.obj; if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_PLAY_STATUS"); if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_PLAY_STATUS"); getPlayStatusRspNative(address, convertPlayStateToPlayStatus(mCurrentPlayState), getPlayStatusRspNative(address, convertPlayStateToPlayStatus(mCurrentPlayState), (int) mSongLengthMs, (int) getPlayPosition()); (int) mMediaAttributes.getLength(), (int) getPlayPosition()); break; break; } } Loading Loading @@ -699,7 +686,8 @@ public final class Avrcp { case MSG_SET_A2DP_AUDIO_STATE: case MSG_SET_A2DP_AUDIO_STATE: if (DEBUG) Log.v(TAG, "MSG_SET_A2DP_AUDIO_STATE:" + msg.arg1); if (DEBUG) Log.v(TAG, "MSG_SET_A2DP_AUDIO_STATE:" + msg.arg1); updateA2dpAudioState(msg.arg1); mA2dpState = msg.arg1; updateCurrentMediaState(); break; break; case MSG_NATIVE_REQ_GET_FOLDER_ITEMS: { case MSG_NATIVE_REQ_GET_FOLDER_ITEMS: { Loading Loading @@ -792,30 +780,22 @@ public final class Avrcp { } } } } private void updateA2dpAudioState(int state) { boolean isPlaying = (state == BluetoothA2dp.STATE_PLAYING); if (isPlaying != isPlayingState(mCurrentPlayState)) { /* if a2dp is streaming, check to make sure music is active */ if (isPlaying && !mAudioManager.isMusicActive()) return; PlaybackState.Builder builder = new PlaybackState.Builder(); if (isPlaying) { builder.setState(PlaybackState.STATE_PLAYING, PlaybackState.PLAYBACK_POSITION_UNKNOWN, 1.0f); } else { builder.setState(PlaybackState.STATE_PAUSED, PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f); } updatePlaybackState(builder.build()); } } private void updatePlaybackState(PlaybackState state) { private void updatePlaybackState(PlaybackState state) { if (state == null) { if (state == null) { state = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE, state = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE, PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f).build(); PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f).build(); } } byte stateBytes = (byte) convertPlayStateToBytes(state.getState()); /* updating play status in global media player list */ MediaPlayerInfo player = getAddressedPlayerInfo(); if (player != null) { player.setPlayStatus(stateBytes); } else { Log.w(TAG, "onPlaybackStateChanged: no addressed player id=" + mCurrAddrPlayerID); } int oldPlayStatus = convertPlayStateToPlayStatus(mCurrentPlayState); int oldPlayStatus = convertPlayStateToPlayStatus(mCurrentPlayState); int newPlayStatus = convertPlayStateToPlayStatus(state); int newPlayStatus = convertPlayStateToPlayStatus(state); Loading @@ -826,7 +806,6 @@ public final class Avrcp { } } mCurrentPlayState = state; mCurrentPlayState = state; mLastStateUpdate = SystemClock.elapsedRealtime(); sendPlayPosNotificationRsp(false); sendPlayPosNotificationRsp(false); Loading @@ -849,7 +828,7 @@ public final class Avrcp { private String mediaNumber; private String mediaNumber; private String mediaTotalNumber; private String mediaTotalNumber; private String genre; private String genre; private String playingTimeMs; private long playingTimeMs; private static final int ATTR_TITLE = 1; private static final int ATTR_TITLE = 1; private static final int ATTR_ARTIST_NAME = 2; private static final int ATTR_ARTIST_NAME = 2; Loading @@ -870,7 +849,7 @@ public final class Avrcp { mediaNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER)); mediaNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER)); mediaTotalNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS)); mediaTotalNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS)); genre = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_GENRE)); genre = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_GENRE)); playingTimeMs = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_DURATION)); playingTimeMs = data.getLong(MediaMetadata.METADATA_KEY_DURATION); // Try harder for the title. // Try harder for the title. title = data.getString(MediaMetadata.METADATA_KEY_TITLE); title = data.getString(MediaMetadata.METADATA_KEY_TITLE); Loading @@ -888,6 +867,11 @@ public final class Avrcp { title = new String(); title = new String(); } } public long getLength() { if (!exists) return 0L; return playingTimeMs; } public boolean equals(MediaAttributes other) { public boolean equals(MediaAttributes other) { if (other == null) if (other == null) return false; return false; Loading @@ -898,13 +882,11 @@ public final class Avrcp { if (exists == false) if (exists == false) return true; return true; return (title.equals(other.title)) && return (title.equals(other.title)) && (artistName.equals(other.artistName)) (artistName.equals(other.artistName)) && && (albumName.equals(other.albumName)) (albumName.equals(other.albumName)) && && (mediaNumber.equals(other.mediaNumber)) (mediaNumber.equals(other.mediaNumber)) && && (mediaTotalNumber.equals(other.mediaTotalNumber)) (mediaTotalNumber.equals(other.mediaTotalNumber)) && && (genre.equals(other.genre)) && (playingTimeMs == other.playingTimeMs); (genre.equals(other.genre)) && (playingTimeMs.equals(other.playingTimeMs)); } } public String getString(int attrId) { public String getString(int attrId) { Loading @@ -925,7 +907,7 @@ public final class Avrcp { case ATTR_GENRE: case ATTR_GENRE: return genre; return genre; case ATTR_PLAYING_TIME_MS: case ATTR_PLAYING_TIME_MS: return playingTimeMs; return Long.toString(playingTimeMs); default: default: return new String(); return new String(); } } Loading @@ -944,40 +926,47 @@ public final class Avrcp { return "[MediaAttributes: none]"; return "[MediaAttributes: none]"; } } return "[MediaAttributes: " + title + " - " + albumName + " by " return "[MediaAttributes: " + title + " - " + albumName + " by " + artistName + " (" + artistName + " (" + mediaNumber + "/" + mediaTotalNumber + ") " + playingTimeMs + " " + mediaNumber + "/" + mediaTotalNumber + ") " + genre + genre + "]"; + "]"; } } } } private void updateMetadata(MediaMetadata data) { private void updateCurrentMediaState() { MediaAttributes oldAttributes = mMediaAttributes; if (mMediaController == null) { mMediaAttributes = new MediaAttributes(data); // Use A2DP state if we don't have a MediaControlller if (data == null) { boolean isPlaying = (mA2dpState == BluetoothA2dp.STATE_PLAYING); mSongLengthMs = 0L; if (isPlaying != isPlayingState(mCurrentPlayState)) { /* if a2dp is streaming, check to make sure music is active */ if (isPlaying && !mAudioManager.isMusicActive()) return; PlaybackState.Builder builder = new PlaybackState.Builder(); if (isPlaying) { builder.setState(PlaybackState.STATE_PLAYING, PlaybackState.PLAYBACK_POSITION_UNKNOWN, 1.0f); } else { } else { mSongLengthMs = data.getLong(MediaMetadata.METADATA_KEY_DURATION); builder.setState(PlaybackState.STATE_PAUSED, PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f); } updatePlaybackState(builder.build()); } // Can't get metadata from A2dp so we're done. return; } } if (!oldAttributes.equals(mMediaAttributes)) { MediaAttributes currentAttributes = mMediaAttributes; PlaybackState newState = mMediaController.getPlaybackState(); // Metadata mMediaAttributes = new MediaAttributes(mMediaController.getMetadata()); if (currentAttributes.equals(mMediaAttributes)) { Log.v(TAG, "MediaAttributes Changed to " + mMediaAttributes.toString()); Log.v(TAG, "MediaAttributes Changed to " + mMediaAttributes.toString()); mTracksPlayed++; mTracksPlayed++; sendTrackChangedRsp(false); if (mTrackChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM) { mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; sendTrackChangedRsp(); } } else { Log.v(TAG, "Updated " + mMediaAttributes.toString() + " but no change!"); } } // Update the play state, which sends play state and play position // notifications if needed. if (mMediaController != null) { updatePlaybackState(mMediaController.getPlaybackState()); updatePlaybackState(mMediaController.getPlaybackState()); } else { updatePlaybackState(null); } } } private void getRcFeaturesRequestFromNative(byte[] address, int features) { private void getRcFeaturesRequestFromNative(byte[] address, int features) { Loading Loading @@ -1021,7 +1010,7 @@ public final class Avrcp { case EVT_TRACK_CHANGED: case EVT_TRACK_CHANGED: Log.v(TAG, "Track changed notification enabled"); Log.v(TAG, "Track changed notification enabled"); mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM; mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM; sendTrackChangedRsp(); sendTrackChangedRsp(true); break; break; case EVT_PLAY_POS_CHANGED: case EVT_PLAY_POS_CHANGED: Loading Loading @@ -1068,22 +1057,25 @@ public final class Avrcp { mHandler.sendMessage(msg); mHandler.sendMessage(msg); } } private void sendTrackChangedRsp() { private void sendTrackChangedRsp(boolean requested) { MediaPlayerInfo info = getAddressedPlayerInfo(); MediaPlayerInfo info = getAddressedPlayerInfo(); if (info != null && !info.isBrowseSupported()) { if (info != null && !info.isBrowseSupported()) { // for players which does not support Browse or when no track is currently selected // for players which does not support Browse or when no track is currently selected trackChangeRspForBrowseUnsupported(); trackChangeRspForBrowseUnsupported(requested); } else { } else { boolean changed = mAddressedMediaPlayer.sendTrackChangeWithId(requested, mMediaController); // for players which support browsing // for players which support browsing mAddressedMediaPlayer.sendTrackChangeWithId(mTrackChangedNT, mMediaController); if (changed) mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; } } } } private void trackChangeRspForBrowseUnsupported() { private void trackChangeRspForBrowseUnsupported(boolean requested) { byte[] track = AvrcpConstants.TRACK_IS_SELECTED; byte[] track = AvrcpConstants.TRACK_IS_SELECTED; if (mTrackChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM if (requested && !mMediaAttributes.exists) { && !mMediaAttributes.exists) { track = AvrcpConstants.NO_TRACK_SELECTED; track = AvrcpConstants.NO_TRACK_SELECTED; } else if (!requested) { mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; } } registerNotificationRspTrackChangeNative(mTrackChangedNT, track); registerNotificationRspTrackChangeNative(mTrackChangedNT, track); } } Loading @@ -1098,7 +1090,9 @@ public final class Avrcp { } } if (isPlayingState(mCurrentPlayState)) { if (isPlayingState(mCurrentPlayState)) { return SystemClock.elapsedRealtime() - mLastStateUpdate + mCurrentPlayState.getPosition(); long sinceUpdate = (SystemClock.elapsedRealtime() - mCurrentPlayState.getLastPositionUpdateTime()); return sinceUpdate + mCurrentPlayState.getPosition(); } } return mCurrentPlayState.getPosition(); return mCurrentPlayState.getPosition(); Loading Loading @@ -2105,13 +2099,12 @@ public final class Avrcp { if (newController != null) { if (newController != null) { mMediaController = newController; mMediaController = newController; mMediaController.registerCallback(mMediaControllerCb, mHandler); mMediaController.registerCallback(mMediaControllerCb, mHandler); updateMetadata(mMediaController.getMetadata()); mAddressedMediaPlayer.updateNowPlayingList(mMediaController.getQueue()); mAddressedMediaPlayer.updateNowPlayingList(mMediaController.getQueue()); } else { } else { updateMetadata(null); mAddressedMediaPlayer.updateNowPlayingList(null); mAddressedMediaPlayer.updateNowPlayingList(null); registerRsp = false; registerRsp = false; } } updateCurrentMediaState(); } } return registerRsp; return registerRsp; } } Loading Loading @@ -2264,10 +2257,8 @@ public final class Avrcp { ProfileService.println(sb, "mTransportControlFlags: " + mTransportControlFlags); ProfileService.println(sb, "mTransportControlFlags: " + mTransportControlFlags); ProfileService.println(sb, "mTracksPlayed: " + mTracksPlayed); ProfileService.println(sb, "mTracksPlayed: " + mTracksPlayed); ProfileService.println(sb, "mCurrentPlayState: " + mCurrentPlayState); ProfileService.println(sb, "mCurrentPlayState: " + mCurrentPlayState); ProfileService.println(sb, "mLastStateUpdate: " + mLastStateUpdate); ProfileService.println(sb, "mPlayStatusChangedNT: " + mPlayStatusChangedNT); ProfileService.println(sb, "mPlayStatusChangedNT: " + mPlayStatusChangedNT); ProfileService.println(sb, "mTrackChangedNT: " + mTrackChangedNT); ProfileService.println(sb, "mTrackChangedNT: " + mTrackChangedNT); ProfileService.println(sb, "mSongLengthMs: " + mSongLengthMs); ProfileService.println(sb, "mPlaybackIntervalMs: " + mPlaybackIntervalMs); ProfileService.println(sb, "mPlaybackIntervalMs: " + mPlaybackIntervalMs); ProfileService.println(sb, "mPlayPosChangedNT: " + mPlayPosChangedNT); ProfileService.println(sb, "mPlayPosChangedNT: " + mPlayPosChangedNT); ProfileService.println(sb, "mNextPosMs: " + mNextPosMs); ProfileService.println(sb, "mNextPosMs: " + mNextPosMs); Loading