Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New namespace, constexprs and scoped enums #18

Merged
merged 11 commits into from
Dec 1, 2017
28 changes: 26 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,32 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -std=c++11")
# Specify directories which the compiler should look for headers
include_directories(
include
src)
src
)

file(GLOB_RECURSE oboe_sources src/*)
set (oboe_sources
include/oboe/LatencyTuner.h
include/oboe/Definitions.h
include/oboe/Stream.h
include/oboe/StreamBase.h
include/oboe/StreamBuilder.h
include/oboe/StreamCallback.h
include/oboe/Utilities.h
src/aaudio/AAudioLoader.cpp
src/aaudio/StreamAAudio.cpp
src/common/AudioClock.h
src/common/OboeDebug.h
src/common/LatencyTuner.cpp
src/common/Stream.cpp
src/common/StreamBuilder.cpp
src/common/Utilities.cpp
src/fifo/FifoBuffer.cpp
src/fifo/FifoController.cpp
src/fifo/FifoControllerBase.cpp
src/fifo/FifoControllerIndirect.cpp
src/opensles/StreamBuffered.cpp
src/opensles/StreamOpenSLES.cpp
src/opensles/OpenSLESUtilities.cpp
)

add_library(oboe STATIC ${oboe_sources})
130 changes: 65 additions & 65 deletions FullGuide.md

Large diffs are not rendered by default.

36 changes: 18 additions & 18 deletions GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,24 @@ Include the Oboe header:

#include <oboe/Oboe.h>

Streams are built using an `OboeStreamBuilder`. Create one like this:
Streams are built using an `StreamBuilder`. Create one like this:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c/an/a/

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the class names Stream and StreamBuilder too generic? Is there a danger of colliding if developers are using multiple namespaces?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There would only be a danger if they're using non-qualified namespaces e.g.

using namespace oboe; Stream stream;

But yes, I do think Stream is too generic. AudioStream, AudioStreamBuilder etc would be more readable. Also if we ever support MIDI we could have a MidiStream. If you agree I'll rename.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

an -> a

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deferring doing the an/a changes until we have made a decision on Stream vs AudioStream naming


OboeStreamBuilder builder;
oboe::StreamBuilder builder;

Use the builder's set methods to set properties on the stream (you can read more about these properties in the [full guide](FullGuide.md)):

builder.setDirection(OBOE_DIRECTION_OUTPUT);
builder.setPerformanceMode(OBOE_PERFORMANCE_MODE_LOW_LATENCY);
builder.setSharingMode(OBOE_SHARING_MODE_EXCLUSIVE);
builder.setDirection(oboe::Direction::Output);
builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);
builder.setSharingMode(oboe::SharingMode::Exclusive);

Define an `OboeStreamCallback` class to receive callbacks whenever the stream requires new data.
Define an `StreamCallback` class to receive callbacks whenever the stream requires new data.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

an -> a


class MyCallback : public OboeStreamCallback {
class MyCallback : public oboe::StreamCallback {
public:
oboe_data_callback_result_t
onAudioReady(OboeStream *audioStream, void *audioData, int32_t numFrames){
oboe::Result
onAudioReady(oboe::Stream *audioStream, void *audioData, int32_t numFrames){
generateSineWave(static_cast<float *>(audioData), numFrames);
return OBOE_CALLBACK_RESULT_CONTINUE;
return oboe::DataCallbackResult::Continue;
}
};

Expand All @@ -76,21 +76,21 @@ Supply this callback class to the builder:

Open the stream:

OboeStream *stream;
oboe_result_t result = builder.openStream(&stream);
oboe::Stream *stream;
oboe::Result result = builder.openStream(&stream);

Check the result to make sure the stream was opened successfully. Oboe has many convenience methods for converting its types into human-readable strings, they all start with `Oboe_convert`:
Check the result to make sure the stream was opened successfully. Oboe has many convenience methods for converting its types into human-readable strings, they all start with `oboe::convert`:

if (result != OBOE_OK){
LOGE("Failed to create stream. Error: %s", Oboe_convertResultToText(result));
if (result != Result::OK){
LOGE("Failed to create stream. Error: %s", oboe::convertResultToText(result));
}

Note that this sample code uses the [logging macros from here](https://github.com/googlesamples/android-audio-high-performance/blob/master/debug-utils/logging_macros.h).

Check the properties of the created stream. The **format** is one property which you should check. The default is `float` on API 21+ and `int16_t` on API 20 or lower. This will dictate the `audioData` type in the `OboeStreamCallback::onAudioReady` callback.
Check the properties of the created stream. The **format** is one property which you should check. The default is `float` on API 21+ and `int16_t` on API 20 or lower. This will dictate the `audioData` type in the `StreamCallback::onAudioReady` callback.

oboe_audio_format_t format = stream->getFormat();
LOGI("Stream format is %s", Oboe_convertAudioFormatToText(format));
oboe::AudioFormat format = stream->getFormat();
LOGI("Stream format is %s", oboe::convertAudioFormatToText(format));

Now start the stream.

Expand Down
4 changes: 2 additions & 2 deletions build_all_android.sh
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ build_oboe mips
printf "%s\r\n" "example: |" >> ${CDEP_MANIFEST_FILE}
printf "%s\r\n" " #include <oboe/Oboe.h>" >> ${CDEP_MANIFEST_FILE}
printf "%s\r\n" " void openStream() {" >> ${CDEP_MANIFEST_FILE}
printf "%s\r\n" " OboeStreamBuilder builder;" >> ${CDEP_MANIFEST_FILE}
printf "%s\r\n" " OboeStream *stream;" >> ${CDEP_MANIFEST_FILE}
printf "%s\r\n" " StreamBuilder builder;" >> ${CDEP_MANIFEST_FILE}
printf "%s\r\n" " Stream *stream;" >> ${CDEP_MANIFEST_FILE}
printf "%s\r\n" " builder.openStream(&stream);" >> ${CDEP_MANIFEST_FILE}
printf "%s\r\n" " }" >> ${CDEP_MANIFEST_FILE}

Expand Down
114 changes: 114 additions & 0 deletions include/oboe/Definitions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* 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_DEFINITIONS_H
#define OBOE_DEFINITIONS_H

#include <cstdint>
#include <aaudio/AAudio.h>

namespace oboe {

constexpr int32_t kUnspecified = 0;

constexpr int64_t kNanosPerMicrosecond = 1000;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a TODO to consider using std::chrono, as it provides a lot of time unit conversion utilities.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

constexpr int64_t kNanosPerMillisecond = kNanosPerMicrosecond * 1000;
constexpr int64_t kMillisPerSecond = 1000;
constexpr int64_t kNanosPerSecond = kNanosPerMillisecond * kMillisPerSecond;

enum class StreamState : aaudio_stream_state_t {
Uninitialized = AAUDIO_STREAM_STATE_UNINITIALIZED,
Open = AAUDIO_STREAM_STATE_OPEN,
Starting = AAUDIO_STREAM_STATE_STARTING,
Started = AAUDIO_STREAM_STATE_STARTED,
Pausing = AAUDIO_STREAM_STATE_PAUSING,
Paused = AAUDIO_STREAM_STATE_PAUSED,
Flushing = AAUDIO_STREAM_STATE_FLUSHING,
Flushed = AAUDIO_STREAM_STATE_FLUSHED,
Stopping = AAUDIO_STREAM_STATE_STOPPING,
Stopped = AAUDIO_STREAM_STATE_STOPPED,
Closing = AAUDIO_STREAM_STATE_CLOSING,
Closed = AAUDIO_STREAM_STATE_CLOSED,
};

enum class Direction : aaudio_direction_t {
Output = AAUDIO_DIRECTION_OUTPUT,
Input = AAUDIO_DIRECTION_INPUT,
};

enum class AudioFormat : aaudio_format_t {
Invalid = AAUDIO_FORMAT_INVALID,
Unspecified = AAUDIO_FORMAT_UNSPECIFIED,
I16 = AAUDIO_FORMAT_PCM_I16,
Float = AAUDIO_FORMAT_PCM_FLOAT,
};

enum class DataCallbackResult : aaudio_data_callback_result_t {
Continue = AAUDIO_CALLBACK_RESULT_CONTINUE,
Stop = AAUDIO_CALLBACK_RESULT_STOP,
};

enum class Result : aaudio_result_t {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider renaming this class to "Error", which would allow dropping the "Error" prefix from the enum items.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it normal to have an Error::OK value? We're going to see a lot of:

if (error != Error::OK){

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's perhaps not the best expression. But seeing a lot of "Error" prefixes doesn't make me happy either. Although, I've just checked Vulkan's 'Result' type, and they also have "error" prefixes everywhere. OK, let's not consider changing anything here for now.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are relying on aaudio_result_t beeing int32_t in multiple places. Maybe we should add in some .cpp static_assert(is_same<int32_t, aaudio_result_t>)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Added checks for all AAudio primitive data types.

OK,
ErrorBase = AAUDIO_ERROR_BASE,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ErrorBase shouldn't be used as a source of an assignment anywhere. To prevent this, I would suggest introducing a helper function 'isError' which compares the value against AAUDIO_ERROR_BASE.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't I just remove ErrorBase from the list of possible values in the Result enum?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. What I've meant is that if anyone will ever need to check against AAUDIO_ERROR_BASE, you can provide a convenience method.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ErrorBase removed

ErrorDisconnected = AAUDIO_ERROR_DISCONNECTED,
ErrorIllegalArgument = AAUDIO_ERROR_ILLEGAL_ARGUMENT,
ErrorInternal = AAUDIO_ERROR_INTERNAL,
ErrorInvalidState = AAUDIO_ERROR_INVALID_STATE,
ErrorInvalidHandle = AAUDIO_ERROR_INVALID_HANDLE,
ErrorUnimplemented = AAUDIO_ERROR_UNIMPLEMENTED,
ErrorUnavailable = AAUDIO_ERROR_UNAVAILABLE,
ErrorNoFreeHandles = AAUDIO_ERROR_NO_FREE_HANDLES,
ErrorNoMemory = AAUDIO_ERROR_NO_MEMORY,
ErrorNull = AAUDIO_ERROR_NULL,
ErrorTimeout = AAUDIO_ERROR_TIMEOUT,
ErrorWouldBlock = AAUDIO_ERROR_WOULD_BLOCK,
ErrorInvalidFormat = AAUDIO_ERROR_INVALID_FORMAT,
ErrorOutOfRange = AAUDIO_ERROR_OUT_OF_RANGE,
ErrorNoService = AAUDIO_ERROR_NO_SERVICE,
ErrorInvalidRate = AAUDIO_ERROR_INVALID_RATE,
};

enum class SharingMode : aaudio_sharing_mode_t {

/**
* This will be the only stream using a particular source or sink.
* This mode will provide the lowest possible latency.
* You should close EXCLUSIVE streams immediately when you are not using them.
*/
Exclusive = AAUDIO_SHARING_MODE_EXCLUSIVE,

/**
* Multiple applications will be mixed by the AAudio Server.
* This will have higher latency than the EXCLUSIVE mode.
*/
Shared = AAUDIO_SHARING_MODE_SHARED,
};

