Loading include/media/AudioTimestamp.h +10 −4 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ public: struct ExtendedTimestamp { enum Location { LOCATION_INVALID = -1, LOCATION_CLIENT, // timestamp of last read frame from client-server track buffer LOCATION_SERVER, // timestamp of newest frame from client-server track buffer LOCATION_KERNEL, // timestamp of newest frame in the kernel (alsa) buffer. Loading Loading @@ -89,8 +90,10 @@ struct ExtendedTimestamp { } // Returns the best timestamp as judged from the closest-to-hw stage in the // pipeline with a valid timestamp. status_t getBestTimestamp(int64_t *position, int64_t *time, int timebase) const { // pipeline with a valid timestamp. If the optional location parameter is non-null, // it will be filled with the location where the time was obtained. status_t getBestTimestamp( int64_t *position, int64_t *time, int timebase, Location *location = nullptr) const { if (position == nullptr || time == nullptr || timebase < 0 || timebase >= TIMEBASE_MAX) { return BAD_VALUE; Loading @@ -102,18 +105,21 @@ struct ExtendedTimestamp { if (mTimeNs[i] > 0) { *position = mPosition[i]; *time = mTimeNs[i] + mTimebaseOffset[timebase]; if (location != nullptr) { *location = (Location)i; } return OK; } } return INVALID_OPERATION; } status_t getBestTimestamp(AudioTimestamp *timestamp) const { status_t getBestTimestamp(AudioTimestamp *timestamp, Location *location = nullptr) const { if (timestamp == nullptr) { return BAD_VALUE; } int64_t position, time; if (getBestTimestamp(&position, &time, TIMEBASE_MONOTONIC) == OK) { if (getBestTimestamp(&position, &time, TIMEBASE_MONOTONIC, location) == OK) { timestamp->mPosition = position; timestamp->mTime.tv_sec = time / 1000000000; timestamp->mTime.tv_nsec = time - timestamp->mTime.tv_sec * 1000000000LL; Loading include/media/AudioTrack.h +2 −0 Original line number Diff line number Diff line Loading @@ -1046,6 +1046,8 @@ protected: bool mTimestampStartupGlitchReported; // reduce log spam bool mRetrogradeMotionReported; // reduce log spam AudioTimestamp mPreviousTimestamp; // used to detect retrograde motion ExtendedTimestamp::Location mPreviousLocation; // location used for previous timestamp double mComputedLatencyMs; // latency between server and kernel uint32_t mUnderrunCountOffset; // updated when restoring tracks Loading media/libmedia/AudioTrack.cpp +38 −1 Original line number Diff line number Diff line Loading @@ -535,6 +535,8 @@ status_t AudioTrack::set( mPreviousTimestampValid = false; mTimestampStartupGlitchReported = false; mRetrogradeMotionReported = false; mPreviousLocation = ExtendedTimestamp::LOCATION_INVALID; mComputedLatencyMs = 0.; mUnderrunCountOffset = 0; mFramesWritten = 0; mFramesWrittenServerOffset = 0; Loading Loading @@ -567,6 +569,8 @@ status_t AudioTrack::start() mPreviousTimestampValid = false; mTimestampStartupGlitchReported = false; mRetrogradeMotionReported = false; mPreviousLocation = ExtendedTimestamp::LOCATION_INVALID; mComputedLatencyMs = 0.; // read last server side position change via timestamp. ExtendedTimestamp ets; Loading Loading @@ -2362,7 +2366,40 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) ExtendedTimestamp ets; status = mProxy->getTimestamp(&ets); if (status == OK) { status = ets.getBestTimestamp(×tamp); ExtendedTimestamp::Location location; status = ets.getBestTimestamp(×tamp, &location); if (status == OK) { // It is possible that the best location has moved from the kernel to the server. // In this case we adjust the position from the previous computed latency. if (location == ExtendedTimestamp::LOCATION_SERVER) { ALOGW_IF(mPreviousLocation == ExtendedTimestamp::LOCATION_KERNEL, "getTimestamp() location moved from kernel to server"); const double latencyMs = mComputedLatencyMs > 0. ? mComputedLatencyMs : mAfLatency; const int64_t frames = int64_t(latencyMs * mSampleRate * mPlaybackRate.mSpeed / 1000); ALOGV("mComputedLatencyMs:%lf mAfLatency:%u frame adjustment:%lld", mComputedLatencyMs, mAfLatency, (long long)frames); if (frames >= ets.mPosition[location]) { timestamp.mPosition = 0; } else { timestamp.mPosition = (uint32_t)(ets.mPosition[location] - frames); } } else if (location == ExtendedTimestamp::LOCATION_KERNEL) { const double bufferDiffMs = (double)(ets.mPosition[ExtendedTimestamp::LOCATION_SERVER] - ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL]) * 1000 / ((double)mSampleRate * mPlaybackRate.mSpeed); mComputedLatencyMs = bufferDiffMs > 0. ? bufferDiffMs : 0.; ALOGV("mComputedLatencyMs:%lf mAfLatency:%d", mComputedLatencyMs, mAfLatency); } mPreviousLocation = location; } else { // right after AudioTrack is started, one may not find a timestamp ALOGV("getBestTimestamp did not find timestamp"); } } if (status == INVALID_OPERATION) { status = WOULD_BLOCK; Loading Loading
include/media/AudioTimestamp.h +10 −4 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ public: struct ExtendedTimestamp { enum Location { LOCATION_INVALID = -1, LOCATION_CLIENT, // timestamp of last read frame from client-server track buffer LOCATION_SERVER, // timestamp of newest frame from client-server track buffer LOCATION_KERNEL, // timestamp of newest frame in the kernel (alsa) buffer. Loading Loading @@ -89,8 +90,10 @@ struct ExtendedTimestamp { } // Returns the best timestamp as judged from the closest-to-hw stage in the // pipeline with a valid timestamp. status_t getBestTimestamp(int64_t *position, int64_t *time, int timebase) const { // pipeline with a valid timestamp. If the optional location parameter is non-null, // it will be filled with the location where the time was obtained. status_t getBestTimestamp( int64_t *position, int64_t *time, int timebase, Location *location = nullptr) const { if (position == nullptr || time == nullptr || timebase < 0 || timebase >= TIMEBASE_MAX) { return BAD_VALUE; Loading @@ -102,18 +105,21 @@ struct ExtendedTimestamp { if (mTimeNs[i] > 0) { *position = mPosition[i]; *time = mTimeNs[i] + mTimebaseOffset[timebase]; if (location != nullptr) { *location = (Location)i; } return OK; } } return INVALID_OPERATION; } status_t getBestTimestamp(AudioTimestamp *timestamp) const { status_t getBestTimestamp(AudioTimestamp *timestamp, Location *location = nullptr) const { if (timestamp == nullptr) { return BAD_VALUE; } int64_t position, time; if (getBestTimestamp(&position, &time, TIMEBASE_MONOTONIC) == OK) { if (getBestTimestamp(&position, &time, TIMEBASE_MONOTONIC, location) == OK) { timestamp->mPosition = position; timestamp->mTime.tv_sec = time / 1000000000; timestamp->mTime.tv_nsec = time - timestamp->mTime.tv_sec * 1000000000LL; Loading
include/media/AudioTrack.h +2 −0 Original line number Diff line number Diff line Loading @@ -1046,6 +1046,8 @@ protected: bool mTimestampStartupGlitchReported; // reduce log spam bool mRetrogradeMotionReported; // reduce log spam AudioTimestamp mPreviousTimestamp; // used to detect retrograde motion ExtendedTimestamp::Location mPreviousLocation; // location used for previous timestamp double mComputedLatencyMs; // latency between server and kernel uint32_t mUnderrunCountOffset; // updated when restoring tracks Loading
media/libmedia/AudioTrack.cpp +38 −1 Original line number Diff line number Diff line Loading @@ -535,6 +535,8 @@ status_t AudioTrack::set( mPreviousTimestampValid = false; mTimestampStartupGlitchReported = false; mRetrogradeMotionReported = false; mPreviousLocation = ExtendedTimestamp::LOCATION_INVALID; mComputedLatencyMs = 0.; mUnderrunCountOffset = 0; mFramesWritten = 0; mFramesWrittenServerOffset = 0; Loading Loading @@ -567,6 +569,8 @@ status_t AudioTrack::start() mPreviousTimestampValid = false; mTimestampStartupGlitchReported = false; mRetrogradeMotionReported = false; mPreviousLocation = ExtendedTimestamp::LOCATION_INVALID; mComputedLatencyMs = 0.; // read last server side position change via timestamp. ExtendedTimestamp ets; Loading Loading @@ -2362,7 +2366,40 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) ExtendedTimestamp ets; status = mProxy->getTimestamp(&ets); if (status == OK) { status = ets.getBestTimestamp(×tamp); ExtendedTimestamp::Location location; status = ets.getBestTimestamp(×tamp, &location); if (status == OK) { // It is possible that the best location has moved from the kernel to the server. // In this case we adjust the position from the previous computed latency. if (location == ExtendedTimestamp::LOCATION_SERVER) { ALOGW_IF(mPreviousLocation == ExtendedTimestamp::LOCATION_KERNEL, "getTimestamp() location moved from kernel to server"); const double latencyMs = mComputedLatencyMs > 0. ? mComputedLatencyMs : mAfLatency; const int64_t frames = int64_t(latencyMs * mSampleRate * mPlaybackRate.mSpeed / 1000); ALOGV("mComputedLatencyMs:%lf mAfLatency:%u frame adjustment:%lld", mComputedLatencyMs, mAfLatency, (long long)frames); if (frames >= ets.mPosition[location]) { timestamp.mPosition = 0; } else { timestamp.mPosition = (uint32_t)(ets.mPosition[location] - frames); } } else if (location == ExtendedTimestamp::LOCATION_KERNEL) { const double bufferDiffMs = (double)(ets.mPosition[ExtendedTimestamp::LOCATION_SERVER] - ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL]) * 1000 / ((double)mSampleRate * mPlaybackRate.mSpeed); mComputedLatencyMs = bufferDiffMs > 0. ? bufferDiffMs : 0.; ALOGV("mComputedLatencyMs:%lf mAfLatency:%d", mComputedLatencyMs, mAfLatency); } mPreviousLocation = location; } else { // right after AudioTrack is started, one may not find a timestamp ALOGV("getBestTimestamp did not find timestamp"); } } if (status == INVALID_OPERATION) { status = WOULD_BLOCK; Loading