Skip to content

Commit

Permalink
oboe: add calculateLatencyMillis()
Browse files Browse the repository at this point in the history
Based on getTimestamp().

Fixes #69
  • Loading branch information
Phil Burk committed Apr 29, 2018
1 parent 9f7ec16 commit c07dc62
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 4 deletions.
27 changes: 24 additions & 3 deletions include/oboe/AudioStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,30 @@ class AudioStream : public AudioStreamBase {

virtual int64_t getFramesRead() const { return mFramesRead; }

/**
* Calculate the latency of a stream based on getTimestamp().
*
* Latency is the time it takes for a given frame to travel from the
* app to the edge of the device or vice versa.
*
* Note that the latency of an OUTPUT stream will increase when you write data to it
* and then decrease over time.
*
* The latency of an INPUT stream will decrease when you read data from it
* and then increase over time.
*
* The latency of an OUTPUT stream is generally higher than the INPUT latency
* because an tries to keep the OUTPUT buffer full and the INPUT buffer empty.
*
* @return The latency in millisecondssec and Result::OK, or a negative error.
*/
virtual ErrorOrValue<double> calculateLatencyMillis() {
return ErrorOrValue<double>(Result::ErrorUnimplemented);
}

virtual Result getTimestamp(clockid_t clockId,
int64_t *framePosition,
int64_t *timeNanoseconds) {
int64_t *framePosition,
int64_t *timeNanoseconds) {
return Result::ErrorUnimplemented;
}

Expand All @@ -173,7 +194,7 @@ class AudioStream : public AudioStreamBase {
* @param buffer The address of the first sample.
* @param numFrames Number of frames to write. Only complete frames will be written.
* @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
* @return The number of frames actually written or a negative error.
* @return The number of frames actually written and Result::OK, or a negative error.
*/
virtual ErrorOrValue<int32_t> write(const void *buffer,
int32_t numFrames,
Expand Down
42 changes: 42 additions & 0 deletions src/aaudio/AudioStreamAAudio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,4 +390,46 @@ Result AudioStreamAAudio::getTimestamp(clockid_t clockId,
}
}

ErrorOrValue<double> AudioStreamAAudio::calculateLatencyMillis() {
AAudioStream *stream = mAAudioStream.load();
if (stream != nullptr) {
bool isOutput = (getDirection() == oboe::Direction::Output);

// Get the time that a known audio frame was presented.
int64_t hardwareFrameIndex;
int64_t hardwareFrameHardwareTime;
auto result = getTimestamp(CLOCK_MONOTONIC,
&hardwareFrameIndex,
&hardwareFrameHardwareTime);
if (result != oboe::Result::OK) {
return ErrorOrValue<double>(static_cast<Result>(result));
}

// Get counter closest to the app.
int64_t appFrameIndex = isOutput ? getFramesWritten() : getFramesRead();

// Assume that the next frame will be processed at the current time
using namespace std::chrono;
int64_t appFrameAppTime =
duration_cast<nanoseconds>(steady_clock::now().time_since_epoch()).count();

// Calculate the number of frames between app and hardware
int64_t frameIndexDelta = appFrameIndex - hardwareFrameIndex;

// Calculate the time which the next frame will be or was presented
int64_t frameTimeDelta = (frameIndexDelta * oboe::kNanosPerSecond) / getSampleRate();
int64_t appFrameHardwareTime = hardwareFrameHardwareTime + frameTimeDelta;

// The current latency is the difference in time between when the current frame is at
// the app and when it is at the hardware.
int64_t latencyNanos = (isOutput)
? (appFrameHardwareTime - appFrameAppTime) // hardware is later
: (appFrameAppTime - appFrameHardwareTime); // hardware is earlier
double latencyMillis = (double) latencyNanos / kNanosPerMillisecond;
return ErrorOrValue<double>(latencyMillis);
} else {
return ErrorOrValue<double>(Result::ErrorNull);
}
}

} // namespace oboe
3 changes: 2 additions & 1 deletion src/aaudio/AudioStreamAAudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ class AudioStreamAAudio : public AudioStream {
int64_t getFramesRead() const override;
int64_t getFramesWritten() const override;

ErrorOrValue<double> calculateLatencyMillis() override;

Result waitForStateChange(StreamState currentState,
StreamState *nextState,
int64_t timeoutNanoseconds) override;
Expand All @@ -86,7 +88,6 @@ class AudioStreamAAudio : public AudioStream {

StreamState getState() override;


AudioApi getAudioApi() const override {
return AudioApi::AAudio;
}
Expand Down

0 comments on commit c07dc62

Please sign in to comment.