enum class PerformanceMode : aaudio_performance_mode_t {

// No particular performance needs. Default.
None = AAUDIO_PERFORMANCE_MODE_NONE,

// Extending battery life is most important.
PowerSaving = AAUDIO_PERFORMANCE_MODE_POWER_SAVING,

// Reducing latency is most important.
LowLatency = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY
};
} // namespace oboe

#endif // OBOE_DEFINITIONS_H
43 changes: 23 additions & 20 deletions include/oboe/OboeLatencyTuner.h → include/oboe/LatencyTuner.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
* limitations under the License.
*/

#ifndef OBOE_OBOE_LATENCY_TUNER_
#define OBOE_OBOE_LATENCY_TUNER_
#ifndef OBOE_LATENCY_TUNER_
#define OBOE_LATENCY_TUNER_

#include <atomic>
#include <stdint.h>
#include "oboe/OboeDefinitions.h"
#include "oboe/OboeStream.h"
#include <cstdint>
#include "oboe/Definitions.h"
#include "oboe/Stream.h"

namespace oboe {

/**
* This can be used to dynamically tune the latency of an output stream.
Expand All @@ -37,19 +39,19 @@
* stream->getBufferSize() periodically.
*
*/
class OboeLatencyTuner {
class LatencyTuner {
public:
explicit OboeLatencyTuner(OboeStream &stream);
explicit LatencyTuner(Stream &stream);

/**
* Adjust the bufferSizeInFrames to optimize latency.
* It will start with a low latency and then raise it if an underrun occurs.
*
* Latency tuning is only supported for AAudio.
*
* @return OBOE_OK or negative error, OBOE_ERROR_UNIMPLEMENTED for OpenSL ES
* @return OK or negative error, ErrorUnimplemented for OpenSL ES
*/
oboe_result_t tune();
Result tune();

/**
* This may be called from another thread. Then tune() will call reset(),
Expand All @@ -71,23 +73,24 @@ class OboeLatencyTuner {
*/
void reset();

enum latency_tuner_state_t {
STATE_IDLE,
STATE_ACTIVE,
STATE_AT_MAX,
STATE_UNSUPPORTED
enum class State {
Idle,
Active,
AtMax,
Unsupported
} ;

enum {
IDLE_COUNT = 8 // arbitrary number of calls to wait before bumping up the latency
};
// arbitrary number of calls to wait before bumping up the latency
static constexpr int32_t kIdleCount = 8;

OboeStream &mStream;
latency_tuner_state_t mState = STATE_IDLE;
Stream &mStream;
State mState = State::Idle;
int32_t mPreviousXRuns = 0;
int32_t mIdleCountDown = 0;
std::atomic<int32_t> mLatencyTriggerRequests{0}; // TODO user atomic requester from AAudio
std::atomic<int32_t> mLatencyTriggerResponses{0};
};

#endif // OBOE_OBOE_LATENCY_TUNER_
} // namespace oboe

#endif // OBOE_LATENCY_TUNER_
12 changes: 6 additions & 6 deletions include/oboe/Oboe.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@
#ifndef OBOE_OBOE_H
#define OBOE_OBOE_H

#include "oboe/OboeDefinitions.h"
#include "oboe/OboeLatencyTuner.h"
#include "oboe/OboeStream.h"
#include "oboe/OboeStreamBase.h"
#include "oboe/OboeStreamBuilder.h"
#include "oboe/OboeUtilities.h"
#include "oboe/Definitions.h"
#include "oboe/LatencyTuner.h"
#include "oboe/Stream.h"
#include "oboe/StreamBase.h"
#include "oboe/StreamBuilder.h"
#include "oboe/Utilities.h"

#endif //OBOE_OBOE_H
Loading