diff options
Diffstat (limited to 'services')
-rw-r--r-- | services/audioflinger/AudioBufferProviderSource.cpp | 14 | ||||
-rw-r--r-- | services/audioflinger/AudioBufferProviderSource.h | 5 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 10 | ||||
-rw-r--r-- | services/audioflinger/AudioStreamOutSink.cpp | 12 | ||||
-rw-r--r-- | services/audioflinger/AudioStreamOutSink.h | 5 | ||||
-rw-r--r-- | services/audioflinger/FastMixer.cpp | 7 | ||||
-rw-r--r-- | services/audioflinger/MonoPipe.cpp | 134 | ||||
-rw-r--r-- | services/audioflinger/MonoPipe.h | 41 | ||||
-rw-r--r-- | services/audioflinger/MonoPipeReader.cpp | 18 | ||||
-rw-r--r-- | services/audioflinger/MonoPipeReader.h | 2 | ||||
-rw-r--r-- | services/audioflinger/NBAIO.cpp | 7 | ||||
-rw-r--r-- | services/audioflinger/NBAIO.h | 28 | ||||
-rw-r--r-- | services/audioflinger/SourceAudioBufferProvider.cpp | 2 |
13 files changed, 261 insertions, 24 deletions
diff --git a/services/audioflinger/AudioBufferProviderSource.cpp b/services/audioflinger/AudioBufferProviderSource.cpp index 4342171..613e924 100644 --- a/services/audioflinger/AudioBufferProviderSource.cpp +++ b/services/audioflinger/AudioBufferProviderSource.cpp @@ -46,14 +46,16 @@ ssize_t AudioBufferProviderSource::availableToRead() return mBuffer.raw != NULL ? mBuffer.frameCount - mConsumed : 0; } -ssize_t AudioBufferProviderSource::read(void *buffer, size_t count) +ssize_t AudioBufferProviderSource::read(void *buffer, + size_t count, + int64_t readPTS) { if (CC_UNLIKELY(!mNegotiated)) { return NEGOTIATE; } if (CC_UNLIKELY(mBuffer.raw == NULL)) { mBuffer.frameCount = count; - status_t status = mProvider->getNextBuffer(&mBuffer, AudioBufferProvider::kInvalidPTS); + status_t status = mProvider->getNextBuffer(&mBuffer, readPTS); if (status != OK) { return status == NOT_ENOUGH_DATA ? (ssize_t) WOULD_BLOCK : (ssize_t) status; } @@ -79,7 +81,8 @@ ssize_t AudioBufferProviderSource::read(void *buffer, size_t count) return count; } -ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *user, size_t block) +ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *user, + int64_t readPTS, size_t block) { if (CC_UNLIKELY(!mNegotiated)) { return NEGOTIATE; @@ -99,7 +102,7 @@ ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *us // 1 <= count <= block if (CC_UNLIKELY(mBuffer.raw == NULL)) { mBuffer.frameCount = count; - status_t status = mProvider->getNextBuffer(&mBuffer, AudioBufferProvider::kInvalidPTS); + status_t status = mProvider->getNextBuffer(&mBuffer, readPTS); if (CC_LIKELY(status == OK)) { ALOG_ASSERT(mBuffer.raw != NULL && mBuffer.frameCount <= count); // mConsumed is 0 either from constructor or after releaseBuffer() @@ -117,7 +120,8 @@ ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *us count = available; } if (CC_LIKELY(count > 0)) { - ssize_t ret = via(user, (char *) mBuffer.raw + (mConsumed << mBitShift), count); + char* readTgt = (char *) mBuffer.raw + (mConsumed << mBitShift); + ssize_t ret = via(user, readTgt, count, readPTS); if (CC_UNLIKELY(ret <= 0)) { if (CC_LIKELY(accumulator > 0)) { return accumulator; diff --git a/services/audioflinger/AudioBufferProviderSource.h b/services/audioflinger/AudioBufferProviderSource.h index 2b39937..1435a84 100644 --- a/services/audioflinger/AudioBufferProviderSource.h +++ b/services/audioflinger/AudioBufferProviderSource.h @@ -42,8 +42,9 @@ public: //virtual size_t framesOverrun(); //virtual size_t overruns(); virtual ssize_t availableToRead(); - virtual ssize_t read(void *buffer, size_t count); - virtual ssize_t readVia(readVia_t via, size_t total, void *user, size_t block); + virtual ssize_t read(void *buffer, size_t count, int64_t readPTS); + virtual ssize_t readVia(readVia_t via, size_t total, void *user, + int64_t readPTS, size_t block); private: AudioBufferProvider * const mProvider; diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 125ec3a..7e5f102 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -2791,9 +2791,10 @@ void AudioFlinger::MixerThread::threadLoop_mix() int64_t pts; status_t status = INVALID_OPERATION; - if (NULL != mOutput->stream->get_next_write_timestamp) { - status = mOutput->stream->get_next_write_timestamp( - mOutput->stream, &pts); + if (mNormalSink != 0) { + status = mNormalSink->getNextWriteTimestamp(&pts); + } else { + status = mOutputSink->getNextWriteTimestamp(&pts); } if (status != NO_ERROR) { @@ -3579,7 +3580,8 @@ void AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& ar #define TEE_SINK_READ 1024 short buffer[TEE_SINK_READ * FCC_2]; size_t count = TEE_SINK_READ; - ssize_t actual = teeSource->read(buffer, count); + ssize_t actual = teeSource->read(buffer, count, + AudioBufferProvider::kInvalidPTS); bool wasFirstRead = firstRead; firstRead = false; if (actual <= 0) { diff --git a/services/audioflinger/AudioStreamOutSink.cpp b/services/audioflinger/AudioStreamOutSink.cpp index 8a5aa0c..bc2d15b 100644 --- a/services/audioflinger/AudioStreamOutSink.cpp +++ b/services/audioflinger/AudioStreamOutSink.cpp @@ -67,4 +67,16 @@ ssize_t AudioStreamOutSink::write(const void *buffer, size_t count) return ret; } +status_t AudioStreamOutSink::getNextWriteTimestamp(int64_t *timestamp) { + ALOG_ASSERT(timestamp != NULL); + + if (NULL == mStream) + return INVALID_OPERATION; + + if (NULL == mStream->get_next_write_timestamp) + return INVALID_OPERATION; + + return mStream->get_next_write_timestamp(mStream, timestamp); +} + } // namespace android diff --git a/services/audioflinger/AudioStreamOutSink.h b/services/audioflinger/AudioStreamOutSink.h index 1eff3f6..5976b18 100644 --- a/services/audioflinger/AudioStreamOutSink.h +++ b/services/audioflinger/AudioStreamOutSink.h @@ -47,6 +47,11 @@ public: virtual ssize_t write(const void *buffer, size_t count); + // AudioStreamOutSink wraps a HAL's output stream. Its + // getNextWriteTimestamp method is simply a passthru to the HAL's underlying + // implementation of GNWT (if any) + virtual status_t getNextWriteTimestamp(int64_t *timestamp); + // NBAIO_Sink end #if 0 // until necessary diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp index 7652132..b89bf81 100644 --- a/services/audioflinger/FastMixer.cpp +++ b/services/audioflinger/FastMixer.cpp @@ -399,8 +399,13 @@ bool FastMixer::threadLoop() ftDump->mUnderruns = underruns; ftDump->mFramesReady = framesReady; } + + int64_t pts; + if (outputSink == NULL || (OK != outputSink->getNextWriteTimestamp(&pts))) + pts = AudioBufferProvider::kInvalidPTS; + // process() is CPU-bound - mixer->process(AudioBufferProvider::kInvalidPTS); + mixer->process(pts); mixBufferState = MIXED; } else if (mixBufferState == MIXED) { mixBufferState = UNDEFINED; diff --git a/services/audioflinger/MonoPipe.cpp b/services/audioflinger/MonoPipe.cpp index f3fc19a..bd876b4 100644 --- a/services/audioflinger/MonoPipe.cpp +++ b/services/audioflinger/MonoPipe.cpp @@ -17,17 +17,22 @@ #define LOG_TAG "MonoPipe" //#define LOG_NDEBUG 0 +#include <common_time/cc_helper.h> #include <cutils/atomic.h> #include <cutils/compiler.h> +#include <utils/LinearTransform.h> #include <utils/Log.h> #include <utils/Trace.h> +#include "AudioBufferProvider.h" #include "MonoPipe.h" #include "roundup.h" + namespace android { MonoPipe::MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock) : NBAIO_Sink(format), + mUpdateSeq(0), mReqFrames(reqFrames), mMaxFrames(roundup(reqFrames)), mBuffer(malloc(mMaxFrames * Format_frameSize(format))), @@ -38,6 +43,37 @@ MonoPipe::MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock) : mSetpoint((reqFrames * 11) / 16), mWriteCanBlock(writeCanBlock) { + CCHelper tmpHelper; + status_t res; + uint64_t N, D; + + mNextRdPTS = AudioBufferProvider::kInvalidPTS; + + mSamplesToLocalTime.a_zero = 0; + mSamplesToLocalTime.b_zero = 0; + mSamplesToLocalTime.a_to_b_numer = 0; + mSamplesToLocalTime.a_to_b_denom = 0; + + D = Format_sampleRate(format); + if (OK != (res = tmpHelper.getLocalFreq(&N))) { + ALOGE("Failed to fetch local time frequency when constructing a" + " MonoPipe (res = %d). getNextWriteTimestamp calls will be" + " non-functional", res); + return; + } + + LinearTransform::reduce(&N, &D); + static const uint64_t kSignedHiBitsMask = ~(0x7FFFFFFFull); + static const uint64_t kUnsignedHiBitsMask = ~(0xFFFFFFFFull); + if ((N & kSignedHiBitsMask) || (D & kUnsignedHiBitsMask)) { + ALOGE("Cannot reduce sample rate to local clock frequency ratio to fit" + " in a 32/32 bit rational. (max reduction is 0x%016llx/0x%016llx" + "). getNextWriteTimestamp calls will be non-functional", N, D); + return; + } + + mSamplesToLocalTime.a_to_b_numer = static_cast<int32_t>(N); + mSamplesToLocalTime.a_to_b_denom = static_cast<uint32_t>(D); } MonoPipe::~MonoPipe() @@ -162,4 +198,102 @@ void MonoPipe::setAvgFrames(size_t setpoint) mSetpoint = setpoint; } +status_t MonoPipe::getNextWriteTimestamp(int64_t *timestamp) +{ + int32_t front; + + ALOG_ASSERT(NULL != timestamp); + + if (0 == mSamplesToLocalTime.a_to_b_denom) + return UNKNOWN_ERROR; + + observeFrontAndNRPTS(&front, timestamp); + + if (AudioBufferProvider::kInvalidPTS != *timestamp) { + // If we have a valid read-pointer and next read timestamp pair, then + // use the current value of the write pointer to figure out how many + // frames are in the buffer, and offset the timestamp by that amt. Then + // next time we write to the MonoPipe, the data will hit the speakers at + // the next read timestamp plus the current amount of data in the + // MonoPipe. + size_t pendingFrames = (mRear - front) & (mMaxFrames - 1); + *timestamp = offsetTimestampByAudioFrames(*timestamp, pendingFrames); + } + + return OK; +} + +void MonoPipe::updateFrontAndNRPTS(int32_t newFront, int64_t newNextRdPTS) +{ + // Set the MSB of the update sequence number to indicate that there is a + // multi-variable update in progress. Use an atomic store with an "acquire" + // barrier to make sure that the next operations cannot be re-ordered and + // take place before the change to mUpdateSeq is commited.. + int32_t tmp = mUpdateSeq | 0x80000000; + android_atomic_acquire_store(tmp, &mUpdateSeq); + + // Update mFront and mNextRdPTS + mFront = newFront; + mNextRdPTS = newNextRdPTS; + + // We are finished with the update. Compute the next sequnce number (which + // should be the old sequence number, plus one, and with the MSB cleared) + // and then store it in mUpdateSeq using an atomic store with a "release" + // barrier so our update operations cannot be re-ordered past the update of + // the sequence number. + tmp = (tmp + 1) & 0x7FFFFFFF; + android_atomic_release_store(tmp, &mUpdateSeq); +} + +void MonoPipe::observeFrontAndNRPTS(int32_t *outFront, int64_t *outNextRdPTS) +{ + // Perform an atomic observation of mFront and mNextRdPTS. Basically, + // atomically observe the sequence number, then observer the variables, then + // atomically observe the sequence number again. If the two observations of + // the sequence number match, and the update-in-progress bit was not set, + // then we know we have a successful atomic observation. Otherwise, we loop + // around and try again. + // + // Note, it is very important that the observer be a lower priority thread + // than the updater. If the updater is lower than the observer, or they are + // the same priority and running with SCHED_FIFO (implying that quantum + // based premption is disabled) then we run the risk of deadlock. + int32_t seqOne, seqTwo; + + do { + seqOne = android_atomic_acquire_load(&mUpdateSeq); + *outFront = mFront; + *outNextRdPTS = mNextRdPTS; + seqTwo = android_atomic_release_load(&mUpdateSeq); + } while ((seqOne != seqTwo) || (seqOne & 0x80000000)); +} + +int64_t MonoPipe::offsetTimestampByAudioFrames(int64_t ts, size_t audFrames) +{ + if (0 == mSamplesToLocalTime.a_to_b_denom) + return AudioBufferProvider::kInvalidPTS; + + if (ts == AudioBufferProvider::kInvalidPTS) + return AudioBufferProvider::kInvalidPTS; + + int64_t frame_lt_duration; + if (!mSamplesToLocalTime.doForwardTransform(audFrames, + &frame_lt_duration)) { + // This should never fail, but if there is a bug which is causing it + // to fail, this message would probably end up flooding the logs + // because the conversion would probably fail forever. Log the + // error, but then zero out the ratio in the linear transform so + // that we don't try to do any conversions from now on. This + // MonoPipe's getNextWriteTimestamp is now broken for good. + ALOGE("Overflow when attempting to convert %d audio frames to" + " duration in local time. getNextWriteTimestamp will fail from" + " now on.", audFrames); + mSamplesToLocalTime.a_to_b_numer = 0; + mSamplesToLocalTime.a_to_b_denom = 0; + return AudioBufferProvider::kInvalidPTS; + } + + return ts + frame_lt_duration; +} + } // namespace android diff --git a/services/audioflinger/MonoPipe.h b/services/audioflinger/MonoPipe.h index f6e2cb3..c47bf6c 100644 --- a/services/audioflinger/MonoPipe.h +++ b/services/audioflinger/MonoPipe.h @@ -18,6 +18,7 @@ #define ANDROID_AUDIO_MONO_PIPE_H #include <time.h> +#include <utils/LinearTransform.h> #include "NBAIO.h" namespace android { @@ -56,6 +57,20 @@ public: virtual ssize_t write(const void *buffer, size_t count); //virtual ssize_t writeVia(writeVia_t via, size_t total, void *user, size_t block); + // MonoPipe's implementation of getNextWriteTimestamp works in conjunction + // with MonoPipeReader. Every time a MonoPipeReader reads from the pipe, it + // receives a "readPTS" indicating the point in time for which the reader + // would like to read data. This "last read PTS" is offset by the amt of + // data the reader is currently mixing and then cached cached along with the + // updated read pointer. This cached value is the local time for which the + // reader is going to request data next time it reads data (assuming we are + // in steady state and operating with no underflows). Writers to the + // MonoPipe who would like to know when their next write operation will hit + // the speakers can call getNextWriteTimestamp which will return the value + // of the last read PTS plus the duration of the amt of data waiting to be + // read in the MonoPipe. + virtual status_t getNextWriteTimestamp(int64_t *timestamp); + // average number of frames present in the pipe under normal conditions. // See throttling mechanism in MonoPipe::write() size_t getAvgFrames() const { return mSetpoint; } @@ -63,20 +78,42 @@ public: size_t maxFrames() const { return mMaxFrames; } private: + // A pair of methods and a helper variable which allows the reader and the + // writer to update and observe the values of mFront and mNextRdPTS in an + // atomic lock-less fashion. + // + // :: Important :: + // Two assumptions must be true in order for this lock-less approach to + // function properly on all systems. First, there may only be one updater + // thread in the system. Second, the updater thread must be running at a + // strictly higher priority than the observer threads. Currently, both of + // these assumptions are true. The only updater is always a single + // FastMixer thread (which runs with SCHED_FIFO/RT priority while the only + // observer is always an AudioFlinger::PlaybackThread running with + // traditional (non-RT) audio priority. + void updateFrontAndNRPTS(int32_t newFront, int64_t newNextRdPTS); + void observeFrontAndNRPTS(int32_t *outFront, int64_t *outNextRdPTS); + volatile int32_t mUpdateSeq; + const size_t mReqFrames; // as requested in constructor, unrounded const size_t mMaxFrames; // always a power of 2 void * const mBuffer; // mFront and mRear will never be separated by more than mMaxFrames. // 32-bit overflow is possible if the pipe is active for a long time, but if that happens it's // safe because we "&" with (mMaxFrames-1) at end of computations to calculate a buffer index. - volatile int32_t mFront; // written by reader with android_atomic_release_store, - // read by writer with android_atomic_acquire_load + volatile int32_t mFront; // written by the reader with updateFrontAndNRPTS, observed by + // the writer with observeFrontAndNRPTS volatile int32_t mRear; // written by writer with android_atomic_release_store, // read by reader with android_atomic_acquire_load + volatile int64_t mNextRdPTS; // written by the reader with updateFrontAndNRPTS, observed by + // the writer with observeFrontAndNRPTS bool mWriteTsValid; // whether mWriteTs is valid struct timespec mWriteTs; // time that the previous write() completed size_t mSetpoint; // target value for pipe fill depth const bool mWriteCanBlock; // whether write() should block if the pipe is full + + int64_t offsetTimestampByAudioFrames(int64_t ts, size_t audFrames); + LinearTransform mSamplesToLocalTime; }; } // namespace android diff --git a/services/audioflinger/MonoPipeReader.cpp b/services/audioflinger/MonoPipeReader.cpp index b80d0c0..39a07de 100644 --- a/services/audioflinger/MonoPipeReader.cpp +++ b/services/audioflinger/MonoPipeReader.cpp @@ -43,11 +43,25 @@ ssize_t MonoPipeReader::availableToRead() return ret; } -ssize_t MonoPipeReader::read(void *buffer, size_t count) +ssize_t MonoPipeReader::read(void *buffer, size_t count, int64_t readPTS) { + // Compute the "next read PTS" and cache it. Callers of read pass a read + // PTS indicating the local time for which they are requesting data along + // with a count (which is the number of audio frames they are going to + // ultimately pass to the next stage of the pipeline). Offsetting readPTS + // by the duration of count will give us the readPTS which will be passed to + // us next time, assuming they system continues to operate in steady state + // with no discontinuities. We stash this value so it can be used by the + // MonoPipe writer to imlement getNextWriteTimestamp. + int64_t nextReadPTS; + nextReadPTS = mPipe->offsetTimestampByAudioFrames(readPTS, count); + // count == 0 is unlikely and not worth checking for explicitly; will be handled automatically ssize_t red = availableToRead(); if (CC_UNLIKELY(red <= 0)) { + // Uh-oh, looks like we are underflowing. Update the next read PTS and + // get out. + mPipe->updateFrontAndNRPTS(mPipe->mFront, nextReadPTS); return red; } if (CC_LIKELY((size_t) red > count)) { @@ -66,7 +80,7 @@ ssize_t MonoPipeReader::read(void *buffer, size_t count) memcpy((char *) buffer + (part1 << mBitShift), mPipe->mBuffer, part2 << mBitShift); } } - android_atomic_release_store(red + mPipe->mFront, &mPipe->mFront); + mPipe->updateFrontAndNRPTS(red + mPipe->mFront, nextReadPTS); mFramesRead += red; } return red; diff --git a/services/audioflinger/MonoPipeReader.h b/services/audioflinger/MonoPipeReader.h index 9bb0a94..0e1c992 100644 --- a/services/audioflinger/MonoPipeReader.h +++ b/services/audioflinger/MonoPipeReader.h @@ -47,7 +47,7 @@ public: virtual ssize_t availableToRead(); - virtual ssize_t read(void *buffer, size_t count); + virtual ssize_t read(void *buffer, size_t count, int64_t readPTS); // NBAIO_Source end diff --git a/services/audioflinger/NBAIO.cpp b/services/audioflinger/NBAIO.cpp index 9d71eae..2c07ebf 100644 --- a/services/audioflinger/NBAIO.cpp +++ b/services/audioflinger/NBAIO.cpp @@ -128,7 +128,8 @@ ssize_t NBAIO_Sink::writeVia(writeVia_t via, size_t total, void *user, size_t bl } // This is a default implementation; it is expected that subclasses will optimize this. -ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user, size_t block) +ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user, + int64_t readPTS, size_t block) { if (!mNegotiated) { return (ssize_t) NEGOTIATE; @@ -147,11 +148,11 @@ ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user, size_t bl if (count > block) { count = block; } - ssize_t ret = read(buffer, count); + ssize_t ret = read(buffer, count, readPTS); if (ret > 0) { ALOG_ASSERT((size_t) ret <= count); size_t maxRet = ret; - ret = via(user, buffer, maxRet); + ret = via(user, buffer, maxRet, readPTS); if (ret > 0) { ALOG_ASSERT((size_t) ret <= maxRet); accumulator += ret; diff --git a/services/audioflinger/NBAIO.h b/services/audioflinger/NBAIO.h index b5ae0f1..81f42ed 100644 --- a/services/audioflinger/NBAIO.h +++ b/services/audioflinger/NBAIO.h @@ -26,6 +26,7 @@ #include <limits.h> #include <stdlib.h> +#include <utils/Errors.h> #include <utils/RefBase.h> namespace android { @@ -74,7 +75,8 @@ unsigned Format_channelCount(NBAIO_Format format); // Callbacks used by NBAIO_Sink::writeVia() and NBAIO_Source::readVia() below. typedef ssize_t (*writeVia_t)(void *user, void *buffer, size_t count); -typedef ssize_t (*readVia_t)(void *user, const void *buffer, size_t count); +typedef ssize_t (*readVia_t)(void *user, const void *buffer, + size_t count, int64_t readPTS); // Abstract class (interface) representing a data port. class NBAIO_Port : public RefBase { @@ -198,6 +200,21 @@ public: // < 0 status_t error occurred prior to the first frame transfer during this callback. virtual ssize_t writeVia(writeVia_t via, size_t total, void *user, size_t block = 0); + // Get the time (on the LocalTime timeline) at which the first frame of audio of the next write + // operation to this sink will be eventually rendered by the HAL. + // Inputs: + // ts A pointer pointing to the int64_t which will hold the result. + // Return value: + // OK Everything went well, *ts holds the time at which the first audio frame of the next + // write operation will be rendered, or AudioBufferProvider::kInvalidPTS if this sink + // does not know the answer for some reason. Sinks which eventually lead to a HAL + // which implements get_next_write_timestamp may return Invalid temporarily if the DMA + // output of the audio driver has not started yet. Sinks which lead to a HAL which + // does not implement get_next_write_timestamp, or which don't lead to a HAL at all, + // will always return kInvalidPTS. + // <other> Something unexpected happened internally. Check the logs and start debugging. + virtual status_t getNextWriteTimestamp(int64_t *ts) { return INVALID_OPERATION; } + protected: NBAIO_Sink(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesWritten(0) { } virtual ~NBAIO_Sink() { } @@ -238,6 +255,8 @@ public: // Inputs: // buffer Non-NULL destination buffer owned by consumer. // count Maximum number of frames to transfer. + // readPTS The presentation time (on the LocalTime timeline) for which data + // is being requested, or kInvalidPTS if not known. // Return value: // > 0 Number of frames successfully transferred prior to first error. // = 0 Count was zero. @@ -247,7 +266,7 @@ public: // WOULD_BLOCK No frames can be transferred without blocking. // OVERRUN read() has not been called frequently enough, or with enough frames to keep up. // One or more frames were lost due to overrun, try again to read more recent data. - virtual ssize_t read(void *buffer, size_t count) = 0; + virtual ssize_t read(void *buffer, size_t count, int64_t readPTS) = 0; // Transfer data from source using a series of callbacks. More suitable for zero-fill, // synthesis, and non-contiguous transfers (e.g. circular buffer or readv). @@ -256,6 +275,8 @@ public: // total Estimate of the number of frames the consumer desires. This is an estimate, // and it can consume a different number of frames during the series of callbacks. // user Arbitrary void * reserved for data consumer. + // readPTS The presentation time (on the LocalTime timeline) for which data + // is being requested, or kInvalidPTS if not known. // block Number of frames per block, that is a suggested value for 'count' in each callback. // Zero means no preference. This parameter is a hint only, and may be ignored. // Return value: @@ -278,7 +299,8 @@ public: // > 0 Number of frames successfully transferred during this callback prior to first error. // = 0 Count was zero. // < 0 status_t error occurred prior to the first frame transfer during this callback. - virtual ssize_t readVia(readVia_t via, size_t total, void *user, size_t block = 0); + virtual ssize_t readVia(readVia_t via, size_t total, void *user, + int64_t readPTS, size_t block = 0); protected: NBAIO_Source(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesRead(0) { } diff --git a/services/audioflinger/SourceAudioBufferProvider.cpp b/services/audioflinger/SourceAudioBufferProvider.cpp index e9d6d2c..3343b53 100644 --- a/services/audioflinger/SourceAudioBufferProvider.cpp +++ b/services/audioflinger/SourceAudioBufferProvider.cpp @@ -65,7 +65,7 @@ status_t SourceAudioBufferProvider::getNextBuffer(Buffer *buffer, int64_t pts) mSize = buffer->frameCount; } // read from source - ssize_t actual = mSource->read(mAllocated, buffer->frameCount); + ssize_t actual = mSource->read(mAllocated, buffer->frameCount, pts); if (actual > 0) { ALOG_ASSERT((size_t) actual <= buffer->frameCount); mOffset = 0; |