xref: /aosp_15_r20/external/oboe/docs/GettingStarted.md (revision 05767d913155b055644481607e6fa1e35e2fe72c)
1*05767d91SRobert Wu# Adding Oboe to your project
2*05767d91SRobert WuThere are two ways use Oboe in your Android Studio project:
3*05767d91SRobert Wu
4*05767d91SRobert Wu1) **Use the Oboe pre-built library binaries and headers**. Use this approach if you just want to use a stable version of the Oboe library in your project.
5*05767d91SRobert Wu
6*05767d91SRobert Wuor
7*05767d91SRobert Wu
8*05767d91SRobert Wu2) **Build Oboe from source.** Use this approach if you would like to debug or make changes to the Oboe source code and contribute back to the project.
9*05767d91SRobert Wu
10*05767d91SRobert Wu## Option 1) Using pre-built binaries and headers
11*05767d91SRobert Wu
12*05767d91SRobert WuOboe is distributed as a [prefab](https://github.com/google/prefab) package via [Google Maven](https://maven.google.com/web/index.html) (search for "oboe"). [Prefab support was added](https://android-developers.googleblog.com/2020/02/native-dependencies-in-android-studio-40.html) to [Android Studio 4.0](https://developer.android.com/studio) so you'll need to be using this version of Android Studio or above.
13*05767d91SRobert Wu
14*05767d91SRobert WuAdd the oboe dependency to your app's `build.gradle` file. Replace "X.X.X" with the [latest stable version](https://github.com/google/oboe/releases/) of Oboe:
15*05767d91SRobert Wu
16*05767d91SRobert Wu    dependencies {
17*05767d91SRobert Wu        implementation 'com.google.oboe:oboe:X.X.X'
18*05767d91SRobert Wu    }
19*05767d91SRobert Wu
20*05767d91SRobert WuAlso enable prefab by adding:
21*05767d91SRobert Wu
22*05767d91SRobert Wu    android {
23*05767d91SRobert Wu        buildFeatures {
24*05767d91SRobert Wu            prefab true
25*05767d91SRobert Wu        }
26*05767d91SRobert Wu    }
27*05767d91SRobert Wu
28*05767d91SRobert WuInclude and link to oboe by updating your `CMakeLists.txt`:
29*05767d91SRobert Wu
30*05767d91SRobert Wu    find_package (oboe REQUIRED CONFIG)
31*05767d91SRobert Wu    target_link_libraries(native-lib oboe::oboe) # You may have other libraries here such as `log`.
32*05767d91SRobert Wu
33*05767d91SRobert WuHere's a complete example `CMakeLists.txt` file:
34*05767d91SRobert Wu
35*05767d91SRobert Wu    cmake_minimum_required(VERSION 3.4.1)
36*05767d91SRobert Wu
37*05767d91SRobert Wu    # Build our own native library
38*05767d91SRobert Wu    add_library (native-lib SHARED native-lib.cpp )
39*05767d91SRobert Wu
40*05767d91SRobert Wu    # Find the Oboe package
41*05767d91SRobert Wu    find_package (oboe REQUIRED CONFIG)
42*05767d91SRobert Wu
43*05767d91SRobert Wu    # Specify the libraries which our native library is dependent on, including Oboe
44*05767d91SRobert Wu    target_link_libraries(native-lib log oboe::oboe)
45*05767d91SRobert Wu
46*05767d91SRobert WuConfigure your app to use the shared STL by updating your `app/build.gradle`:
47*05767d91SRobert Wu
48*05767d91SRobert Wu    android {
49*05767d91SRobert Wu        defaultConfig {
50*05767d91SRobert Wu            externalNativeBuild {
51*05767d91SRobert Wu                cmake {
52*05767d91SRobert Wu                    arguments "-DANDROID_STL=c++_shared"
53*05767d91SRobert Wu                }
54*05767d91SRobert Wu	        }
55*05767d91SRobert Wu        }
56*05767d91SRobert Wu    }
57*05767d91SRobert Wu
58*05767d91SRobert Wu## Option 2) Building from source
59*05767d91SRobert Wu
60*05767d91SRobert Wu### 1. Clone the github repository
61*05767d91SRobert WuStart by cloning the [latest stable release](https://github.com/google/oboe/releases/) of the Oboe repository, for example:
62*05767d91SRobert Wu
63*05767d91SRobert Wu    git clone -b 1.6-stable https://github.com/google/oboe
64*05767d91SRobert Wu
65*05767d91SRobert Wu**Make a note of the path which you cloned oboe into - you will need it shortly**
66*05767d91SRobert Wu
67*05767d91SRobert WuIf you use git as your version control system, consider adding Oboe as a [submodule](https://gist.github.com/gitaarik/8735255)  (underneath your
68*05767d91SRobert Wucpp directory)
69*05767d91SRobert Wu
70*05767d91SRobert Wu```
71*05767d91SRobert Wugit submodule add https://github.com/google/oboe
72*05767d91SRobert Wu```
73*05767d91SRobert Wu
74*05767d91SRobert WuThis makes it easier to integrate updates to Oboe into your app, as well as contribute to the Oboe project.
75*05767d91SRobert Wu
76*05767d91SRobert Wu### 2. Update CMakeLists.txt
77*05767d91SRobert WuOpen your app's `CMakeLists.txt`. This can be found under `External Build Files` in the Android project view. If you don't have a `CMakeLists.txt` you will need to [add C++ support to your project](https://developer.android.com/studio/projects/add-native-code).
78*05767d91SRobert Wu
79*05767d91SRobert Wu![CMakeLists.txt location in Android Studio](images/cmakelists-location-in-as.png "CMakeLists.txt location in Android Studio")
80*05767d91SRobert Wu
81*05767d91SRobert WuNow add the following commands to the end of `CMakeLists.txt`. **Remember to update `**PATH TO OBOE**` with your local Oboe path from the previous step**:
82*05767d91SRobert Wu
83*05767d91SRobert Wu    # Set the path to the Oboe directory.
84*05767d91SRobert Wu    set (OBOE_DIR ***PATH TO OBOE***)
85*05767d91SRobert Wu
86*05767d91SRobert Wu    # Add the Oboe library as a subdirectory in your project.
87*05767d91SRobert Wu    # add_subdirectory tells CMake to look in this directory to
88*05767d91SRobert Wu    # compile oboe source files using oboe's CMake file.
89*05767d91SRobert Wu    # ./oboe specifies where the compiled binaries will be stored
90*05767d91SRobert Wu    add_subdirectory (${OBOE_DIR} ./oboe)
91*05767d91SRobert Wu
92*05767d91SRobert Wu    # Specify the path to the Oboe header files.
93*05767d91SRobert Wu    # This allows targets compiled with this CMake (application code)
94*05767d91SRobert Wu    # to see public Oboe headers, in order to access its API.
95*05767d91SRobert Wu    include_directories (${OBOE_DIR}/include)
96*05767d91SRobert Wu
97*05767d91SRobert Wu
98*05767d91SRobert WuIn the same file find the [`target_link_libraries`](https://cmake.org/cmake/help/latest/command/target_link_libraries.html) command.
99*05767d91SRobert WuAdd `oboe` to the list of libraries which your app's library depends on. For example:
100*05767d91SRobert Wu
101*05767d91SRobert Wu    target_link_libraries(native-lib oboe)
102*05767d91SRobert Wu
103*05767d91SRobert WuHere's a complete example `CMakeLists.txt` file:
104*05767d91SRobert Wu
105*05767d91SRobert Wu    cmake_minimum_required(VERSION 3.4.1)
106*05767d91SRobert Wu
107*05767d91SRobert Wu    # Build our own native library
108*05767d91SRobert Wu    add_library (native-lib SHARED native-lib.cpp )
109*05767d91SRobert Wu
110*05767d91SRobert Wu    # Build the Oboe library
111*05767d91SRobert Wu    set (OBOE_DIR ./oboe)
112*05767d91SRobert Wu    add_subdirectory (${OBOE_DIR} ./oboe)
113*05767d91SRobert Wu
114*05767d91SRobert Wu    # Make the Oboe public headers available to our app
115*05767d91SRobert Wu    include_directories (${OBOE_DIR}/include)
116*05767d91SRobert Wu
117*05767d91SRobert Wu    # Specify the libraries which our native library is dependent on, including Oboe
118*05767d91SRobert Wu    target_link_libraries (native-lib log oboe)
119*05767d91SRobert Wu
120*05767d91SRobert Wu
121*05767d91SRobert WuNow go to `Build->Refresh Linked C++ Projects` to have Android Studio index the Oboe library.
122*05767d91SRobert Wu
123*05767d91SRobert WuVerify that your project builds correctly. If you have any issues building please [report them here](issues/new).
124*05767d91SRobert Wu
125*05767d91SRobert Wu# Using Oboe
126*05767d91SRobert WuOnce you've added Oboe to your project you can start using Oboe's features. The simplest, and probably most common thing you'll do in Oboe is to create an audio stream.
127*05767d91SRobert Wu
128*05767d91SRobert Wu## Creating an audio stream
129*05767d91SRobert WuInclude the Oboe header:
130*05767d91SRobert Wu
131*05767d91SRobert Wu    #include <oboe/Oboe.h>
132*05767d91SRobert Wu
133*05767d91SRobert WuStreams are built using an `AudioStreamBuilder`. Create one like this:
134*05767d91SRobert Wu
135*05767d91SRobert Wu    oboe::AudioStreamBuilder builder;
136*05767d91SRobert Wu
137*05767d91SRobert WuUse the builder's set methods to set properties on the stream (you can read more about these properties in the [full guide](FullGuide.md)):
138*05767d91SRobert Wu
139*05767d91SRobert Wu    builder.setDirection(oboe::Direction::Output);
140*05767d91SRobert Wu    builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);
141*05767d91SRobert Wu    builder.setSharingMode(oboe::SharingMode::Exclusive);
142*05767d91SRobert Wu    builder.setFormat(oboe::AudioFormat::Float);
143*05767d91SRobert Wu    builder.setChannelCount(oboe::ChannelCount::Mono);
144*05767d91SRobert Wu
145*05767d91SRobert WuThe builder's set methods return a pointer to the builder. So they can be easily chained:
146*05767d91SRobert Wu
147*05767d91SRobert Wu```
148*05767d91SRobert Wuoboe::AudioStreamBuilder builder;
149*05767d91SRobert Wubuilder.setPerformanceMode(oboe::PerformanceMode::LowLatency)
150*05767d91SRobert Wu  ->setSharingMode(oboe::SharingMode::Exclusive)
151*05767d91SRobert Wu  ->setDataCallback(myCallback)
152*05767d91SRobert Wu  ->setFormat(oboe::AudioFormat::Float);
153*05767d91SRobert Wu```
154*05767d91SRobert Wu
155*05767d91SRobert WuDefine an `AudioStreamDataCallback` class to receive callbacks whenever the stream requires new data.
156*05767d91SRobert Wu
157*05767d91SRobert Wu    class MyCallback : public oboe::AudioStreamDataCallback {
158*05767d91SRobert Wu    public:
159*05767d91SRobert Wu        oboe::DataCallbackResult
160*05767d91SRobert Wu        onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames) {
161*05767d91SRobert Wu
162*05767d91SRobert Wu            // We requested AudioFormat::Float. So if the stream opens
163*05767d91SRobert Wu	    // we know we got the Float format.
164*05767d91SRobert Wu            // If you do not specify a format then you should check what format
165*05767d91SRobert Wu            // the stream has and cast to the appropriate type.
166*05767d91SRobert Wu            auto *outputData = static_cast<float *>(audioData);
167*05767d91SRobert Wu
168*05767d91SRobert Wu            // Generate random numbers (white noise) centered around zero.
169*05767d91SRobert Wu            const float amplitude = 0.2f;
170*05767d91SRobert Wu            for (int i = 0; i < numFrames; ++i){
171*05767d91SRobert Wu                outputData[i] = ((float)drand48() - 0.5f) * 2 * amplitude;
172*05767d91SRobert Wu            }
173*05767d91SRobert Wu
174*05767d91SRobert Wu            return oboe::DataCallbackResult::Continue;
175*05767d91SRobert Wu        }
176*05767d91SRobert Wu    };
177*05767d91SRobert Wu
178*05767d91SRobert WuYou can find examples of how to play sound using digital synthesis and pre-recorded audio in the [code samples](../samples).
179*05767d91SRobert Wu
180*05767d91SRobert WuDeclare your callback somewhere that it won't get deleted while you are using it.
181*05767d91SRobert Wu
182*05767d91SRobert Wu    MyCallback myCallback;
183*05767d91SRobert Wu
184*05767d91SRobert WuSupply this callback class to the builder:
185*05767d91SRobert Wu
186*05767d91SRobert Wu    builder.setDataCallback(&myCallback);
187*05767d91SRobert Wu
188*05767d91SRobert WuDeclare a shared pointer for the stream. Make sure it is declared with the appropriate scope. The best place is as a member variable in a managing class or as a global. Avoid declaring it as a local variable because the stream may get deleted when the function returns.
189*05767d91SRobert Wu
190*05767d91SRobert Wu    std::shared_ptr<oboe::AudioStream> mStream;
191*05767d91SRobert Wu
192*05767d91SRobert WuOpen the stream:
193*05767d91SRobert Wu
194*05767d91SRobert Wu    oboe::Result result = builder.openStream(mStream);
195*05767d91SRobert Wu
196*05767d91SRobert WuCheck the result to make sure the stream was opened successfully. Oboe has a convenience method for converting its types into human-readable strings called `oboe::convertToText`:
197*05767d91SRobert Wu
198*05767d91SRobert Wu    if (result != oboe::Result::OK) {
199*05767d91SRobert Wu        LOGE("Failed to create stream. Error: %s", oboe::convertToText(result));
200*05767d91SRobert Wu    }
201*05767d91SRobert Wu
202*05767d91SRobert WuNote 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).
203*05767d91SRobert Wu
204*05767d91SRobert Wu## Playing audio
205*05767d91SRobert WuCheck the properties of the created stream. If you did not specify a channelCount, sampleRate, or format then you need to
206*05767d91SRobert Wuquery the stream to see what you got. The **format** property will dictate the `audioData` type in the `AudioStreamDataCallback::onAudioReady` callback. If you did specify any of those three properties then you will get what you requested.
207*05767d91SRobert Wu
208*05767d91SRobert Wu    oboe::AudioFormat format = mStream->getFormat();
209*05767d91SRobert Wu    LOGI("AudioStream format is %s", oboe::convertToText(format));
210*05767d91SRobert Wu
211*05767d91SRobert WuNow start the stream.
212*05767d91SRobert Wu
213*05767d91SRobert Wu    mStream->requestStart();
214*05767d91SRobert Wu
215*05767d91SRobert WuAt this point you should start receiving callbacks.
216*05767d91SRobert Wu
217*05767d91SRobert WuTo stop receiving callbacks call
218*05767d91SRobert Wu
219*05767d91SRobert Wu    mStream->requestStop();
220*05767d91SRobert Wu
221*05767d91SRobert Wu## Closing the stream
222*05767d91SRobert WuIt is important to close your stream when you're not using it to avoid hogging audio resources which other apps could use. This is particularly true when using `SharingMode::Exclusive` because you might prevent other apps from obtaining a low latency audio stream.
223*05767d91SRobert Wu
224*05767d91SRobert WuStreams should be explicitly closed when the app is no longer playing audio.
225*05767d91SRobert Wu
226*05767d91SRobert Wu    mStream->close();
227*05767d91SRobert Wu
228*05767d91SRobert Wu`close()` is a blocking call which also stops the stream.
229*05767d91SRobert Wu
230*05767d91SRobert WuFor apps which only play or record audio when they are in the foreground this is usually done when [`Activity.onPause()`](https://developer.android.com/guide/components/activities/activity-lifecycle#onpause) is called.
231*05767d91SRobert Wu
232*05767d91SRobert Wu## Reconfiguring streams
233*05767d91SRobert WuAfter closing, in order to change the configuration of the stream, simply call `openStream`
234*05767d91SRobert Wuagain. The existing stream is deleted and a new stream is built and
235*05767d91SRobert Wupopulates the `mStream` variable.
236*05767d91SRobert Wu```
237*05767d91SRobert Wu// Modify the builder with some additional properties at runtime.
238*05767d91SRobert Wubuilder.setDeviceId(MY_DEVICE_ID);
239*05767d91SRobert Wu// Re-open the stream with some additional config
240*05767d91SRobert Wu// The old AudioStream is automatically deleted
241*05767d91SRobert Wubuilder.openStream(mStream);
242*05767d91SRobert Wu```
243*05767d91SRobert Wu
244*05767d91SRobert Wu## Example
245*05767d91SRobert Wu
246*05767d91SRobert WuThe following class is a complete implementation of an audio player that
247*05767d91SRobert Wurenders a sine wave.
248*05767d91SRobert Wu```
249*05767d91SRobert Wu#include <oboe/Oboe.h>
250*05767d91SRobert Wu#include <math.h>
251*05767d91SRobert Wuusing namespace oboe;
252*05767d91SRobert Wu
253*05767d91SRobert Wuclass OboeSinePlayer: public oboe::AudioStreamDataCallback {
254*05767d91SRobert Wupublic:
255*05767d91SRobert Wu
256*05767d91SRobert Wu    virtual ~OboeSinePlayer() = default;
257*05767d91SRobert Wu
258*05767d91SRobert Wu    // Call this from Activity onResume()
259*05767d91SRobert Wu    int32_t startAudio() {
260*05767d91SRobert Wu        std::lock_guard<std::mutex> lock(mLock);
261*05767d91SRobert Wu        oboe::AudioStreamBuilder builder;
262*05767d91SRobert Wu        // The builder set methods can be chained for convenience.
263*05767d91SRobert Wu        Result result = builder.setSharingMode(oboe::SharingMode::Exclusive)
264*05767d91SRobert Wu                ->setPerformanceMode(oboe::PerformanceMode::LowLatency)
265*05767d91SRobert Wu                ->setChannelCount(kChannelCount)
266*05767d91SRobert Wu                ->setSampleRate(kSampleRate)
267*05767d91SRobert Wu		->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::Medium)
268*05767d91SRobert Wu                ->setFormat(oboe::AudioFormat::Float)
269*05767d91SRobert Wu                ->setDataCallback(this)
270*05767d91SRobert Wu                ->openStream(mStream);
271*05767d91SRobert Wu	if (result != Result::OK) return (int32_t) result;
272*05767d91SRobert Wu
273*05767d91SRobert Wu        // Typically, start the stream after querying some stream information, as well as some input from the user
274*05767d91SRobert Wu        result = outStream->requestStart();
275*05767d91SRobert Wu	return (int32_t) result;
276*05767d91SRobert Wu    }
277*05767d91SRobert Wu
278*05767d91SRobert Wu    // Call this from Activity onPause()
279*05767d91SRobert Wu    void stopAudio() {
280*05767d91SRobert Wu        // Stop, close and delete in case not already closed.
281*05767d91SRobert Wu        std::lock_guard<std::mutex> lock(mLock);
282*05767d91SRobert Wu        if (mStream) {
283*05767d91SRobert Wu            mStream->stop();
284*05767d91SRobert Wu            mStream->close();
285*05767d91SRobert Wu            mStream.reset();
286*05767d91SRobert Wu        }
287*05767d91SRobert Wu    }
288*05767d91SRobert Wu
289*05767d91SRobert Wu    oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) override {
290*05767d91SRobert Wu        float *floatData = (float *) audioData;
291*05767d91SRobert Wu        for (int i = 0; i < numFrames; ++i) {
292*05767d91SRobert Wu            float sampleValue = kAmplitude * sinf(mPhase);
293*05767d91SRobert Wu            for (int j = 0; j < kChannelCount; j++) {
294*05767d91SRobert Wu                floatData[i * kChannelCount + j] = sampleValue;
295*05767d91SRobert Wu            }
296*05767d91SRobert Wu            mPhase += mPhaseIncrement;
297*05767d91SRobert Wu            if (mPhase >= kTwoPi) mPhase -= kTwoPi;
298*05767d91SRobert Wu        }
299*05767d91SRobert Wu        return oboe::DataCallbackResult::Continue;
300*05767d91SRobert Wu    }
301*05767d91SRobert Wu
302*05767d91SRobert Wuprivate:
303*05767d91SRobert Wu    std::mutex         mLock;
304*05767d91SRobert Wu    std::shared_ptr<oboe::AudioStream> mStream;
305*05767d91SRobert Wu
306*05767d91SRobert Wu    // Stream params
307*05767d91SRobert Wu    static int constexpr kChannelCount = 2;
308*05767d91SRobert Wu    static int constexpr kSampleRate = 48000;
309*05767d91SRobert Wu    // Wave params, these could be instance variables in order to modify at runtime
310*05767d91SRobert Wu    static float constexpr kAmplitude = 0.5f;
311*05767d91SRobert Wu    static float constexpr kFrequency = 440;
312*05767d91SRobert Wu    static float constexpr kPI = M_PI;
313*05767d91SRobert Wu    static float constexpr kTwoPi = kPI * 2;
314*05767d91SRobert Wu    static double constexpr mPhaseIncrement = kFrequency * kTwoPi / (double) kSampleRate;
315*05767d91SRobert Wu    // Keeps track of where the wave is
316*05767d91SRobert Wu    float mPhase = 0.0;
317*05767d91SRobert Wu};
318*05767d91SRobert Wu```
319*05767d91SRobert WuNote that this implementation computes sine values at run-time for simplicity,
320*05767d91SRobert Wurather than pre-computing them.
321*05767d91SRobert WuAdditionally, best practice is to implement a separate data callback class, rather
322*05767d91SRobert Wuthan managing the stream and defining its data callback in the same class.
323*05767d91SRobert Wu
324*05767d91SRobert WuFor more examples on how to use Oboe look in the [samples](https://github.com/google/oboe/tree/main/samples) folder.
325*05767d91SRobert Wu
326*05767d91SRobert Wu## Obtaining optimal latency
327*05767d91SRobert WuOne of the goals of the Oboe library is to provide low latency audio streams on the widest range of hardware configurations.
328*05767d91SRobert WuWhen a stream is opened using AAudio, the optimal rate will be chosen unless the app requests a specific rate. The framesPerBurst is also provided by AAudio.
329*05767d91SRobert Wu
330*05767d91SRobert WuBut OpenSL ES cannot determine those values. So applications should query them using Java and then pass them to Oboe. They will be used for OpenSL ES streams on older devices.
331*05767d91SRobert Wu
332*05767d91SRobert WuHere's a code sample showing how to set these default values.
333*05767d91SRobert Wu
334*05767d91SRobert Wu*MainActivity.java*
335*05767d91SRobert Wu
336*05767d91SRobert Wu    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){
337*05767d91SRobert Wu        AudioManager myAudioMgr = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
338*05767d91SRobert Wu        String sampleRateStr = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
339*05767d91SRobert Wu	    int defaultSampleRate = Integer.parseInt(sampleRateStr);
340*05767d91SRobert Wu	    String framesPerBurstStr = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
341*05767d91SRobert Wu	    int defaultFramesPerBurst = Integer.parseInt(framesPerBurstStr);
342*05767d91SRobert Wu
343*05767d91SRobert Wu	    native_setDefaultStreamValues(defaultSampleRate, defaultFramesPerBurst);
344*05767d91SRobert Wu	}
345*05767d91SRobert Wu
346*05767d91SRobert Wu*jni-bridge.cpp*
347*05767d91SRobert Wu
348*05767d91SRobert Wu	JNIEXPORT void JNICALL
349*05767d91SRobert Wu	Java_com_google_sample_oboe_hellooboe_MainActivity_native_1setDefaultStreamValues(JNIEnv *env,
350*05767d91SRobert Wu	                                                                                  jclass type,
351*05767d91SRobert Wu	                                                                                  jint sampleRate,
352*05767d91SRobert Wu	                                                                                  jint framesPerBurst) {
353*05767d91SRobert Wu	    oboe::DefaultStreamValues::SampleRate = (int32_t) sampleRate;
354*05767d91SRobert Wu	    oboe::DefaultStreamValues::FramesPerBurst = (int32_t) framesPerBurst;
355*05767d91SRobert Wu	}
356*05767d91SRobert Wu
357*05767d91SRobert WuNote that the values from Java are for built-in audio devices. Peripheral devices, such as Bluetooth may need larger framesPerBurst.
358*05767d91SRobert Wu
359*05767d91SRobert Wu# Further information
360*05767d91SRobert Wu- [Code samples](https://github.com/google/oboe/tree/main/samples)
361*05767d91SRobert Wu- [Full guide to Oboe](FullGuide.md)
362