OboeAudioService: add thread to service for passing timestamps
Cleanup several TODOs.
Test: test_aaudio in CTS
Change-Id: I7fc956b6a21cbb592f98e1e5a8f43ebd6926d796
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/services/oboeservice/Android.mk b/services/oboeservice/Android.mk
index 07b4d76..5a79b80 100644
--- a/services/oboeservice/Android.mk
+++ b/services/oboeservice/Android.mk
@@ -42,7 +42,9 @@
OboeAudioService.cpp \
OboeServiceStreamBase.cpp \
OboeServiceStreamFakeHal.cpp \
- OboeServiceMain.cpp
+ TimestampScheduler.cpp \
+ OboeServiceMain.cpp \
+ OboeThread.cpp
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CFLAGS += -Wall -Werror
diff --git a/services/oboeservice/OboeAudioService.cpp b/services/oboeservice/OboeAudioService.cpp
index caddc1d..001569c 100644
--- a/services/oboeservice/OboeAudioService.cpp
+++ b/services/oboeservice/OboeAudioService.cpp
@@ -34,11 +34,20 @@
typedef enum
{
+ OBOE_HANDLE_TYPE_DUMMY1, // TODO remove DUMMYs
+ OBOE_HANDLE_TYPE_DUMMY2, // make server handles different than client
OBOE_HANDLE_TYPE_STREAM,
OBOE_HANDLE_TYPE_COUNT
} oboe_service_handle_type_t;
static_assert(OBOE_HANDLE_TYPE_COUNT <= HANDLE_TRACKER_MAX_TYPES, "Too many handle types.");
+android::OboeAudioService::OboeAudioService()
+ : BnOboeAudioService() {
+}
+
+OboeAudioService::~OboeAudioService() {
+}
+
oboe_handle_t OboeAudioService::openStream(oboe::OboeStreamRequest &request,
oboe::OboeStreamConfiguration &configuration) {
OboeServiceStreamBase *serviceStream = new OboeServiceStreamFakeHal();
@@ -61,7 +70,7 @@
OboeServiceStreamBase *serviceStream = (OboeServiceStreamBase *)
mHandleTracker.remove(OBOE_HANDLE_TYPE_STREAM,
streamHandle);
- ALOGI("OboeAudioService.closeStream(0x%08X)", streamHandle);
+ ALOGD("OboeAudioService.closeStream(0x%08X)", streamHandle);
if (serviceStream != nullptr) {
ALOGD("OboeAudioService::closeStream(): deleting serviceStream = %p", serviceStream);
delete serviceStream;
@@ -79,9 +88,8 @@
oboe_result_t OboeAudioService::getStreamDescription(
oboe_handle_t streamHandle,
oboe::AudioEndpointParcelable &parcelable) {
- ALOGI("OboeAudioService::getStreamDescriptor(), streamHandle = 0x%08x", streamHandle);
OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
- ALOGI("OboeAudioService::getStreamDescriptor(), serviceStream = %p", serviceStream);
+ ALOGD("OboeAudioService::getStreamDescription(), serviceStream = %p", serviceStream);
if (serviceStream == nullptr) {
return OBOE_ERROR_INVALID_HANDLE;
}
@@ -90,45 +98,38 @@
oboe_result_t OboeAudioService::startStream(oboe_handle_t streamHandle) {
OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
- ALOGI("OboeAudioService::startStream(), serviceStream = %p", serviceStream);
+ ALOGD("OboeAudioService::startStream(), serviceStream = %p", serviceStream);
if (serviceStream == nullptr) {
return OBOE_ERROR_INVALID_HANDLE;
}
- mLatestHandle = streamHandle;
- return serviceStream->start();
+ oboe_result_t result = serviceStream->start();
+ return result;
}
oboe_result_t OboeAudioService::pauseStream(oboe_handle_t streamHandle) {
OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
- ALOGI("OboeAudioService::pauseStream(), serviceStream = %p", serviceStream);
+ ALOGD("OboeAudioService::pauseStream(), serviceStream = %p", serviceStream);
if (serviceStream == nullptr) {
return OBOE_ERROR_INVALID_HANDLE;
}
- return serviceStream->pause();
+ oboe_result_t result = serviceStream->pause();
+ return result;
}
oboe_result_t OboeAudioService::flushStream(oboe_handle_t streamHandle) {
OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
- ALOGI("OboeAudioService::flushStream(), serviceStream = %p", serviceStream);
+ ALOGD("OboeAudioService::flushStream(), serviceStream = %p", serviceStream);
if (serviceStream == nullptr) {
return OBOE_ERROR_INVALID_HANDLE;
}
return serviceStream->flush();
}
-void OboeAudioService::tickle() {
- OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(mLatestHandle);
- //ALOGI("OboeAudioService::tickle(), serviceStream = %p", serviceStream);
- if (serviceStream != nullptr) {
- serviceStream->tickle();
- }
-}
-
oboe_result_t OboeAudioService::registerAudioThread(oboe_handle_t streamHandle,
pid_t clientThreadId,
oboe_nanoseconds_t periodNanoseconds) {
OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
- ALOGI("OboeAudioService::registerAudioThread(), serviceStream = %p", serviceStream);
+ ALOGD("OboeAudioService::registerAudioThread(), serviceStream = %p", serviceStream);
if (serviceStream == nullptr) {
ALOGE("OboeAudioService::registerAudioThread(), serviceStream == nullptr");
return OBOE_ERROR_INVALID_HANDLE;
diff --git a/services/oboeservice/OboeAudioService.h b/services/oboeservice/OboeAudioService.h
index df3cbf8..b196f1d 100644
--- a/services/oboeservice/OboeAudioService.h
+++ b/services/oboeservice/OboeAudioService.h
@@ -24,31 +24,32 @@
#include <oboe/OboeDefinitions.h>
#include <oboe/OboeAudio.h>
-#include "HandleTracker.h"
+#include "utility/HandleTracker.h"
#include "IOboeAudioService.h"
-#include "OboeService.h"
#include "OboeServiceStreamBase.h"
-using namespace android;
-namespace oboe {
+namespace android {
class OboeAudioService :
public BinderService<OboeAudioService>,
public BnOboeAudioService
{
- friend class BinderService<OboeAudioService>; // for OboeAudioService()
+ friend class BinderService<OboeAudioService>;
+
public:
-// TODO why does this fail? static const char* getServiceName() ANDROID_API { return "media.audio_oboe"; }
+ OboeAudioService();
+ virtual ~OboeAudioService();
+
static const char* getServiceName() { return "media.audio_oboe"; }
- virtual oboe_handle_t openStream(OboeStreamRequest &request,
- OboeStreamConfiguration &configuration);
+ virtual oboe_handle_t openStream(oboe::OboeStreamRequest &request,
+ oboe::OboeStreamConfiguration &configuration);
virtual oboe_result_t closeStream(oboe_handle_t streamHandle);
virtual oboe_result_t getStreamDescription(
oboe_handle_t streamHandle,
- AudioEndpointParcelable &parcelable);
+ oboe::AudioEndpointParcelable &parcelable);
virtual oboe_result_t startStream(oboe_handle_t streamHandle);
@@ -61,16 +62,14 @@
virtual oboe_result_t unregisterAudioThread(oboe_handle_t streamHandle, pid_t pid);
- virtual void tickle();
-
private:
- OboeServiceStreamBase *convertHandleToServiceStream(oboe_handle_t streamHandle) const;
+ oboe::OboeServiceStreamBase *convertHandleToServiceStream(oboe_handle_t streamHandle) const;
HandleTracker mHandleTracker;
- oboe_handle_t mLatestHandle = OBOE_ERROR_INVALID_HANDLE; // TODO until we have service threads
+
};
-} /* namespace oboe */
+} /* namespace android */
#endif //OBOE_OBOE_AUDIO_SERVICE_H
diff --git a/services/oboeservice/OboeServiceStreamBase.cpp b/services/oboeservice/OboeServiceStreamBase.cpp
index 6b7e4e5..15b70a5 100644
--- a/services/oboeservice/OboeServiceStreamBase.cpp
+++ b/services/oboeservice/OboeServiceStreamBase.cpp
@@ -40,12 +40,15 @@
}
OboeServiceStreamBase::~OboeServiceStreamBase() {
+ Mutex::Autolock _l(mLockUpMessageQueue);
delete mUpMessageQueue;
}
void OboeServiceStreamBase::sendServiceEvent(oboe_service_event_t event,
int32_t data1,
int64_t data2) {
+
+ Mutex::Autolock _l(mLockUpMessageQueue);
OboeServiceMessage command;
command.what = OboeServiceMessage::code::EVENT;
command.event.event = event;
diff --git a/services/oboeservice/OboeServiceStreamBase.h b/services/oboeservice/OboeServiceStreamBase.h
index 736c754..33857c6 100644
--- a/services/oboeservice/OboeServiceStreamBase.h
+++ b/services/oboeservice/OboeServiceStreamBase.h
@@ -17,12 +17,14 @@
#ifndef OBOE_OBOE_SERVICE_STREAM_BASE_H
#define OBOE_OBOE_SERVICE_STREAM_BASE_H
+#include <utils/Mutex.h>
+
#include "IOboeAudioService.h"
#include "OboeService.h"
-#include "AudioStream.h"
#include "fifo/FifoBuffer.h"
#include "SharedRingBuffer.h"
#include "AudioEndpointParcelable.h"
+#include "OboeThread.h"
namespace oboe {
@@ -30,7 +32,7 @@
// This should be way more than we need.
#define QUEUE_UP_CAPACITY_COMMANDS (128)
-class OboeServiceStreamBase {
+class OboeServiceStreamBase {
public:
OboeServiceStreamBase();
@@ -68,7 +70,11 @@
virtual oboe_result_t close() = 0;
- virtual void tickle() = 0;
+ virtual void sendCurrentTimestamp() = 0;
+
+ oboe_size_frames_t getFramesPerBurst() {
+ return mFramesPerBurst;
+ }
virtual void sendServiceEvent(oboe_service_event_t event,
int32_t data1 = 0,
@@ -77,6 +83,7 @@
virtual void setRegisteredThread(pid_t pid) {
mRegisteredClientThread = pid;
}
+
virtual pid_t getRegisteredThread() {
return mRegisteredClientThread;
}
@@ -92,6 +99,8 @@
oboe_size_frames_t mFramesPerBurst = 0;
oboe_size_frames_t mCapacityInFrames = 0;
oboe_size_bytes_t mCapacityInBytes = 0;
+
+ android::Mutex mLockUpMessageQueue;
};
} /* namespace oboe */
diff --git a/services/oboeservice/OboeServiceStreamFakeHal.cpp b/services/oboeservice/OboeServiceStreamFakeHal.cpp
index dbbc860..da4099d 100644
--- a/services/oboeservice/OboeServiceStreamFakeHal.cpp
+++ b/services/oboeservice/OboeServiceStreamFakeHal.cpp
@@ -18,6 +18,8 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <atomic>
+
#include "AudioClock.h"
#include "AudioEndpointParcelable.h"
@@ -41,6 +43,7 @@
: OboeServiceStreamBase()
, mStreamId(nullptr)
, mPreviousFrameCounter(0)
+ , mOboeThread()
{
}
@@ -86,7 +89,8 @@
// Fill in OboeStreamConfiguration
configuration.setSampleRate(mSampleRate);
configuration.setSamplesPerFrame(mmapInfo.channel_count);
- configuration.setAudioFormat(OBOE_AUDIO_FORMAT_PCM16);
+ configuration.setAudioFormat(OBOE_AUDIO_FORMAT_PCM_I16);
+
return OBOE_OK;
}
@@ -117,6 +121,10 @@
oboe_result_t result = fake_hal_start(mStreamId);
sendServiceEvent(OBOE_SERVICE_EVENT_STARTED);
mState = OBOE_STREAM_STATE_STARTED;
+ if (result == OBOE_OK) {
+ mThreadEnabled.store(true);
+ result = mOboeThread.start(this);
+ }
return result;
}
@@ -131,6 +139,8 @@
mState = OBOE_STREAM_STATE_PAUSED;
mFramesRead.reset32();
ALOGD("OboeServiceStreamFakeHal::pause() sent OBOE_SERVICE_EVENT_PAUSED");
+ mThreadEnabled.store(false);
+ result = mOboeThread.stop();
return result;
}
@@ -166,7 +176,7 @@
command.what = OboeServiceMessage::code::TIMESTAMP;
mFramesRead.update32(frameCounter);
command.timestamp.position = mFramesRead.get();
- ALOGV("OboeServiceStreamFakeHal::sendCurrentTimestamp() HAL frames = %d, pos = %d",
+ ALOGD("OboeServiceStreamFakeHal::sendCurrentTimestamp() HAL frames = %d, pos = %d",
frameCounter, (int)mFramesRead.get());
command.timestamp.timestamp = AudioClock::getNanoseconds();
mUpMessageQueue->getFifoBuffer()->write(&command, 1);
@@ -174,17 +184,18 @@
}
}
-void OboeServiceStreamFakeHal::tickle() {
- if (mStreamId != nullptr) {
- switch (mState) {
- case OBOE_STREAM_STATE_STARTING:
- case OBOE_STREAM_STATE_STARTED:
- case OBOE_STREAM_STATE_PAUSING:
- case OBOE_STREAM_STATE_STOPPING:
- sendCurrentTimestamp();
- break;
- default:
- break;
+// implement Runnable
+void OboeServiceStreamFakeHal::run() {
+ TimestampScheduler timestampScheduler;
+ timestampScheduler.setBurstPeriod(mFramesPerBurst, mSampleRate);
+ timestampScheduler.start(AudioClock::getNanoseconds());
+ while(mThreadEnabled.load()) {
+ oboe_nanoseconds_t nextTime = timestampScheduler.nextAbsoluteTime();
+ if (AudioClock::getNanoseconds() >= nextTime) {
+ sendCurrentTimestamp();
+ } else {
+ // Sleep until it is time to send the next timestamp.
+ AudioClock::sleepUntilNanoTime(nextTime);
}
}
}
diff --git a/services/oboeservice/OboeServiceStreamFakeHal.h b/services/oboeservice/OboeServiceStreamFakeHal.h
index b026d34..39b952a 100644
--- a/services/oboeservice/OboeServiceStreamFakeHal.h
+++ b/services/oboeservice/OboeServiceStreamFakeHal.h
@@ -22,10 +22,13 @@
#include "FakeAudioHal.h"
#include "MonotonicCounter.h"
#include "AudioEndpointParcelable.h"
+#include "TimestampScheduler.h"
namespace oboe {
-class OboeServiceStreamFakeHal : public OboeServiceStreamBase {
+class OboeServiceStreamFakeHal
+ : public OboeServiceStreamBase
+ , public Runnable {
public:
OboeServiceStreamFakeHal();
@@ -53,12 +56,10 @@
virtual oboe_result_t close() override;
- virtual void tickle() override;
-
-protected:
-
void sendCurrentTimestamp();
+ virtual void run() override; // to implement Runnable
+
private:
fake_hal_stream_ptr mStreamId; // Move to HAL
@@ -68,6 +69,9 @@
int mPreviousFrameCounter = 0; // from HAL
oboe_stream_state_t mState = OBOE_STREAM_STATE_UNINITIALIZED;
+
+ OboeThread mOboeThread;
+ std::atomic<bool> mThreadEnabled;
};
} // namespace oboe
diff --git a/services/oboeservice/OboeThread.cpp b/services/oboeservice/OboeThread.cpp
new file mode 100644
index 0000000..9ecfa90
--- /dev/null
+++ b/services/oboeservice/OboeThread.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OboeService"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <pthread.h>
+
+#include <oboe/OboeDefinitions.h>
+
+#include "OboeThread.h"
+
+using namespace oboe;
+
+
+OboeThread::OboeThread() {
+ // mThread is a pthread_t of unknown size so we need memset.
+ memset(&mThread, 0, sizeof(mThread));
+}
+
+void OboeThread::dispatch() {
+ if (mRunnable != nullptr) {
+ mRunnable->run();
+ } else {
+ run();
+ }
+}
+
+// This is the entry point for the new thread created by createThread().
+// It converts the 'C' function call to a C++ method call.
+static void * OboeThread_internalThreadProc(void *arg) {
+ OboeThread *oboeThread = (OboeThread *) arg;
+ oboeThread->dispatch();
+ return nullptr;
+}
+
+oboe_result_t OboeThread::start(Runnable *runnable) {
+ if (mHasThread) {
+ return OBOE_ERROR_INVALID_STATE;
+ }
+ mRunnable = runnable; // TODO use atomic?
+ int err = pthread_create(&mThread, nullptr, OboeThread_internalThreadProc, this);
+ if (err != 0) {
+ ALOGE("OboeThread::pthread_create() returned %d", err);
+ // TODO convert errno to oboe_result_t
+ return OBOE_ERROR_INTERNAL;
+ } else {
+ mHasThread = true;
+ return OBOE_OK;
+ }
+}
+
+oboe_result_t OboeThread::stop() {
+ if (!mHasThread) {
+ return OBOE_ERROR_INVALID_STATE;
+ }
+ int err = pthread_join(mThread, nullptr);
+ mHasThread = false;
+ // TODO convert errno to oboe_result_t
+ return err ? OBOE_ERROR_INTERNAL : OBOE_OK;
+}
+
diff --git a/services/oboeservice/OboeThread.h b/services/oboeservice/OboeThread.h
new file mode 100644
index 0000000..48fafc7
--- /dev/null
+++ b/services/oboeservice/OboeThread.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OBOE_THREAD_H
+#define OBOE_THREAD_H
+
+#include <atomic>
+#include <pthread.h>
+
+#include <oboe/OboeDefinitions.h>
+
+namespace oboe {
+
+class Runnable {
+public:
+ Runnable() {};
+ virtual ~Runnable() = default;
+
+ virtual void run() {}
+};
+
+/**
+ * Abstraction for a host thread.
+ */
+class OboeThread
+{
+public:
+ OboeThread();
+ OboeThread(Runnable *runnable);
+ virtual ~OboeThread() = default;
+
+ /**
+ * Start the thread running.
+ */
+ oboe_result_t start(Runnable *runnable = nullptr);
+
+ /**
+ * Join the thread.
+ * The caller must somehow tell the thread to exit before calling join().
+ */
+ oboe_result_t stop();
+
+ /**
+ * This will get called in the thread.
+ * Override this or pass a Runnable to start().
+ */
+ virtual void run() {};
+
+ void dispatch(); // called internally from 'C' thread wrapper
+
+private:
+ Runnable* mRunnable = nullptr; // TODO make atomic with memory barrier?
+ bool mHasThread = false;
+ pthread_t mThread; // initialized in constructor
+
+};
+
+} /* namespace oboe */
+
+#endif ///OBOE_THREAD_H
diff --git a/services/oboeservice/TimestampScheduler.cpp b/services/oboeservice/TimestampScheduler.cpp
new file mode 100644
index 0000000..17d6c63
--- /dev/null
+++ b/services/oboeservice/TimestampScheduler.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// for random()
+#include <stdlib.h>
+
+#include "TimestampScheduler.h"
+
+using namespace oboe;
+
+void TimestampScheduler::start(oboe_nanoseconds_t startTime) {
+ mStartTime = startTime;
+ mLastTime = startTime;
+}
+
+oboe_nanoseconds_t TimestampScheduler::nextAbsoluteTime() {
+ int64_t periodsElapsed = (mLastTime - mStartTime) / mBurstPeriod;
+ // This is an arbitrary schedule that could probably be improved.
+ // It starts out sending a timestamp on every period because we want to
+ // get an accurate picture when the stream starts. Then it slows down
+ // to the occasional timestamps needed to detect a slow drift.
+ int64_t minPeriodsToDelay = (periodsElapsed < 10) ? 1 :
+ (periodsElapsed < 100) ? 3 :
+ (periodsElapsed < 1000) ? 10 : 50;
+ oboe_nanoseconds_t sleepTime = minPeriodsToDelay * mBurstPeriod;
+ // Generate a random rectangular distribution one burst wide so that we get
+ // an uncorrelated sampling of the MMAP pointer.
+ sleepTime += (oboe_nanoseconds_t)(random() * mBurstPeriod / RAND_MAX);
+ mLastTime += sleepTime;
+ return mLastTime;
+}
diff --git a/services/oboeservice/TimestampScheduler.h b/services/oboeservice/TimestampScheduler.h
new file mode 100644
index 0000000..041e432
--- /dev/null
+++ b/services/oboeservice/TimestampScheduler.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OBOE_TIMESTAMP_SCHEDULER_H
+#define OBOE_TIMESTAMP_SCHEDULER_H
+
+//#include <stdlib.h> // random()
+
+#include "IOboeAudioService.h"
+#include "OboeService.h"
+#include "AudioStream.h"
+#include "fifo/FifoBuffer.h"
+#include "SharedRingBuffer.h"
+#include "AudioEndpointParcelable.h"
+
+namespace oboe {
+
+/**
+ * Schedule wakeup time for monitoring the position
+ * of an MMAP/NOIRQ buffer.
+ *
+ * Note that this object is not thread safe. Only call it from a single thread.
+ */
+class TimestampScheduler
+{
+public:
+ TimestampScheduler() {};
+ virtual ~TimestampScheduler() = default;
+
+ /**
+ * Start the schedule at the given time.
+ */
+ void start(oboe_nanoseconds_t startTime);
+
+ /**
+ * Calculate the next time that the read position should be
+ * measured.
+ */
+ oboe_nanoseconds_t nextAbsoluteTime();
+
+ void setBurstPeriod(oboe_nanoseconds_t burstPeriod) {
+ mBurstPeriod = burstPeriod;
+ }
+
+ void setBurstPeriod(oboe_size_frames_t framesPerBurst,
+ oboe_sample_rate_t sampleRate) {
+ mBurstPeriod = OBOE_NANOS_PER_SECOND * framesPerBurst / sampleRate;
+ }
+
+ oboe_nanoseconds_t getBurstPeriod() {
+ return mBurstPeriod;
+ }
+
+private:
+ // Start with an arbitrary default so we do not divide by zero.
+ oboe_nanoseconds_t mBurstPeriod = OBOE_NANOS_PER_MILLISECOND;
+ oboe_nanoseconds_t mStartTime;
+ oboe_nanoseconds_t mLastTime;
+};
+
+} /* namespace oboe */
+
+#endif /* OBOE_TIMESTAMP_SCHEDULER_H */