Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d83e296 authored by Marie Janssen's avatar Marie Janssen Committed by Gerrit Code Review
Browse files

Merge "Refactor playback position tracking"

parents 89902a18 f7942360
Loading
Loading
Loading
Loading
+69 −81
Original line number Diff line number Diff line
@@ -62,14 +62,13 @@ public final class Avrcp {
    private MediaAttributes mMediaAttributes;
    private int mTransportControlFlags;
    private PlaybackState mCurrentPlayState;
    private long mLastStateUpdate;
    private int mPlayStatusChangedNT;
    private int mTrackChangedNT;
    private int mPlayPosChangedNT;
    private long mTrackNumber;
    private long mCurrentPosMs;
    private long mPlayStartTimeMs;
    private long mSongLengthMs;
    private long mPlaybackIntervalMs;
    private int mPlayPosChangedNT;
    private long mNextPosMs;
    private long mPrevPosMs;
    private long mSkipStartTime;
@@ -144,8 +143,7 @@ public final class Avrcp {
        mPlayStatusChangedNT = NOTIFICATION_TYPE_CHANGED;
        mTrackChangedNT = NOTIFICATION_TYPE_CHANGED;
        mTrackNumber = -1L;
        mCurrentPosMs = PlaybackState.PLAYBACK_POSITION_UNKNOWN;
        mPlayStartTimeMs = -1L;
        mLastStateUpdate = -1L;
        mSongLengthMs = 0L;
        mPlaybackIntervalMs = 0L;
        mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
@@ -220,7 +218,7 @@ public final class Avrcp {
        @Override
        public void onPlaybackStateChanged(PlaybackState state) {
            Log.v(TAG, "MediaController playback changed: " + state.toString());
            updatePlayPauseState(state);
            updatePlaybackState(state);
        }

        @Override
@@ -261,12 +259,12 @@ public final class Avrcp {
        mMediaController = controller;
        if (mMediaController == null) {
            updateMetadata(null);
            updatePlayPauseState(null);
            updatePlaybackState(null);
            return;
        }
        mMediaController.registerCallback(mMediaControllerCb, mHandler);
        updateMetadata(mMediaController.getMetadata());
        updatePlayPauseState(mMediaController.getPlaybackState());
        updatePlaybackState(mMediaController.getPlaybackState());
    }

    /** Handles Avrcp messages. */
@@ -325,8 +323,7 @@ public final class Avrcp {

            case MESSAGE_PLAY_INTERVAL_TIMEOUT:
                if (DEBUG) Log.v(TAG, "MESSAGE_PLAY_INTERVAL_TIMEOUT");
                mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
                registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)getPlayPosition());
                sendPlayPosNotificationRsp(false);
                break;

            case MESSAGE_VOLUME_CHANGED:
@@ -624,56 +621,25 @@ public final class Avrcp {
                builder.setState(PlaybackState.STATE_PAUSED,
                                 PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f);
            }
            updatePlayPauseState(builder.build());
            updatePlaybackState(builder.build());
        }
    }

    private void updatePlayPauseState(PlaybackState state) {
    private void updatePlaybackState(PlaybackState state) {
        if (DEBUG) Log.v(TAG,
                "updatePlayPauseState: old=" + mCurrentPlayState + ", state=" + state);
                "updatePlaybackState: old=" + mCurrentPlayState + ", new=" + state);
        if (state == null) {
          state = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE,
                         PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f).build();
        }
        boolean oldPosValid = (mCurrentPosMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN);

        int oldPlayStatus = convertPlayStateToPlayStatus(mCurrentPlayState);
        int newPlayStatus = convertPlayStateToPlayStatus(state);

        if ((mCurrentPlayState.getState() == PlaybackState.STATE_PLAYING) &&
                (mCurrentPlayState != state) && oldPosValid) {
            mCurrentPosMs = getPlayPosition();
        }

        if (state.getState() == PlaybackState.STATE_NONE ||
                state.getState() == PlaybackState.STATE_ERROR) {
            mCurrentPosMs = PlaybackState.PLAYBACK_POSITION_UNKNOWN;
        } else {
            mCurrentPosMs = state.getPosition();
        }

        if ((state.getState() == PlaybackState.STATE_PLAYING) &&
                (mCurrentPlayState.getState() != PlaybackState.STATE_PLAYING)) {
            mPlayStartTimeMs = SystemClock.elapsedRealtime();
        }

        mCurrentPlayState = state;
        mLastStateUpdate = SystemClock.elapsedRealtime();

        boolean newPosValid = mCurrentPosMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN;
        long playPosition = getPlayPosition();

        mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT);
        /* need send play position changed notification when play status is changed */
        if ((mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) &&
                ((oldPlayStatus != newPlayStatus) || (oldPosValid != newPosValid) ||
                 (newPosValid && ((playPosition >= mNextPosMs) || (playPosition <= mPrevPosMs))))) {
            mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
            registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)playPosition);
        }
        if ((mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) && newPosValid &&
                (state.getState() == PlaybackState.STATE_PLAYING)) {
            Message msg = mHandler.obtainMessage(MESSAGE_PLAY_INTERVAL_TIMEOUT);
            mHandler.sendMessageDelayed(msg, mNextPosMs - playPosition);
        }
        sendPlayPosNotificationRsp(false);

        if ((mPlayStatusChangedNT == NOTIFICATION_TYPE_INTERIM) && (oldPlayStatus != newPlayStatus)) {
            mPlayStatusChangedNT = NOTIFICATION_TYPE_CHANGED;
@@ -804,22 +770,14 @@ public final class Avrcp {
        if (!oldAttributes.equals(mMediaAttributes)) {
            Log.v(TAG, "MediaAttributes Changed to " + mMediaAttributes.toString());
            mTrackNumber++;

            // Update the play state, which sends a notification if needed.
            updatePlaybackState(mMediaController.getPlaybackState());

            if (mTrackChangedNT == NOTIFICATION_TYPE_INTERIM) {
                mTrackChangedNT = NOTIFICATION_TYPE_CHANGED;
                sendTrackChangedRsp();
            }

            if (mCurrentPosMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN &&
                isPlayingState(mCurrentPlayState)) {
                mPlayStartTimeMs = SystemClock.elapsedRealtime();
            }
            /* need send play position changed notification when track is changed */
            if (mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) {
                mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
                registerNotificationRspPlayPosNative(mPlayPosChangedNT,
                        (int)getPlayPosition());
                mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT);
            }
        } else {
            Log.v(TAG, "Updated " + mMediaAttributes.toString() + " but no change!");
        }
@@ -867,18 +825,9 @@ public final class Avrcp {
                break;

            case EVT_PLAY_POS_CHANGED:
                long songPosition = getPlayPosition();
                mPlayPosChangedNT = NOTIFICATION_TYPE_INTERIM;
                sendPlayPosNotificationRsp(true);
                mPlaybackIntervalMs = (long)param * 1000L;
                if (mCurrentPosMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
                    mNextPosMs = songPosition + mPlaybackIntervalMs;
                    mPrevPosMs = songPosition - mPlaybackIntervalMs;
                    if (isPlayingState(mCurrentPlayState)) {
                        Message msg = mHandler.obtainMessage(MESSAGE_PLAY_INTERVAL_TIMEOUT);
                        mHandler.sendMessageDelayed(msg, mPlaybackIntervalMs);
                    }
                }
                registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)songPosition);
                break;

        }
