blob: 39c9f9c4f2f3a4f9caac33485c29109c69d34375 [file] [log] [blame]
/*
* Copyright 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 AAUDIO_AUDIOSTREAM_H
#define AAUDIO_AUDIOSTREAM_H
#include <atomic>
#include <mutex>
#include <stdint.h>
#include <aaudio/AAudio.h>
#include "utility/AAudioUtilities.h"
#include "utility/MonotonicCounter.h"
namespace aaudio {
typedef void *(*aaudio_audio_thread_proc_t)(void *);
class AudioStreamBuilder;
/**
* AAudio audio stream.
*/
class AudioStream {
public:
AudioStream();
virtual ~AudioStream();
// =========== Begin ABSTRACT methods ===========================
/* Asynchronous requests.
* Use waitForStateChange() to wait for completion.
*/
virtual aaudio_result_t requestStart() = 0;
virtual aaudio_result_t requestPause() = 0;
virtual aaudio_result_t requestFlush() = 0;
virtual aaudio_result_t requestStop() = 0;
virtual aaudio_result_t getTimestamp(clockid_t clockId,
int64_t *framePosition,
int64_t *timeNanoseconds) = 0;
/**
* Update state while in the middle of waitForStateChange()
* @return
*/
virtual aaudio_result_t updateStateWhileWaiting() = 0;
// =========== End ABSTRACT methods ===========================
virtual aaudio_result_t waitForStateChange(aaudio_stream_state_t currentState,
aaudio_stream_state_t *nextState,
int64_t timeoutNanoseconds);
/**
* Open the stream using the parameters in the builder.
* Allocate the necessary resources.
*/
virtual aaudio_result_t open(const AudioStreamBuilder& builder);
/**
* Close the stream and deallocate any resources from the open() call.
* It is safe to call close() multiple times.
*/
virtual aaudio_result_t close() {
return AAUDIO_OK;
}
virtual aaudio_result_t setBufferSize(int32_t requestedFrames) {
return AAUDIO_ERROR_UNIMPLEMENTED;
}
virtual aaudio_result_t createThread(int64_t periodNanoseconds,
aaudio_audio_thread_proc_t threadProc,
void *threadArg);
aaudio_result_t joinThread(void **returnArg, int64_t timeoutNanoseconds);
virtual aaudio_result_t registerThread() {
return AAUDIO_OK;
}
virtual aaudio_result_t unregisterThread() {
return AAUDIO_OK;
}
/**
* Internal function used to call the audio thread passed by the user.
* It is unfortunately public because it needs to be called by a static 'C' function.
*/
void* wrapUserThread();
// ============== Queries ===========================
aaudio_stream_state_t getState() const {
return mState;
}
virtual int32_t getBufferSize() const {
return AAUDIO_ERROR_UNIMPLEMENTED;
}
virtual int32_t getBufferCapacity() const {
return AAUDIO_ERROR_UNIMPLEMENTED;
}
virtual int32_t getFramesPerBurst() const {
return AAUDIO_ERROR_UNIMPLEMENTED;
}
virtual int32_t getXRunCount() const {
return AAUDIO_ERROR_UNIMPLEMENTED;
}
bool isActive() const {
return mState == AAUDIO_STREAM_STATE_STARTING || mState == AAUDIO_STREAM_STATE_STARTED;
}
virtual bool isMMap() {
return false;
}
aaudio_result_t getSampleRate() const {
return mSampleRate;
}
aaudio_format_t getFormat() const {
return mFormat;
}
aaudio_result_t getSamplesPerFrame() const {
return mSamplesPerFrame;
}
virtual int32_t getPerformanceMode() const {
return mPerformanceMode;
}
void setPerformanceMode(aaudio_performance_mode_t performanceMode) {
mPerformanceMode = performanceMode;
}
int32_t getDeviceId() const {
return mDeviceId;
}
aaudio_sharing_mode_t getSharingMode() const {
return mSharingMode;
}
bool isSharingModeMatchRequired() const {
return mSharingModeMatchRequired;
}
virtual aaudio_direction_t getDirection() const = 0;
/**
* This is only valid after setSamplesPerFrame() and setFormat() have been called.
*/
int32_t getBytesPerFrame() const {
return mSamplesPerFrame * getBytesPerSample();
}
/**
* This is only valid after setFormat() has been called.
*/
int32_t getBytesPerSample() const {
return AAudioConvert_formatToSizeInBytes(mFormat);
}
virtual int64_t getFramesWritten() {
return mFramesWritten.get();
}
virtual int64_t getFramesRead() {
return mFramesRead.get();
}
AAudioStream_dataCallback getDataCallbackProc() const {
return mDataCallbackProc;
}
AAudioStream_errorCallback getErrorCallbackProc() const {
return mErrorCallbackProc;
}
void *getDataCallbackUserData() const {
return mDataCallbackUserData;
}
void *getErrorCallbackUserData() const {
return mErrorCallbackUserData;
}
int32_t getFramesPerDataCallback() const {
return mFramesPerDataCallback;
}
bool isDataCallbackActive() {
return (mDataCallbackProc != nullptr) && isActive();
}
// ============== I/O ===========================
// A Stream will only implement read() or write() depending on its direction.
virtual aaudio_result_t write(const void *buffer,
int32_t numFrames,
int64_t timeoutNanoseconds) {
return AAUDIO_ERROR_UNIMPLEMENTED;
}
virtual aaudio_result_t read(void *buffer,
int32_t numFrames,
int64_t timeoutNanoseconds) {
return AAUDIO_ERROR_UNIMPLEMENTED;
}
protected:
virtual int64_t incrementFramesWritten(int32_t frames) {
return mFramesWritten.increment(frames);
}
virtual int64_t incrementFramesRead(int32_t frames) {
return mFramesRead.increment(frames);
}
/**
* This should not be called after the open() call.
*/
void setSampleRate(int32_t sampleRate) {
mSampleRate = sampleRate;
}
/**
* This should not be called after the open() call.
*/
void setSamplesPerFrame(int32_t samplesPerFrame) {
mSamplesPerFrame = samplesPerFrame;
}
/**
* This should not be called after the open() call.
*/
void setSharingMode(aaudio_sharing_mode_t sharingMode) {
mSharingMode = sharingMode;
}
/**
* This should not be called after the open() call.
*/
void setFormat(aaudio_format_t format) {
mFormat = format;
}
void setState(aaudio_stream_state_t state) {
mState = state;
}
void setDeviceId(int32_t deviceId) {
mDeviceId = deviceId;
}
std::mutex mStreamMutex;
std::atomic<bool> mCallbackEnabled;
protected:
MonotonicCounter mFramesWritten;
MonotonicCounter mFramesRead;
void setPeriodNanoseconds(int64_t periodNanoseconds) {
mPeriodNanoseconds.store(periodNanoseconds, std::memory_order_release);
}
int64_t getPeriodNanoseconds() {
return mPeriodNanoseconds.load(std::memory_order_acquire);
}
private:
// These do not change after open().
int32_t mSamplesPerFrame = AAUDIO_UNSPECIFIED;
int32_t mSampleRate = AAUDIO_UNSPECIFIED;
int32_t mDeviceId = AAUDIO_UNSPECIFIED;
aaudio_sharing_mode_t mSharingMode = AAUDIO_SHARING_MODE_SHARED;
bool mSharingModeMatchRequired = false; // must match sharing mode requested
aaudio_format_t mFormat = AAUDIO_FORMAT_UNSPECIFIED;
aaudio_stream_state_t mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
aaudio_performance_mode_t mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
// callback ----------------------------------
AAudioStream_dataCallback mDataCallbackProc = nullptr; // external callback functions
void *mDataCallbackUserData = nullptr;
int32_t mFramesPerDataCallback = AAUDIO_UNSPECIFIED; // frames
AAudioStream_errorCallback mErrorCallbackProc = nullptr;
void *mErrorCallbackUserData = nullptr;
// background thread ----------------------------------
bool mHasThread = false;
pthread_t mThread; // initialized in constructor
// These are set by the application thread and then read by the audio pthread.
std::atomic<int64_t> mPeriodNanoseconds; // for tuning SCHED_FIFO threads
// TODO make atomic?
aaudio_audio_thread_proc_t mThreadProc = nullptr;
void* mThreadArg = nullptr;
aaudio_result_t mThreadRegistrationResult = AAUDIO_OK;
};
} /* namespace aaudio */
#endif /* AAUDIO_AUDIOSTREAM_H */