blob: 9b81f89f19708dd9d81fa70c5b6c2aa82220a2b1 [file] [log] [blame]
Phil Burk0433d8f2018-11-21 16:41:25 -08001/*
2 * Copyright 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef NATIVEOBOE_NATIVEAUDIOCONTEXT_H
18#define NATIVEOBOE_NATIVEAUDIOCONTEXT_H
19
20#include <dlfcn.h>
Phil Burk0817a2b2019-01-03 14:50:18 -080021#include <jni.h>
Phil Burk0433d8f2018-11-21 16:41:25 -080022#include <thread>
Phil Burk21de29d2019-04-03 12:06:30 -070023#include <unordered_map>
Phil Burke5985ed2018-12-06 11:38:30 -080024#include <vector>
Phil Burk0433d8f2018-11-21 16:41:25 -080025
26#include "common/OboeDebug.h"
27#include "oboe/Oboe.h"
28
29#include "AudioStreamGateway.h"
Phil Burk84e7e652019-05-13 16:29:15 -070030#include "flowunits/ImpulseOscillator.h"
Phil Burk0817a2b2019-01-03 14:50:18 -080031#include "flowgraph/ManyToMultiConverter.h"
32#include "flowgraph/MonoToMultiConverter.h"
33#include "flowgraph/SinkFloat.h"
34#include "flowgraph/SinkI16.h"
Phil Burk0a784e62019-07-20 12:43:15 -070035#include "flowunits/ExponentialShape.h"
36#include "flowunits/LinearShape.h"
Phil Burk84e7e652019-05-13 16:29:15 -070037#include "flowunits/SineOscillator.h"
38#include "flowunits/SawtoothOscillator.h"
Phil Burk7e601f32019-03-08 16:04:43 -080039
40#include "FullDuplexEcho.h"
Phil Burk7386a832019-03-21 16:07:27 -070041#include "FullDuplexGlitches.h"
Phil Burk80d83d82019-03-15 12:03:37 -070042#include "FullDuplexLatency.h"
Phil Burk7e601f32019-03-08 16:04:43 -080043#include "FullDuplexStream.h"
Phil Burk0433d8f2018-11-21 16:41:25 -080044#include "InputStreamCallbackAnalyzer.h"
Phil Burk0433d8f2018-11-21 16:41:25 -080045#include "MultiChannelRecording.h"
46#include "OboeStreamCallbackProxy.h"
47#include "PlayRecordingCallback.h"
48#include "SawPingGenerator.h"
Phil Burk0a784e62019-07-20 12:43:15 -070049#include "flowunits/TriangleOscillator.h"
Phil Burk0433d8f2018-11-21 16:41:25 -080050
Phil Burk6c16ce92019-03-05 16:07:38 -080051// These must match order in strings.xml and in StreamConfiguration.java
52#define NATIVE_MODE_UNSPECIFIED 0
53#define NATIVE_MODE_OPENSLES 1
54#define NATIVE_MODE_AAUDIO 2
55
Phil Burke5985ed2018-12-06 11:38:30 -080056#define MAX_SINE_OSCILLATORS 8
Phil Burk0433d8f2018-11-21 16:41:25 -080057#define AMPLITUDE_SINE 1.0
Phil Burk0817a2b2019-01-03 14:50:18 -080058#define AMPLITUDE_SAWTOOTH 0.5
Phil Burke5985ed2018-12-06 11:38:30 -080059#define FREQUENCY_SAW_PING 800.0
Phil Burk0817a2b2019-01-03 14:50:18 -080060#define AMPLITUDE_SAW_PING 0.8
Phil Burk0433d8f2018-11-21 16:41:25 -080061#define AMPLITUDE_IMPULSE 0.7
62
63#define NANOS_PER_MICROSECOND ((int64_t) 1000)
64#define NANOS_PER_MILLISECOND (1000 * NANOS_PER_MICROSECOND)
65#define NANOS_PER_SECOND (1000 * NANOS_PER_MILLISECOND)
66
67#define LIB_AAUDIO_NAME "libaaudio.so"
68#define FUNCTION_IS_MMAP "AAudioStream_isMMapUsed"
Phil Burk2beb2c72019-09-05 18:51:14 -070069#define FUNCTION_SET_MMAP_POLICY "AAudio_setMMapPolicy"
70#define FUNCTION_GET_MMAP_POLICY "AAudio_getMMapPolicy"
Phil Burk0433d8f2018-11-21 16:41:25 -080071
Phil Burk81ca4742019-04-24 07:53:36 -070072#define SECONDS_TO_RECORD 10
73
Phil Burkecdc4c82019-03-28 19:07:24 -070074typedef struct AAudioStreamStruct AAudioStream;
75
Phil Burk0433d8f2018-11-21 16:41:25 -080076/**
Phil Burk2beb2c72019-09-05 18:51:14 -070077 * Call some AAudio test routines that are not part of the normal API.
78 */
79class AAudioExtensions {
80public:
81 static AAudioExtensions &getInstance() {
82 static AAudioExtensions instance;
83 return instance;
84 }
85
86 bool isMMapUsed(oboe::AudioStream *oboeStream) {
87 if (!loadLibrary()) return false;
88 AAudioStream *aaudioStream = (AAudioStream *) oboeStream->getUnderlyingStream();
89 return mAAudioStream_isMMap(aaudioStream);
90 }
91
92 bool setMMapEnabled(bool enabled) {
93 if (!loadLibrary()) return false;
94 return mAAudio_setMMapPolicy(enabled ? AAUDIO_POLICY_AUTO : AAUDIO_POLICY_NEVER);
95 }
96
97 bool isMMapEnabled() {
98 if (!loadLibrary()) return false;
99 return mAAudio_getMMapPolicy() != AAUDIO_POLICY_NEVER;
100 }
101
102 bool isMMapSupported() {
103 if (!loadLibrary()) return false;
104 return mMMapSupported;
105 }
106
107private:
108
109 enum {
110 AAUDIO_POLICY_NEVER = 1,
111 AAUDIO_POLICY_AUTO,
112 AAUDIO_POLICY_ALWAYS
113 };
114 typedef int32_t aaudio_policy_t;
115
116 // return true if it succeeds
117 bool loadLibrary() {
118 if (mFirstTime) {
119 mFirstTime = false;
120 mLibHandle = dlopen(LIB_AAUDIO_NAME, 0);
121 if (mLibHandle == nullptr) {
122 LOGI("%s() could not find "
123 LIB_AAUDIO_NAME, __func__);
124 return false;
125 }
126
127 mAAudioStream_isMMap = (bool (*)(AAudioStream *stream))
128 dlsym(mLibHandle, FUNCTION_IS_MMAP);
129
130 if (mAAudioStream_isMMap == nullptr) {
131 LOGI("%s() could not find "
132 FUNCTION_IS_MMAP, __func__);
133 return false;
134 }
135
136 mAAudio_setMMapPolicy = (int32_t (*)(aaudio_policy_t policy))
137 dlsym(mLibHandle, FUNCTION_SET_MMAP_POLICY);
138
139 if (mAAudio_setMMapPolicy == nullptr) {
140 LOGI("%s() could not find "
141 FUNCTION_SET_MMAP_POLICY, __func__);
142 return false;
143 }
144
145 mAAudio_getMMapPolicy = (aaudio_policy_t (*)())
146 dlsym(mLibHandle, FUNCTION_GET_MMAP_POLICY);
147
148 if (mAAudio_getMMapPolicy == nullptr) {
149 LOGI("%s() could not find "
150 FUNCTION_GET_MMAP_POLICY, __func__);
151 return false;
152 }
153
154 mMMapSupported = isMMapEnabled(); // still supported even if disabled later
155 }
156 return true;
157 }
158
159 bool mFirstTime = true;
160 void *mLibHandle = nullptr;
161 bool (*mAAudioStream_isMMap)(AAudioStream *stream) = nullptr;
162 int32_t (*mAAudio_setMMapPolicy)(aaudio_policy_t policy) = nullptr;
163 aaudio_policy_t (*mAAudio_getMMapPolicy)() = nullptr;
164 bool mMMapSupported = false;
165};
166
167/**
Phil Burk0af43bb2019-03-12 14:11:38 -0700168 * Abstract base class that corresponds to a test at the Java level.
Phil Burk0433d8f2018-11-21 16:41:25 -0800169 */
Phil Burk0af43bb2019-03-12 14:11:38 -0700170class ActivityContext {
Phil Burk0433d8f2018-11-21 16:41:25 -0800171public:
172
Phil Burk0af43bb2019-03-12 14:11:38 -0700173 ActivityContext() {}
174 virtual ~ActivityContext() = default;
Phil Burk0433d8f2018-11-21 16:41:25 -0800175
Phil Burk6c16ce92019-03-05 16:07:38 -0800176 oboe::AudioStream *getStream(int32_t streamIndex) {
Phil Burk21de29d2019-04-03 12:06:30 -0700177 auto it = mOboeStreams.find(streamIndex);
178 if (it != mOboeStreams.end()) {
179 return it->second;
180 } else {
181 return nullptr;
182 }
Phil Burk6c16ce92019-03-05 16:07:38 -0800183 }
184
Phil Burk0af43bb2019-03-12 14:11:38 -0700185 virtual void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder);
186
Phil Burk6c16ce92019-03-05 16:07:38 -0800187 int open(jint nativeApi,
188 jint sampleRate,
Phil Burk0433d8f2018-11-21 16:41:25 -0800189 jint channelCount,
190 jint format,
191 jint sharingMode,
192 jint performanceMode,
Phil Burkcd03b992019-09-20 10:28:20 +0900193 jint inputPreset,
Phil Burk0433d8f2018-11-21 16:41:25 -0800194 jint deviceId,
195 jint sessionId,
Phil Burk0af43bb2019-03-12 14:11:38 -0700196 jint framesPerBurst,
Phil Burk301b0662019-06-06 11:36:30 -0700197 jboolean channelConversionAllowed,
Phil Burk59273982019-08-29 09:10:37 -0700198 jboolean formatConversionAllowed,
Phil Burk301b0662019-06-06 11:36:30 -0700199 jint rateConversionQuality,
Phil Burk2beb2c72019-09-05 18:51:14 -0700200 jboolean isMMap,
Phil Burk0af43bb2019-03-12 14:11:38 -0700201 jboolean isInput);
Phil Burk0433d8f2018-11-21 16:41:25 -0800202
Phil Burk0433d8f2018-11-21 16:41:25 -0800203
Phil Burk0af43bb2019-03-12 14:11:38 -0700204 virtual void close(int32_t streamIndex);
Phil Burk0433d8f2018-11-21 16:41:25 -0800205
206 void printScheduler() {
Glenn Kasten91dec2d2019-04-09 16:17:59 -0700207#if OBOE_ENABLE_LOGGING
Phil Burkd7151632019-03-09 09:37:24 -0800208 int scheduler = audioStreamGateway.getScheduler();
Glenn Kasten91dec2d2019-04-09 16:17:59 -0700209#endif
Phil Burkd7151632019-03-09 09:37:24 -0800210 LOGI("scheduler = 0x%08x, SCHED_FIFO = 0x%08X\n", scheduler, SCHED_FIFO);
Phil Burk0433d8f2018-11-21 16:41:25 -0800211 }
212
Phil Burk0af43bb2019-03-12 14:11:38 -0700213 virtual void configureForStart() {}
214
215 oboe::Result start();
216
217 oboe::Result pause();
218
219 oboe::Result stopAllStreams();
220
221 virtual oboe::Result stop() {
222 return stopAllStreams();
Phil Burk0433d8f2018-11-21 16:41:25 -0800223 }
224
Phil Burk0af43bb2019-03-12 14:11:38 -0700225 virtual void setAmplitude(double amplitude) {}
Phil Burk0433d8f2018-11-21 16:41:25 -0800226
Phil Burk0af43bb2019-03-12 14:11:38 -0700227 virtual oboe::Result startPlayback() {
228 return oboe::Result::OK;
Phil Burk0433d8f2018-11-21 16:41:25 -0800229 }
230
Phil Burk0af43bb2019-03-12 14:11:38 -0700231 virtual oboe::Result stopPlayback() {
232 return oboe::Result::OK;
Phil Burk0433d8f2018-11-21 16:41:25 -0800233 }
234
Phil Burk0af43bb2019-03-12 14:11:38 -0700235 virtual void runBlockingIO() {};
Phil Burk0433d8f2018-11-21 16:41:25 -0800236
Phil Burk0af43bb2019-03-12 14:11:38 -0700237 static void threadCallback(ActivityContext *context) {
Phil Burk0433d8f2018-11-21 16:41:25 -0800238 LOGD("%s: called", __func__);
239 context->runBlockingIO();
240 LOGD("%s: exiting", __func__);
241 }
242
Phil Burk0af43bb2019-03-12 14:11:38 -0700243 void stopBlockingIOThread() {
244 if (dataThread != nullptr) {
245 // stop a thread that runs in place of the callback
246 threadEnabled.store(false); // ask thread to exit its loop
247 dataThread->join();
248 dataThread = nullptr;
Phil Burke5985ed2018-12-06 11:38:30 -0800249 }
Phil Burk0433d8f2018-11-21 16:41:25 -0800250 }
251
Phil Burk0af43bb2019-03-12 14:11:38 -0700252 virtual double getPeakLevel(int index) {
253 return 0.0;
254 }
255
256 virtual void setEnabled(bool enabled) {
257 }
258
259 bool isMMapUsed(int32_t streamIndex);
260
261 int32_t getFramesPerBlock() {
262 return (callbackSize == 0) ? mFramesPerBurst : callbackSize;
Phil Burk6fb1d802018-12-21 15:28:07 -0800263 }
264
265 int64_t getCallbackCount() {
266 return oboeCallbackProxy.getCallbackCount();
267 }
268
Phil Burk0af43bb2019-03-12 14:11:38 -0700269 virtual void setChannelEnabled(int channelIndex, bool enabled) {}
Phil Burk03bdc0a2019-03-06 15:56:25 -0800270
Phil Burk0a784e62019-07-20 12:43:15 -0700271 virtual void setSignalType(int signalType) {}
272
Phil Burk9f3a33f2019-04-17 16:03:14 -0700273 virtual int32_t saveWaveFile(const char *filename);
Phil Burk327361c2019-04-13 14:45:27 -0700274
Phil Burkbbde5bb2019-09-02 16:00:18 -0700275 virtual void setMinimumFramesBeforeRead(int32_t numFrames) {}
276
Phil Burkbd76d6a2019-06-01 08:48:03 -0700277 static bool mUseCallback;
Phil Burk0af43bb2019-03-12 14:11:38 -0700278 static int callbackSize;
279
Phil Burk0af43bb2019-03-12 14:11:38 -0700280protected:
Phil Burk9f3a33f2019-04-17 16:03:14 -0700281 oboe::AudioStream *getInputStream();
282 oboe::AudioStream *getOutputStream();
Phil Burk0af43bb2019-03-12 14:11:38 -0700283 int32_t allocateStreamIndex();
284 void freeStreamIndex(int32_t streamIndex);
285
Phil Burk81ca4742019-04-24 07:53:36 -0700286 virtual void createRecording() {
287 mRecording = std::make_unique<MultiChannelRecording>(mChannelCount,
288 SECONDS_TO_RECORD * mSampleRate);
289 }
290
Phil Burk0af43bb2019-03-12 14:11:38 -0700291 virtual void finishOpen(bool isInput, oboe::AudioStream *oboeStream) {}
292
293 virtual oboe::Result startStreams() = 0;
294
295 std::unique_ptr<float []> dataBuffer{};
296
297 AudioStreamGateway audioStreamGateway;
298 OboeStreamCallbackProxy oboeCallbackProxy;
299
Phil Burk9f3a33f2019-04-17 16:03:14 -0700300 std::unique_ptr<MultiChannelRecording> mRecording{};
301
Phil Burk21de29d2019-04-03 12:06:30 -0700302 int32_t mNextStreamHandle = 0;
303 std::unordered_map<int32_t, oboe::AudioStream *> mOboeStreams;
Phil Burk0af43bb2019-03-12 14:11:38 -0700304 int32_t mFramesPerBurst = 0; // TODO per stream
305 int32_t mChannelCount = 0; // TODO per stream
306 int32_t mSampleRate = 0; // TODO per stream
307
308 std::atomic<bool> threadEnabled{false};
309 std::thread *dataThread = nullptr;
310
Phil Burk0af43bb2019-03-12 14:11:38 -0700311private:
312};
313
314/**
315 * Test a single input stream.
316 */
317class ActivityTestInput : public ActivityContext {
318public:
319
320 ActivityTestInput() {}
321 virtual ~ActivityTestInput() = default;
322
323 void configureForStart() override;
324
325 double getPeakLevel(int index) override {
Phil Burkd7151632019-03-09 09:37:24 -0800326 return mInputAnalyzer.getPeakLevel(index);
327 }
328
Phil Burk0af43bb2019-03-12 14:11:38 -0700329 void runBlockingIO() override;
330
Phil Burk0af43bb2019-03-12 14:11:38 -0700331 InputStreamCallbackAnalyzer mInputAnalyzer;
332
Phil Burkbbde5bb2019-09-02 16:00:18 -0700333 void setMinimumFramesBeforeRead(int32_t numFrames) override {
334 mInputAnalyzer.setMinimumFramesBeforeRead(numFrames);
335 mMinimumFramesBeforeRead = numFrames;
336 }
337
338 int32_t getMinimumFramesBeforeRead() const {
339 return mMinimumFramesBeforeRead;
340 }
341
Phil Burk0af43bb2019-03-12 14:11:38 -0700342protected:
Phil Burkbbde5bb2019-09-02 16:00:18 -0700343
Phil Burk0af43bb2019-03-12 14:11:38 -0700344 oboe::Result startStreams() override {
Phil Burkd3d015e2019-08-26 13:32:45 -0700345 mInputAnalyzer.reset();
Phil Burk0af43bb2019-03-12 14:11:38 -0700346 return getInputStream()->requestStart();
347 }
Phil Burk0433d8f2018-11-21 16:41:25 -0800348
Phil Burkbbde5bb2019-09-02 16:00:18 -0700349 int32_t mMinimumFramesBeforeRead = 0;
Phil Burk0af43bb2019-03-12 14:11:38 -0700350};
351
352/**
353 * Record a configured input stream and play it back some simple way.
354 */
355class ActivityRecording : public ActivityTestInput {
356public:
357
358 ActivityRecording() {}
359 virtual ~ActivityRecording() = default;
360
361 oboe::Result stop() override {
362
363 oboe::Result resultStopPlayback = stopPlayback();
364 oboe::Result resultStopAudio = ActivityContext::stop();
365
Phil Burkbd76d6a2019-06-01 08:48:03 -0700366 return (resultStopPlayback != oboe::Result::OK) ? resultStopPlayback : resultStopAudio;
Phil Burk0af43bb2019-03-12 14:11:38 -0700367 }
368
369 oboe::Result startPlayback() override;
370
371 oboe::Result stopPlayback() override;
372
373 PlayRecordingCallback mPlayRecordingCallback;
374 oboe::AudioStream *playbackStream = nullptr;
375
376};
377
378/**
379 * Test a single output stream.
380 */
381class ActivityTestOutput : public ActivityContext {
382public:
383 ActivityTestOutput()
384 : sineOscillators(MAX_SINE_OSCILLATORS)
385 , sawtoothOscillators(MAX_SINE_OSCILLATORS) {}
386
387 virtual ~ActivityTestOutput() = default;
388
389 void close(int32_t streamIndex) override;
390
391 oboe::Result startStreams() override {
Phil Burk3873e882019-03-18 10:15:13 -0700392 return getOutputStream()->start();
Phil Burk0af43bb2019-03-12 14:11:38 -0700393 }
394
395 void configureForStart() override;
396
397 virtual void configureStreamGateway();
398
399 void runBlockingIO() override;
400
401 void setAmplitude(double amplitude) override {
402 LOGD("%s(%f)", __func__, amplitude);
403 for (int i = 0; i < mChannelCount; i++) {
404 sineOscillators[i].amplitude.setValue(amplitude);
405 sawtoothOscillators[i].amplitude.setValue(amplitude);
406 }
407 impulseGenerator.amplitude.setValue(amplitude);
408 }
409
410 void setChannelEnabled(int channelIndex, bool enabled) override;
Phil Burk0433d8f2018-11-21 16:41:25 -0800411
412 // WARNING - must match order in strings.xml and OboeAudioOutputStream.java
Phil Burk0a784e62019-07-20 12:43:15 -0700413 enum SignalType {
414 Sine = 0,
415 Sawtooth = 1,
416 FreqSweep = 2,
417 PitchSweep = 3,
418 WhiteNoise = 4
Phil Burk0433d8f2018-11-21 16:41:25 -0800419 };
420
Phil Burk0a784e62019-07-20 12:43:15 -0700421 void setSignalType(int signalType) override {
422 mSignalType = (SignalType) signalType;
423 }
Phil Burk0af43bb2019-03-12 14:11:38 -0700424
Phil Burk0a784e62019-07-20 12:43:15 -0700425protected:
426 SignalType mSignalType = SignalType::Sine;
427
428 std::vector<SineOscillator> sineOscillators;
429 std::vector<SawtoothOscillator> sawtoothOscillators;
430 ImpulseOscillator impulseGenerator;
431 static constexpr float kSweepPeriod = 10.0; // for triangle up and down
432
433 // A triangle LFO is shaped into either a linear or an exponential range.
434 TriangleOscillator mTriangleOscillator;
435 LinearShape mLinearShape;
436 ExponentialShape mExponentialShape;
Phil Burk0af43bb2019-03-12 14:11:38 -0700437
438 std::unique_ptr<ManyToMultiConverter> manyToMulti;
439 std::unique_ptr<MonoToMultiConverter> monoToMulti;
440 std::shared_ptr<flowgraph::SinkFloat> mSinkFloat;
441 std::shared_ptr<flowgraph::SinkI16> mSinkI16;
442};
443
444/**
445 * Generate a short beep with a very short attack.
446 * This is used by Java to measure output latency.
447 */
448class ActivityTapToTone : public ActivityTestOutput {
449public:
450 ActivityTapToTone() {}
451 virtual ~ActivityTapToTone() = default;
452
453 void configureForStart() override;
454
455 void setAmplitude(double amplitude) override {
456 LOGD("%s(%f)", __func__, amplitude);
457 ActivityTestOutput::setAmplitude(amplitude);
458 sawPingGenerator.amplitude.setValue(amplitude);
459 }
460
461 virtual void setEnabled(bool enabled) override {
462 sawPingGenerator.setEnabled(enabled);
463 }
464
465 SawPingGenerator sawPingGenerator;
466};
467
468/**
Phil Burk57a35eb2019-07-31 10:46:18 -0700469 * Activity that uses synchronized input/output streams.
Phil Burk0af43bb2019-03-12 14:11:38 -0700470 */
Phil Burk42c9f8a2019-03-20 14:19:30 -0700471class ActivityFullDuplex : public ActivityContext {
472public:
473
474 void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) override;
475
Phil Burk7386a832019-03-21 16:07:27 -0700476 virtual int32_t getState() { return -1; }
477 virtual int32_t getResult() { return -1; }
478 virtual bool isAnalyzerDone() { return false; }
Phil Burkcd818322019-03-22 16:51:40 -0700479
Phil Burkbbde5bb2019-09-02 16:00:18 -0700480 void setMinimumFramesBeforeRead(int32_t numFrames) override {
481 getFullDuplexAnalyzer()->setMinimumFramesBeforeRead(numFrames);
482 }
483
Phil Burkcd818322019-03-22 16:51:40 -0700484 virtual FullDuplexAnalyzer *getFullDuplexAnalyzer() = 0;
485
486 int32_t getResetCount() {
487 return getFullDuplexAnalyzer()->getLoopbackProcessor()->getResetCount();
488 }
Phil Burk81ca4742019-04-24 07:53:36 -0700489
490protected:
491 void createRecording() override {
492 mRecording = std::make_unique<MultiChannelRecording>(2, // output and input
493 SECONDS_TO_RECORD * mSampleRate);
494 }
Phil Burk42c9f8a2019-03-20 14:19:30 -0700495};
496
497/**
498 * Echo input to output through a delay line.
499 */
500class ActivityEcho : public ActivityFullDuplex {
Phil Burk0af43bb2019-03-12 14:11:38 -0700501public:
502
503 oboe::Result startStreams() override {
504 return mFullDuplexEcho->start();
505 }
506
507 void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) override;
508
Phil Burk1d17a602019-03-12 15:37:56 -0700509 void setDelayTime(double delayTimeSeconds) {
510 if (mFullDuplexEcho) {
511 mFullDuplexEcho->setDelayTime(delayTimeSeconds);
512 }
513 }
514
Phil Burka556a322019-10-24 15:43:18 -0700515 FullDuplexAnalyzer *getFullDuplexAnalyzer() override {
Phil Burkcd818322019-03-22 16:51:40 -0700516 return (FullDuplexAnalyzer *) mFullDuplexEcho.get();
517 }
518
Phil Burk0af43bb2019-03-12 14:11:38 -0700519protected:
520 void finishOpen(bool isInput, oboe::AudioStream *oboeStream) override;
521
522private:
523 std::unique_ptr<FullDuplexEcho> mFullDuplexEcho{};
524};
525
526/**
Phil Burk80d83d82019-03-15 12:03:37 -0700527 * Measure Round Trip Latency
528 */
Phil Burk42c9f8a2019-03-20 14:19:30 -0700529class ActivityRoundTripLatency : public ActivityFullDuplex {
Phil Burk80d83d82019-03-15 12:03:37 -0700530public:
531
532 oboe::Result startStreams() override {
533 return mFullDuplexLatency->start();
534 }
535
536 void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) override;
537
Phil Burkd2dd5272019-03-18 16:05:25 -0700538 LatencyAnalyzer *getLatencyAnalyzer() {
539 return mFullDuplexLatency->getLatencyAnalyzer();
Phil Burk80d83d82019-03-15 12:03:37 -0700540 }
541
Phil Burk7386a832019-03-21 16:07:27 -0700542 int32_t getState() override {
543 return getLatencyAnalyzer()->getState();
544 }
545 int32_t getResult() override {
546 return getLatencyAnalyzer()->getState();
547 }
548 bool isAnalyzerDone() override {
Phil Burk80d83d82019-03-15 12:03:37 -0700549 return mFullDuplexLatency->isDone();
550 }
551
Phil Burkcd818322019-03-22 16:51:40 -0700552 FullDuplexAnalyzer *getFullDuplexAnalyzer() override {
553 return (FullDuplexAnalyzer *) mFullDuplexLatency.get();
554 }
555
Phil Burk80d83d82019-03-15 12:03:37 -0700556protected:
557 void finishOpen(bool isInput, oboe::AudioStream *oboeStream) override;
558
559private:
560 std::unique_ptr<FullDuplexLatency> mFullDuplexLatency{};
561};
562
563/**
Phil Burk7386a832019-03-21 16:07:27 -0700564 * Measure Glitches
565 */
566class ActivityGlitches : public ActivityFullDuplex {
567public:
568
569 oboe::Result startStreams() override {
570 return mFullDuplexGlitches->start();
571 }
572
573 void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) override;
574
575 GlitchAnalyzer *getGlitchAnalyzer() {
Phil Burkaf0c19f2019-09-22 17:18:23 +0800576 if (!mFullDuplexGlitches) return nullptr;
Phil Burk7386a832019-03-21 16:07:27 -0700577 return mFullDuplexGlitches->getGlitchAnalyzer();
578 }
579
580 int32_t getState() override {
581 return getGlitchAnalyzer()->getState();
582 }
583 int32_t getResult() override {
584 return getGlitchAnalyzer()->getResult();
585 }
586 bool isAnalyzerDone() override {
587 return mFullDuplexGlitches->isDone();
588 }
589
Phil Burkcd818322019-03-22 16:51:40 -0700590 FullDuplexAnalyzer *getFullDuplexAnalyzer() override {
591 return (FullDuplexAnalyzer *) mFullDuplexGlitches.get();
592 }
593
Phil Burk7386a832019-03-21 16:07:27 -0700594protected:
595 void finishOpen(bool isInput, oboe::AudioStream *oboeStream) override;
596
597private:
598 std::unique_ptr<FullDuplexGlitches> mFullDuplexGlitches{};
599};
600
601/**
Phil Burk06dfb462019-11-26 18:09:58 -0800602 * Test a single output stream.
603 */
604class ActivityTestDisconnect : public ActivityContext {
605public:
606 ActivityTestDisconnect() {}
607
608 virtual ~ActivityTestDisconnect() = default;
609
610 void close(int32_t streamIndex) override;
611
612 oboe::Result startStreams() override {
613 return getOutputStream()->start();
614 }
615
616 void configureForStart() override;
617
618private:
619 std::unique_ptr<SineOscillator> sineOscillator;
620 std::unique_ptr<MonoToMultiConverter> monoToMulti;
621 std::shared_ptr<flowgraph::SinkFloat> mSinkFloat;
622};
623
624/**
Phil Burk0af43bb2019-03-12 14:11:38 -0700625 * Switch between various
626 */
627class NativeAudioContext {
628public:
629
630 ActivityContext *getCurrentActivity() {
631 return currentActivity;
632 };
633
634 void setActivityType(int activityType) {
635 LOGD("%s(%d)", __func__, activityType);
636 mActivityType = (ActivityType) activityType;
637 switch(mActivityType) {
638 default:
639 case ActivityType::Undefined:
640 case ActivityType::TestOutput:
641 currentActivity = &mActivityTestOutput;
642 break;
643 case ActivityType::TestInput:
644 currentActivity = &mActivityTestInput;
645 break;
646 case ActivityType::TapToTone:
647 currentActivity = &mActivityTapToTone;
648 break;
649 case ActivityType::RecordPlay:
650 currentActivity = &mActivityRecording;
651 break;
652 case ActivityType::Echo:
653 currentActivity = &mActivityEcho;
654 break;
Phil Burk80d83d82019-03-15 12:03:37 -0700655 case ActivityType::RoundTripLatency:
656 currentActivity = &mActivityRoundTripLatency;
657 break;
Phil Burk7386a832019-03-21 16:07:27 -0700658 case ActivityType::Glitches:
659 currentActivity = &mActivityGlitches;
660 break;
Phil Burk06dfb462019-11-26 18:09:58 -0800661 case ActivityType::TestDisconnect:
662 currentActivity = &mActivityTestDisconnect;
663 break;
Phil Burk0af43bb2019-03-12 14:11:38 -0700664 }
665 }
666
Phil Burk1d17a602019-03-12 15:37:56 -0700667 void setDelayTime(double delayTimeMillis) {
668 mActivityEcho.setDelayTime(delayTimeMillis);
669 }
670
Phil Burk80d83d82019-03-15 12:03:37 -0700671 ActivityTestOutput mActivityTestOutput;
672 ActivityTestInput mActivityTestInput;
673 ActivityTapToTone mActivityTapToTone;
674 ActivityRecording mActivityRecording;
675 ActivityEcho mActivityEcho;
676 ActivityRoundTripLatency mActivityRoundTripLatency;
Phil Burk7386a832019-03-21 16:07:27 -0700677 ActivityGlitches mActivityGlitches;
Phil Burk06dfb462019-11-26 18:09:58 -0800678 ActivityTestDisconnect mActivityTestDisconnect;
Phil Burk80d83d82019-03-15 12:03:37 -0700679
Phil Burk0af43bb2019-03-12 14:11:38 -0700680private:
681
Phil Burk03bdc0a2019-03-06 15:56:25 -0800682 // WARNING - must match definitions in TestAudioActivity.java
683 enum ActivityType {
684 Undefined = -1,
685 TestOutput = 0,
686 TestInput = 1,
687 TapToTone = 2,
688 RecordPlay = 3,
Phil Burk80d83d82019-03-15 12:03:37 -0700689 Echo = 4,
690 RoundTripLatency = 5,
Phil Burk7386a832019-03-21 16:07:27 -0700691 Glitches = 6,
Phil Burk06dfb462019-11-26 18:09:58 -0800692 TestDisconnect = 7,
Phil Burk03bdc0a2019-03-06 15:56:25 -0800693 };
694
Phil Burk03bdc0a2019-03-06 15:56:25 -0800695 ActivityType mActivityType = ActivityType::Undefined;
Phil Burk0af43bb2019-03-12 14:11:38 -0700696 ActivityContext *currentActivity = &mActivityTestOutput;
Phil Burk0433d8f2018-11-21 16:41:25 -0800697
698};
699
700#endif //NATIVEOBOE_NATIVEAUDIOCONTEXT_H