@@ -938,17 +887,17 @@ public final class Avrcp {
    }

    private long getPlayPosition() {
        long songPosition = -1L;
        if (mCurrentPosMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
            if (mCurrentPlayState.getState() == PlaybackState.STATE_PLAYING) {
                songPosition = SystemClock.elapsedRealtime() -
                        mPlayStartTimeMs + mCurrentPosMs;
            } else {
                songPosition = mCurrentPosMs;
            }
        if (mCurrentPlayState == null)
            return -1L;

        if (mCurrentPlayState.getPosition() == PlaybackState.PLAYBACK_POSITION_UNKNOWN)
            return -1L;

        if (isPlayingState(mCurrentPlayState)) {
            return SystemClock.elapsedRealtime() - mLastStateUpdate + mCurrentPlayState.getPosition();
        }
        if (DEBUG) Log.v(TAG, "position=" + songPosition);
        return songPosition;

        return -1L;
    }

    private int convertPlayStateToPlayStatus(PlaybackState state) {
@@ -992,6 +941,44 @@ public final class Avrcp {
               (state.getState() == PlaybackState.STATE_BUFFERING);
    }

    /**
     * Sends a play position notification, or schedules one to be
     * sent later at an appropriate time. If |requested| is true,
     * does both because this was called in reponse to a request from the
     * TG.
     */
    private void sendPlayPosNotificationRsp(boolean requested) {
        long playPositionMs = getPlayPosition();

        // mNextPosMs is set to -1 when the previous position was invalid
        // so this will be true if the new position is valid & old was invalid.
        // mPlayPositionMs is set to -1 when the new position is invalid,
        // and the old mPrevPosMs is >= 0 so this is true when the new is invalid
        // and the old was valid.
        if (requested || ((mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) &&
             ((playPositionMs >= mNextPosMs) || (playPositionMs <= mPrevPosMs)))) {
            if (!requested) mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
            registerNotificationRspPlayPosNative(mPlayStatusChangedNT, (int)playPositionMs);
            if (playPositionMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
                mNextPosMs = playPositionMs + mPlaybackIntervalMs;
                mPrevPosMs = playPositionMs - mPlaybackIntervalMs;
            } else {
                mNextPosMs = -1;
                mPrevPosMs = -1;
            }
        }

        mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT);
        if (mPlayStatusChangedNT == NOTIFICATION_TYPE_INTERIM) {
            Message msg = mHandler.obtainMessage(MESSAGE_PLAY_INTERVAL_TIMEOUT);
            long delay = mPlaybackIntervalMs;
            if (mNextPosMs != -1) {
                delay = mNextPosMs - (playPositionMs > 0 ? playPositionMs : 0);
            }
            mHandler.sendMessageDelayed(msg, delay);
        }
    }

    /**
     * This is called from AudioService. It will return whether this device supports abs volume.
     * NOT USED AT THE MOMENT.
@@ -1090,11 +1077,10 @@ public final class Avrcp {
        ProfileService.println(sb, "mMediaAttributes: " + mMediaAttributes);
        ProfileService.println(sb, "mTransportControlFlags: " + mTransportControlFlags);
        ProfileService.println(sb, "mCurrentPlayState: " + mCurrentPlayState);
        ProfileService.println(sb, "mLastStateUpdate: " + mLastStateUpdate);
        ProfileService.println(sb, "mPlayStatusChangedNT: " + mPlayStatusChangedNT);
        ProfileService.println(sb, "mTrackChangedNT: " + mTrackChangedNT);
        ProfileService.println(sb, "mTrackNumber: " + mTrackNumber);
        ProfileService.println(sb, "mCurrentPosMs: " + mCurrentPosMs);
        ProfileService.println(sb, "mPlayStartTimeMs: " + mPlayStartTimeMs);
        ProfileService.println(sb, "mSongLengthMs: " + mSongLengthMs);
        ProfileService.println(sb, "mPlaybackIntervalMs: " + mPlaybackIntervalMs);
        ProfileService.println(sb, "mPlayPosChangedNT: " + mPlayPosChangedNT);
@@ -1112,6 +1098,8 @@ public final class Avrcp {
        ProfileService.println(sb, "mAbsVolRetryTimes: " + mAbsVolRetryTimes);
        ProfileService.println(sb, "mSkipAmount: " + mSkipAmount);
        ProfileService.println(sb, "mVolumeMapping: " + mVolumeMapping.toString());
        if (mMediaController != null)
            ProfileService.println(sb, "mMediaSession pkg: " + mMediaController.getPackageName());
    }

    // Do not modify without updating the HAL bt_rc.h files.