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

add input capture support to OpenSL wrapper #26

Merged
merged 7 commits into from
Dec 15, 2017
Merged

add input capture support to OpenSL wrapper #26

merged 7 commits into from
Dec 15, 2017

Conversation

philburk
Copy link
Collaborator

Refactored the OpenSL ES code.
Moved static functions into classes.
Split into an Input and Output stream.
Added RECORD support.
Added some thread safety to EngineOpenSLES.
Fixed some bugs and removed asserts.

Phil Burk added 5 commits December 13, 2017 18:36
Put Engine and OutputMixer into Singleton classes.
Create separate input and output classes.
Also fix some bugs in OpenSL ES implementation
and replace asserts with error returns.
Use mutex.
Better singleton behavior.
Separate files for each class.
@@ -64,8 +61,23 @@ class AudioStreamOpenSLES : public AudioStreamBuffered {

int32_t getFramesPerBurst() override;

static SLuint32 getDefaultByteOrder();

virtual int chanCountToChanMask(int chanCount) = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why this method needs to be declared as part of the interface? It doesn't seem to be used in any common code, only in particular implementations. Also, it can be made static.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I made it protected. It was already static. It is used by input and output streams to open a stream.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Sorry if I didn't explain my point clear enough. What I was trying to say is that virtual methods in the base class usually exist because there is either an external client or common code in the base class that uses them. For chanCountToChanMask, the usages only seem to be in the derived classes (in and out streams). So why not just define these methods in the derived classes?

Putting chanCountToChanMask doesn't help with code reuse, it only pollutes the interface definition.


case 2:
channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
break;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why isn't this defined as SL_ANDROID_SPEAKER_STEREO? Then the masks above can use it as well.

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

#define SL_ANDROID_SPEAKER_QUAD (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT \
| SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT)

#define SL_ANDROID_SPEAKER_5DOT1 (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT \
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can be defined as an extension to QUAD.

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


result = AudioStreamOpenSLES::registerBufferQueueCallback();
if (SL_RESULT_SUCCESS != result) {
LOGE("get bufferqueue interface:%p result:%s", mSimpleBufferQueueInterface, getSLErrStr(result));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why isn't this error message being printed by registerBufferQueueCallback? You seem to have the same code in the output stream.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It is printed in registerBufferQueueCallback() so I removed it from the input and output streams.


EngineOpenSLES *EngineOpenSLES::getInstance() {
static EngineOpenSLES sInstance;
return &sInstance;
Copy link
Collaborator

Choose a reason for hiding this comment

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

It is preferred to return a reference (EngineOpenSLES&) rather than pointer for preventing clients from attempting to calling 'delete' on it or putting it into a smart pointer.

Also, references can't be null which makes caller's life easier.

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

return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
case AudioFormat::Float:
return SL_ANDROID_PCM_REPRESENTATION_FLOAT;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

default: ?

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


OutputMixerOpenSL *OutputMixerOpenSL::getInstance() {
static OutputMixerOpenSL sInstance;
return &sInstance;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same note about returning the reference.

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


private:
std::mutex mLock;
std::atomic<int32_t> mOpenCount{0};
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same note about atomicity.

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

SLDataSource *audioSource,
SLDataSink *audioSink);

private:
Copy link
Collaborator

Choose a reason for hiding this comment

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

The constructor and the destructor need to be made private, and copy and assignment constructors deleted. Otherwise, someone could make another instance of this singleton.

See example code here: http://www.modernescpp.com/index.php/thread-safe-initialization-of-a-singleton

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

SLresult createAudioPlayer(SLObjectItf *objectItf,
SLDataSource *audioSource);

private:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same note about the need to hide and delete constructors.

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

@@ -0,0 +1,219 @@
/*
Copy link
Collaborator

Choose a reason for hiding this comment

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

This file must be added to CMakeLists.txt so that clients can build it

Copy link
Collaborator

Choose a reason for hiding this comment

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

Here's the relevant part of the CMakeLists.txt updated so this version builds and links correctly:

set (oboe_sources
    src/aaudio/AAudioLoader.cpp
    src/aaudio/AudioStreamAAudio.cpp
    src/common/LatencyTuner.cpp
    src/common/AudioStream.cpp
    src/common/AudioStreamBuilder.cpp
    src/common/Utilities.cpp
    src/fifo/FifoBuffer.cpp
    src/fifo/FifoController.cpp
    src/fifo/FifoControllerBase.cpp
    src/fifo/FifoControllerIndirect.cpp
    src/opensles/AudioInputStreamOpenSLES.cpp
    src/opensles/AudioOutputStreamOpenSLES.cpp
    src/opensles/AudioStreamBuffered.cpp
    src/opensles/AudioStreamOpenSLES.cpp
    src/opensles/EngineOpenSLES.cpp
    src/opensles/OpenSLESUtilities.cpp
    src/opensles/OutputMixerOpenSLES.cpp
    )

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

}

// These will wind up in <SLES/OpenSLES_Android.h>
#define SL_ANDROID_SPEAKER_QUAD (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT \
Copy link
Collaborator

Choose a reason for hiding this comment

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

Better practice to use constexpr here

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

return Result::ErrorInternal;
}

SLuint32 bitsPerSample = getBytesPerSample() * OBOE_BITS_PER_BYTE;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Use constexpr for this oboe constant and add it to the oboe namespace. The usual convention is to prefix constants with k so this would end up as oboe::kBitsPerByte

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


namespace oboe {

#define OBOE_BITS_PER_BYTE 8 // common value TODO modernize
Copy link
Collaborator

Choose a reason for hiding this comment

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

See previous comment

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

Use constexpr.
Add new files to CMakeLists.txt
Copy link
Collaborator

@mnaganov mnaganov left a comment

Choose a reason for hiding this comment

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

Please resolve the note about chanCountToChanMask before submitting.

Copy link
Collaborator

@dturner dturner left a comment

Choose a reason for hiding this comment

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

Great work!! Really excited to see this major feature implemented.

@philburk philburk merged commit a40baae into master Dec 15, 2017
@philburk philburk deleted the addinput branch February 9, 2018 01:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants