blob: 5dcddf38dcc40215fe466583d65e76512c54b570 [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 UTILITY_AAUDIO_UTILITIES_H
#define UTILITY_AAUDIO_UTILITIES_H
#include <algorithm>
#include <functional>
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <system/audio.h>
#include "aaudio/AAudio.h"
/**
* Convert an AAudio result into the closest matching Android status.
*/
android::status_t AAudioConvert_aaudioToAndroidStatus(aaudio_result_t result);
/**
* Convert an Android status into the closest matching AAudio result.
*/
aaudio_result_t AAudioConvert_androidToAAudioResult(android::status_t status);
/**
* Convert an aaudio_session_id_t to a value that is safe to pass to AudioFlinger.
* @param sessionId
* @return safe value
*/
audio_session_t AAudioConvert_aaudioToAndroidSessionId(aaudio_session_id_t sessionId);
/**
* Calculate the number of bytes and prevent numeric overflow.
* The *sizeInBytes will be set to zero if there is an error.
*
* @param numFrames frame count
* @param bytesPerFrame size of a frame in bytes
* @param sizeInBytes pointer to a variable to receive total size in bytes
* @return AAUDIO_OK or negative error, eg. AAUDIO_ERROR_OUT_OF_RANGE
*/
int32_t AAudioConvert_framesToBytes(int32_t numFrames,
int32_t bytesPerFrame,
int32_t *sizeInBytes);
audio_format_t AAudioConvert_aaudioToAndroidDataFormat(aaudio_format_t aaudio_format);
aaudio_format_t AAudioConvert_androidToAAudioDataFormat(audio_format_t format);
/**
* Note that this function does not validate the passed in value.
* That is done somewhere else.
* @return internal value
*/
audio_usage_t AAudioConvert_usageToInternal(aaudio_usage_t usage);
/**
* Note that this function does not validate the passed in value.
* That is done somewhere else.
* @return internal value
*/
audio_content_type_t AAudioConvert_contentTypeToInternal(aaudio_content_type_t contentType);
/**
* Note that this function does not validate the passed in value.
* That is done somewhere else.
* @return internal audio source
*/
audio_source_t AAudioConvert_inputPresetToAudioSource(aaudio_input_preset_t preset);
/**
* Note that this function does not validate the passed in value.
* That is done somewhere else.
* @return internal audio flags mask
*/
audio_flags_mask_t AAudioConvert_allowCapturePolicyToAudioFlagsMask(
aaudio_allowed_capture_policy_t policy);
// Note that this code may be replaced by Settings or by some other system configuration tool.
/**
* Read system property.
* @return AAUDIO_UNSPECIFIED, AAUDIO_POLICY_NEVER or AAUDIO_POLICY_AUTO or AAUDIO_POLICY_ALWAYS
*/
int32_t AAudioProperty_getMMapPolicy();
#define AAUDIO_PROP_MMAP_POLICY "aaudio.mmap_policy"
/**
* Read system property.
* @return AAUDIO_UNSPECIFIED, AAUDIO_POLICY_NEVER or AAUDIO_POLICY_AUTO or AAUDIO_POLICY_ALWAYS
*/
int32_t AAudioProperty_getMMapExclusivePolicy();
#define AAUDIO_PROP_MMAP_EXCLUSIVE_POLICY "aaudio.mmap_exclusive_policy"
/**
* Read system property.
* @return number of bursts per AAudio service mixer cycle
*/
int32_t AAudioProperty_getMixerBursts();
#define AAUDIO_PROP_MIXER_BURSTS "aaudio.mixer_bursts"
/**
* Read a system property that specifies the number of extra microseconds that a thread
* should sleep when waiting for another thread to service a FIFO. This is used
* to avoid the waking thread from being overly optimistic about the other threads
* wakeup timing. This value should be set high enough to cover typical scheduling jitter
* for a real-time thread.
*
* @return number of microseconds to delay the wakeup.
*/
int32_t AAudioProperty_getWakeupDelayMicros();
#define AAUDIO_PROP_WAKEUP_DELAY_USEC "aaudio.wakeup_delay_usec"
/**
* Read a system property that specifies the minimum sleep time when polling the FIFO.
*
* @return minimum number of microseconds to sleep.
*/
int32_t AAudioProperty_getMinimumSleepMicros();
#define AAUDIO_PROP_MINIMUM_SLEEP_USEC "aaudio.minimum_sleep_usec"
/**
* Read system property.
* This is handy in case the DMA is bursting too quickly for the CPU to keep up.
* For example, there may be a DMA burst every 100 usec but you only
* want to feed the MMAP buffer every 2000 usec.
*
* This will affect the framesPerBurst for an MMAP stream.
*
* @return minimum number of microseconds for a MMAP HW burst
*/
int32_t AAudioProperty_getHardwareBurstMinMicros();
#define AAUDIO_PROP_HW_BURST_MIN_USEC "aaudio.hw_burst_min_usec"
/**
* Read a system property that specifies an offset that will be added to MMAP timestamps.
* This can be used to correct bias in the timestamp.
* It can also be used to analyze the time distribution of the timestamp
* by progressively modifying the offset and listening for glitches.
*
* @return number of microseconds to offset the time part of an MMAP timestamp
*/
int32_t AAudioProperty_getInputMMapOffsetMicros();
#define AAUDIO_PROP_INPUT_MMAP_OFFSET_USEC "aaudio.in_mmap_offset_usec"
int32_t AAudioProperty_getOutputMMapOffsetMicros();
#define AAUDIO_PROP_OUTPUT_MMAP_OFFSET_USEC "aaudio.out_mmap_offset_usec"
// These are powers of two that can be combined as a bit mask.
// AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM must be enabled before the stream is opened.
#define AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM 1
#define AAUDIO_LOG_RESERVED_2 2
#define AAUDIO_LOG_RESERVED_4 4
#define AAUDIO_LOG_RESERVED_8 8
/**
* Use a mask to enable various logs in AAudio.
* @return mask that enables various AAudio logs, such as AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM
*/
int32_t AAudioProperty_getLogMask();
#define AAUDIO_PROP_LOG_MASK "aaudio.log_mask"
/**
* Is flush allowed for the given state?
* @param state
* @return AAUDIO_OK if allowed or an error
*/
aaudio_result_t AAudio_isFlushAllowed(aaudio_stream_state_t state);
/**
* Try a function f until it returns true.
*
* The function is always called at least once.
*
* @param f the function to evaluate, which returns a bool.
* @param times the number of times to evaluate f.
* @param sleepMs the sleep time per check of f, if greater than 0.
* @return true if f() eventually returns true.
*/
static inline bool AAudio_tryUntilTrue(
std::function<bool()> f, int times, int sleepMs) {
static const useconds_t US_PER_MS = 1000;
sleepMs = std::max(sleepMs, 0);
for (;;) {
if (f()) return true;
if (times <= 1) return false;
--times;
usleep(sleepMs * US_PER_MS);
}
}
/**
* Simple double buffer for a structure that can be written occasionally and read occasionally.
* This allows a SINGLE writer with multiple readers.
*
* It is OK if the FIFO overflows and we lose old values.
* It is also OK if we read an old value.
* Thread may return a non-atomic result if the other thread is rapidly writing
* new values on another core.
*/
template <class T>
class SimpleDoubleBuffer {
public:
SimpleDoubleBuffer()
: mValues() {}
__attribute__((no_sanitize("integer")))
void write(T value) {
int index = mCounter.load() & 1;
mValues[index] = value;
mCounter++; // Increment AFTER updating storage, OK if it wraps.
}
/**
* This should only be called by the same thread that calls write() or when
* no other thread is calling write.
*/
void clear() {
mCounter.store(0);
}
T read() const {
T result;
int before;
int after;
int timeout = 3;
do {
// Check to see if a write occurred while were reading.
before = mCounter.load();
int index = (before & 1) ^ 1;
result = mValues[index];
after = mCounter.load();
} while ((after != before) && (after > 0) && (--timeout > 0));
return result;
}
/**
* @return true if at least one value has been written
*/
bool isValid() const {
return mCounter.load() > 0;
}
private:
T mValues[2];
std::atomic<int> mCounter{0};
};
class Timestamp {
public:
Timestamp()
: mPosition(0)
, mNanoseconds(0) {}
Timestamp(int64_t position, int64_t nanoseconds)
: mPosition(position)
, mNanoseconds(nanoseconds) {}
int64_t getPosition() const { return mPosition; }
int64_t getNanoseconds() const { return mNanoseconds; }
private:
// These cannot be const because we need to implement the copy assignment operator.
int64_t mPosition;
int64_t mNanoseconds;
};
/**
* Pass a request to another thread.
* This is used when one thread, A, wants another thread, B, to do something.
* A naive approach would be for A to set a flag and for B to clear it when done.
* But that creates a race condition. This technique avoids the race condition.
*
* Assumes only one requester and one acknowledger.
*/
class AtomicRequestor {
public:
__attribute__((no_sanitize("integer")))
void request() {
mRequested++;
}
__attribute__((no_sanitize("integer")))
bool isRequested() {
return (mRequested.load() - mAcknowledged.load()) > 0;
}
__attribute__((no_sanitize("integer")))
void acknowledge() {
mAcknowledged++;
}
private:
std::atomic<int> mRequested{0};
std::atomic<int> mAcknowledged{0};
};
#endif //UTILITY_AAUDIO_UTILITIES_H