1 /* 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 <jni.h> 21 #include <sys/system_properties.h> 22 #include <thread> 23 #include <unordered_map> 24 #include <vector> 25 26 #include "common/OboeDebug.h" 27 #include "oboe/Oboe.h" 28 29 #include "aaudio/AAudioExtensions.h" 30 #include "AudioStreamGateway.h" 31 32 #include "flowunits/ImpulseOscillator.h" 33 #include "flowgraph/ManyToMultiConverter.h" 34 #include "flowgraph/MonoToMultiConverter.h" 35 #include "flowgraph/SinkFloat.h" 36 #include "flowgraph/SinkI16.h" 37 #include "flowunits/ExponentialShape.h" 38 #include "flowunits/LinearShape.h" 39 #include "flowunits/SineOscillator.h" 40 #include "flowunits/SawtoothOscillator.h" 41 #include "flowunits/TriangleOscillator.h" 42 43 #include "FullDuplexAnalyzer.h" 44 #include "FullDuplexEcho.h" 45 #include "FullDuplexStream.h" 46 #include "analyzer/GlitchAnalyzer.h" 47 #include "analyzer/DataPathAnalyzer.h" 48 #include "InputStreamCallbackAnalyzer.h" 49 #include "MultiChannelRecording.h" 50 #include "OboeStreamCallbackProxy.h" 51 #include "PlayRecordingCallback.h" 52 #include "SawPingGenerator.h" 53 54 // These must match order in strings.xml and in StreamConfiguration.java 55 #define NATIVE_MODE_UNSPECIFIED 0 56 #define NATIVE_MODE_OPENSLES 1 57 #define NATIVE_MODE_AAUDIO 2 58 59 #define MAX_SINE_OSCILLATORS 8 60 #define AMPLITUDE_SINE 1.0 61 #define AMPLITUDE_SAWTOOTH 0.5 62 #define FREQUENCY_SAW_PING 800.0 63 #define AMPLITUDE_SAW_PING 0.8 64 #define AMPLITUDE_IMPULSE 0.7 65 66 #define NANOS_PER_MICROSECOND ((int64_t) 1000) 67 #define NANOS_PER_MILLISECOND (1000 * NANOS_PER_MICROSECOND) 68 #define NANOS_PER_SECOND (1000 * NANOS_PER_MILLISECOND) 69 70 #define SECONDS_TO_RECORD 10 71 72 /** 73 * Abstract base class that corresponds to a test at the Java level. 74 */ 75 class ActivityContext { 76 public: 77 ActivityContext()78 ActivityContext() {} 79 80 virtual ~ActivityContext() = default; 81 getStream(int32_t streamIndex)82 std::shared_ptr<oboe::AudioStream> getStream(int32_t streamIndex) { 83 auto it = mOboeStreams.find(streamIndex); 84 if (it != mOboeStreams.end()) { 85 return it->second; 86 } else { 87 return nullptr; 88 } 89 } 90 91 virtual void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder); 92 93 /** 94 * Open a stream with the given parameters. 95 * @param nativeApi 96 * @param sampleRate 97 * @param channelCount 98 * @param format 99 * @param sharingMode 100 * @param performanceMode 101 * @param inputPreset 102 * @param deviceId 103 * @param sessionId 104 * @param framesPerBurst 105 * @param channelConversionAllowed 106 * @param formatConversionAllowed 107 * @param rateConversionQuality 108 * @param isMMap 109 * @param isInput 110 * @return stream ID 111 */ 112 int open(jint nativeApi, 113 jint sampleRate, 114 jint channelCount, 115 jint format, 116 jint sharingMode, 117 jint performanceMode, 118 jint inputPreset, 119 jint deviceId, 120 jint sessionId, 121 jint framesPerBurst, 122 jboolean channelConversionAllowed, 123 jboolean formatConversionAllowed, 124 jint rateConversionQuality, 125 jboolean isMMap, 126 jboolean isInput); 127 128 virtual void close(int32_t streamIndex); 129 configureForStart()130 virtual void configureForStart() {} 131 132 oboe::Result start(); 133 134 oboe::Result pause(); 135 136 oboe::Result stopAllStreams(); 137 stop()138 virtual oboe::Result stop() { 139 return stopAllStreams(); 140 } 141 getCpuLoad()142 double getCpuLoad() { 143 return oboeCallbackProxy.getCpuLoad(); 144 } 145 setWorkload(double workload)146 void setWorkload(double workload) { 147 oboeCallbackProxy.setWorkload(workload); 148 } 149 startPlayback()150 virtual oboe::Result startPlayback() { 151 return oboe::Result::OK; 152 } 153 stopPlayback()154 virtual oboe::Result stopPlayback() { 155 return oboe::Result::OK; 156 } 157 runBlockingIO()158 virtual void runBlockingIO() {}; 159 threadCallback(ActivityContext * context)160 static void threadCallback(ActivityContext *context) { 161 context->runBlockingIO(); 162 } 163 stopBlockingIOThread()164 void stopBlockingIOThread() { 165 if (dataThread != nullptr) { 166 // stop a thread that runs in place of the callback 167 threadEnabled.store(false); // ask thread to exit its loop 168 dataThread->join(); 169 dataThread = nullptr; 170 } 171 } 172 getPeakLevel(int index)173 virtual double getPeakLevel(int index) { 174 return 0.0; 175 } 176 177 static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) { 178 struct timespec time; 179 int result = clock_gettime(clockId, &time); 180 if (result < 0) { 181 return result; 182 } 183 return (time.tv_sec * NANOS_PER_SECOND) + time.tv_nsec; 184 } 185 186 // Calculate time between beginning and when frame[0] occurred. calculateColdStartLatencyMillis(int32_t sampleRate,int64_t beginTimeNanos,int64_t timeStampPosition,int64_t timestampNanos)187 int32_t calculateColdStartLatencyMillis(int32_t sampleRate, 188 int64_t beginTimeNanos, 189 int64_t timeStampPosition, 190 int64_t timestampNanos) const { 191 int64_t elapsedNanos = NANOS_PER_SECOND * (timeStampPosition / (double) sampleRate); 192 int64_t timeOfFrameZero = timestampNanos - elapsedNanos; 193 int64_t coldStartLatencyNanos = timeOfFrameZero - beginTimeNanos; 194 return coldStartLatencyNanos / NANOS_PER_MILLISECOND; 195 } 196 getColdStartInputMillis()197 int32_t getColdStartInputMillis() { 198 std::shared_ptr<oboe::AudioStream> oboeStream = getInputStream(); 199 if (oboeStream != nullptr) { 200 int64_t framesRead = oboeStream->getFramesRead(); 201 if (framesRead > 0) { 202 // Base latency on the time that frame[0] would have been received by the app. 203 int64_t nowNanos = getNanoseconds(); 204 return calculateColdStartLatencyMillis(oboeStream->getSampleRate(), 205 mInputOpenedAt, 206 framesRead, 207 nowNanos); 208 } 209 } 210 return -1; 211 } 212 getColdStartOutputMillis()213 int32_t getColdStartOutputMillis() { 214 std::shared_ptr<oboe::AudioStream> oboeStream = getOutputStream(); 215 if (oboeStream != nullptr) { 216 auto result = oboeStream->getTimestamp(CLOCK_MONOTONIC); 217 if (result) { 218 auto frameTimestamp = result.value(); 219 // Calculate the time that frame[0] would have been played by the speaker. 220 int64_t position = frameTimestamp.position; 221 int64_t timestampNanos = frameTimestamp.timestamp; 222 return calculateColdStartLatencyMillis(oboeStream->getSampleRate(), 223 mOutputOpenedAt, 224 position, 225 timestampNanos); 226 } 227 } 228 return -1; 229 } 230 231 /** 232 * Trigger a sound or impulse. 233 * @param enabled 234 */ trigger()235 virtual void trigger() {} 236 237 bool isMMapUsed(int32_t streamIndex); 238 getFramesPerBlock()239 int32_t getFramesPerBlock() { 240 return (callbackSize == 0) ? mFramesPerBurst : callbackSize; 241 } 242 getCallbackCount()243 int64_t getCallbackCount() { 244 return oboeCallbackProxy.getCallbackCount(); 245 } 246 getLastErrorCallbackResult()247 oboe::Result getLastErrorCallbackResult() { 248 std::shared_ptr<oboe::AudioStream> stream = getOutputStream(); 249 if (stream == nullptr) { 250 stream = getInputStream(); 251 } 252 return stream ? oboe::Result::ErrorNull : stream->getLastErrorCallbackResult(); 253 } 254 getFramesPerCallback()255 int32_t getFramesPerCallback() { 256 return oboeCallbackProxy.getFramesPerCallback(); 257 } 258 setChannelEnabled(int channelIndex,bool enabled)259 virtual void setChannelEnabled(int channelIndex, bool enabled) {} 260 setSignalType(int signalType)261 virtual void setSignalType(int signalType) {} 262 263 virtual int32_t saveWaveFile(const char *filename); 264 setMinimumFramesBeforeRead(int32_t numFrames)265 virtual void setMinimumFramesBeforeRead(int32_t numFrames) {} 266 267 static bool mUseCallback; 268 static int callbackSize; 269 270 double getTimestampLatency(int32_t streamIndex); 271 272 protected: 273 std::shared_ptr<oboe::AudioStream> getInputStream(); 274 std::shared_ptr<oboe::AudioStream> getOutputStream(); 275 int32_t allocateStreamIndex(); 276 void freeStreamIndex(int32_t streamIndex); 277 createRecording()278 virtual void createRecording() { 279 mRecording = std::make_unique<MultiChannelRecording>(mChannelCount, 280 SECONDS_TO_RECORD * mSampleRate); 281 } 282 finishOpen(bool isInput,oboe::AudioStream * oboeStream)283 virtual void finishOpen(bool isInput, oboe::AudioStream *oboeStream) {} 284 285 virtual oboe::Result startStreams() = 0; 286 287 std::unique_ptr<float []> dataBuffer{}; 288 289 AudioStreamGateway audioStreamGateway; 290 OboeStreamCallbackProxy oboeCallbackProxy; 291 292 std::unique_ptr<MultiChannelRecording> mRecording{}; 293 294 int32_t mNextStreamHandle = 0; 295 std::unordered_map<int32_t, std::shared_ptr<oboe::AudioStream>> mOboeStreams; 296 int32_t mFramesPerBurst = 0; // TODO per stream 297 int32_t mChannelCount = 0; // TODO per stream 298 int32_t mSampleRate = 0; // TODO per stream 299 300 std::atomic<bool> threadEnabled{false}; 301 std::thread *dataThread = nullptr; 302 303 private: 304 int64_t mInputOpenedAt = 0; 305 int64_t mOutputOpenedAt = 0; 306 }; 307 308 /** 309 * Test a single input stream. 310 */ 311 class ActivityTestInput : public ActivityContext { 312 public: 313 ActivityTestInput()314 ActivityTestInput() {} 315 virtual ~ActivityTestInput() = default; 316 317 void configureForStart() override; 318 getPeakLevel(int index)319 double getPeakLevel(int index) override { 320 return mInputAnalyzer.getPeakLevel(index); 321 } 322 323 void runBlockingIO() override; 324 325 InputStreamCallbackAnalyzer mInputAnalyzer; 326 setMinimumFramesBeforeRead(int32_t numFrames)327 void setMinimumFramesBeforeRead(int32_t numFrames) override { 328 mInputAnalyzer.setMinimumFramesBeforeRead(numFrames); 329 mMinimumFramesBeforeRead = numFrames; 330 } 331 getMinimumFramesBeforeRead()332 int32_t getMinimumFramesBeforeRead() const { 333 return mMinimumFramesBeforeRead; 334 } 335 336 protected: 337 startStreams()338 oboe::Result startStreams() override { 339 mInputAnalyzer.reset(); 340 return getInputStream()->requestStart(); 341 } 342 343 int32_t mMinimumFramesBeforeRead = 0; 344 }; 345 346 /** 347 * Record a configured input stream and play it back some simple way. 348 */ 349 class ActivityRecording : public ActivityTestInput { 350 public: 351 ActivityRecording()352 ActivityRecording() {} 353 virtual ~ActivityRecording() = default; 354 stop()355 oboe::Result stop() override { 356 357 oboe::Result resultStopPlayback = stopPlayback(); 358 oboe::Result resultStopAudio = ActivityContext::stop(); 359 360 return (resultStopPlayback != oboe::Result::OK) ? resultStopPlayback : resultStopAudio; 361 } 362 363 oboe::Result startPlayback() override; 364 365 oboe::Result stopPlayback() override; 366 367 PlayRecordingCallback mPlayRecordingCallback; 368 oboe::AudioStream *playbackStream = nullptr; 369 370 }; 371 372 /** 373 * Test a single output stream. 374 */ 375 class ActivityTestOutput : public ActivityContext { 376 public: ActivityTestOutput()377 ActivityTestOutput() 378 : sineOscillators(MAX_SINE_OSCILLATORS) 379 , sawtoothOscillators(MAX_SINE_OSCILLATORS) {} 380 381 virtual ~ActivityTestOutput() = default; 382 383 void close(int32_t streamIndex) override; 384 startStreams()385 oboe::Result startStreams() override { 386 return getOutputStream()->start(); 387 } 388 389 void configureForStart() override; 390 391 virtual void configureStreamGateway(); 392 393 void runBlockingIO() override; 394 395 void setChannelEnabled(int channelIndex, bool enabled) override; 396 397 // WARNING - must match order in strings.xml and OboeAudioOutputStream.java 398 enum SignalType { 399 Sine = 0, 400 Sawtooth = 1, 401 FreqSweep = 2, 402 PitchSweep = 3, 403 WhiteNoise = 4 404 }; 405 setSignalType(int signalType)406 void setSignalType(int signalType) override { 407 mSignalType = (SignalType) signalType; 408 } 409 410 protected: 411 SignalType mSignalType = SignalType::Sine; 412 413 std::vector<SineOscillator> sineOscillators; 414 std::vector<SawtoothOscillator> sawtoothOscillators; 415 static constexpr float kSweepPeriod = 10.0; // for triangle up and down 416 417 // A triangle LFO is shaped into either a linear or an exponential range. 418 TriangleOscillator mTriangleOscillator; 419 LinearShape mLinearShape; 420 ExponentialShape mExponentialShape; 421 422 std::unique_ptr<ManyToMultiConverter> manyToMulti; 423 std::unique_ptr<MonoToMultiConverter> monoToMulti; 424 std::shared_ptr<oboe::flowgraph::SinkFloat> mSinkFloat; 425 std::shared_ptr<oboe::flowgraph::SinkI16> mSinkI16; 426 }; 427 428 /** 429 * Generate a short beep with a very short attack. 430 * This is used by Java to measure output latency. 431 */ 432 class ActivityTapToTone : public ActivityTestOutput { 433 public: ActivityTapToTone()434 ActivityTapToTone() {} 435 virtual ~ActivityTapToTone() = default; 436 437 void configureForStart() override; 438 trigger()439 virtual void trigger() override { 440 sawPingGenerator.trigger(); 441 } 442 443 SawPingGenerator sawPingGenerator; 444 }; 445 446 /** 447 * Activity that uses synchronized input/output streams. 448 */ 449 class ActivityFullDuplex : public ActivityContext { 450 public: 451 452 void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) override; 453 getState()454 virtual int32_t getState() { return -1; } getResult()455 virtual int32_t getResult() { return -1; } isAnalyzerDone()456 virtual bool isAnalyzerDone() { return false; } 457 setMinimumFramesBeforeRead(int32_t numFrames)458 void setMinimumFramesBeforeRead(int32_t numFrames) override { 459 getFullDuplexAnalyzer()->setMinimumFramesBeforeRead(numFrames); 460 } 461 462 virtual FullDuplexAnalyzer *getFullDuplexAnalyzer() = 0; 463 getResetCount()464 int32_t getResetCount() { 465 return getFullDuplexAnalyzer()->getLoopbackProcessor()->getResetCount(); 466 } 467 468 protected: createRecording()469 void createRecording() override { 470 mRecording = std::make_unique<MultiChannelRecording>(2, // output and input 471 SECONDS_TO_RECORD * mSampleRate); 472 } 473 }; 474 475 /** 476 * Echo input to output through a delay line. 477 */ 478 class ActivityEcho : public ActivityFullDuplex { 479 public: 480 startStreams()481 oboe::Result startStreams() override { 482 return mFullDuplexEcho->start(); 483 } 484 485 void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) override; 486 setDelayTime(double delayTimeSeconds)487 void setDelayTime(double delayTimeSeconds) { 488 if (mFullDuplexEcho) { 489 mFullDuplexEcho->setDelayTime(delayTimeSeconds); 490 } 491 } 492 getFullDuplexAnalyzer()493 FullDuplexAnalyzer *getFullDuplexAnalyzer() override { 494 return (FullDuplexAnalyzer *) mFullDuplexEcho.get(); 495 } 496 497 protected: 498 void finishOpen(bool isInput, oboe::AudioStream *oboeStream) override; 499 500 private: 501 std::unique_ptr<FullDuplexEcho> mFullDuplexEcho{}; 502 }; 503 504 /** 505 * Measure Round Trip Latency 506 */ 507 class ActivityRoundTripLatency : public ActivityFullDuplex { 508 public: 509 startStreams()510 oboe::Result startStreams() override { 511 mAnalyzerLaunched = false; 512 return mFullDuplexLatency->start(); 513 } 514 515 void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) override; 516 getLatencyAnalyzer()517 LatencyAnalyzer *getLatencyAnalyzer() { 518 return &mEchoAnalyzer; 519 } 520 getState()521 int32_t getState() override { 522 return getLatencyAnalyzer()->getState(); 523 } 524 getResult()525 int32_t getResult() override { 526 return getLatencyAnalyzer()->getState(); // TODO This does not look right. 527 } 528 isAnalyzerDone()529 bool isAnalyzerDone() override { 530 if (!mAnalyzerLaunched) { 531 mAnalyzerLaunched = launchAnalysisIfReady(); 532 } 533 return mEchoAnalyzer.isDone(); 534 } 535 getFullDuplexAnalyzer()536 FullDuplexAnalyzer *getFullDuplexAnalyzer() override { 537 return (FullDuplexAnalyzer *) mFullDuplexLatency.get(); 538 } 539 analyzeData(PulseLatencyAnalyzer * analyzer)540 static void analyzeData(PulseLatencyAnalyzer *analyzer) { 541 analyzer->analyze(); 542 } 543 launchAnalysisIfReady()544 bool launchAnalysisIfReady() { 545 // Are we ready to do the analysis? 546 if (mEchoAnalyzer.hasEnoughData()) { 547 // Crunch the numbers on a separate thread. 548 std::thread t(analyzeData, &mEchoAnalyzer); 549 t.detach(); 550 return true; 551 } 552 return false; 553 } 554 555 protected: 556 void finishOpen(bool isInput, oboe::AudioStream *oboeStream) override; 557 558 private: 559 std::unique_ptr<FullDuplexAnalyzer> mFullDuplexLatency{}; 560 561 PulseLatencyAnalyzer mEchoAnalyzer; 562 bool mAnalyzerLaunched = false; 563 }; 564 565 /** 566 * Measure Glitches 567 */ 568 class ActivityGlitches : public ActivityFullDuplex { 569 public: 570 startStreams()571 oboe::Result startStreams() override { 572 return mFullDuplexGlitches->start(); 573 } 574 575 void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) override; 576 getGlitchAnalyzer()577 GlitchAnalyzer *getGlitchAnalyzer() { 578 return &mGlitchAnalyzer; 579 } 580 getState()581 int32_t getState() override { 582 return getGlitchAnalyzer()->getState(); 583 } 584 getResult()585 int32_t getResult() override { 586 return getGlitchAnalyzer()->getResult(); 587 } 588 isAnalyzerDone()589 bool isAnalyzerDone() override { 590 return mGlitchAnalyzer.isDone(); 591 } 592 getFullDuplexAnalyzer()593 FullDuplexAnalyzer *getFullDuplexAnalyzer() override { 594 return (FullDuplexAnalyzer *) mFullDuplexGlitches.get(); 595 } 596 597 protected: 598 void finishOpen(bool isInput, oboe::AudioStream *oboeStream) override; 599 600 private: 601 std::unique_ptr<FullDuplexAnalyzer> mFullDuplexGlitches{}; 602 GlitchAnalyzer mGlitchAnalyzer; 603 }; 604 605 /** 606 * Measure Data Path 607 */ 608 class ActivityDataPath : public ActivityFullDuplex { 609 public: 610 startStreams()611 oboe::Result startStreams() override { 612 return mFullDuplexDataPath->start(); 613 } 614 615 void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) override; 616 configureForStart()617 void configureForStart() override { 618 std::shared_ptr<oboe::AudioStream> outputStream = getOutputStream(); 619 int32_t capacityInFrames = outputStream->getBufferCapacityInFrames(); 620 int32_t burstInFrames = outputStream->getFramesPerBurst(); 621 int32_t capacityInBursts = capacityInFrames / burstInFrames; 622 int32_t sizeInBursts = std::max(2, capacityInBursts / 2); 623 // Set size of buffer to minimize underruns. 624 auto result = outputStream->setBufferSizeInFrames(sizeInBursts * burstInFrames); 625 static_cast<void>(result); // Avoid unused variable. 626 LOGD("ActivityDataPath: %s() capacity = %d, burst = %d, size = %d", 627 __func__, capacityInFrames, burstInFrames, result.value()); 628 } 629 getDataPathAnalyzer()630 DataPathAnalyzer *getDataPathAnalyzer() { 631 return &mDataPathAnalyzer; 632 } 633 getFullDuplexAnalyzer()634 FullDuplexAnalyzer *getFullDuplexAnalyzer() override { 635 return (FullDuplexAnalyzer *) mFullDuplexDataPath.get(); 636 } 637 638 protected: 639 void finishOpen(bool isInput, oboe::AudioStream *oboeStream) override; 640 641 private: 642 std::unique_ptr<FullDuplexAnalyzer> mFullDuplexDataPath{}; 643 644 DataPathAnalyzer mDataPathAnalyzer; 645 }; 646 647 /** 648 * Test a single output stream. 649 */ 650 class ActivityTestDisconnect : public ActivityContext { 651 public: ActivityTestDisconnect()652 ActivityTestDisconnect() {} 653 654 virtual ~ActivityTestDisconnect() = default; 655 656 void close(int32_t streamIndex) override; 657 startStreams()658 oboe::Result startStreams() override { 659 std::shared_ptr<oboe::AudioStream> outputStream = getOutputStream(); 660 if (outputStream) { 661 return outputStream->start(); 662 } 663 664 std::shared_ptr<oboe::AudioStream> inputStream = getInputStream(); 665 if (inputStream) { 666 return inputStream->start(); 667 } 668 return oboe::Result::ErrorNull; 669 } 670 671 void configureForStart() override; 672 673 private: 674 std::unique_ptr<SineOscillator> sineOscillator; 675 std::unique_ptr<MonoToMultiConverter> monoToMulti; 676 std::shared_ptr<oboe::flowgraph::SinkFloat> mSinkFloat; 677 }; 678 679 /** 680 * Switch between various 681 */ 682 class NativeAudioContext { 683 public: 684 getCurrentActivity()685 ActivityContext *getCurrentActivity() { 686 return currentActivity; 687 }; 688 setActivityType(int activityType)689 void setActivityType(int activityType) { 690 mActivityType = (ActivityType) activityType; 691 switch(mActivityType) { 692 default: 693 case ActivityType::Undefined: 694 case ActivityType::TestOutput: 695 currentActivity = &mActivityTestOutput; 696 break; 697 case ActivityType::TestInput: 698 currentActivity = &mActivityTestInput; 699 break; 700 case ActivityType::TapToTone: 701 currentActivity = &mActivityTapToTone; 702 break; 703 case ActivityType::RecordPlay: 704 currentActivity = &mActivityRecording; 705 break; 706 case ActivityType::Echo: 707 currentActivity = &mActivityEcho; 708 break; 709 case ActivityType::RoundTripLatency: 710 currentActivity = &mActivityRoundTripLatency; 711 break; 712 case ActivityType::Glitches: 713 currentActivity = &mActivityGlitches; 714 break; 715 case ActivityType::TestDisconnect: 716 currentActivity = &mActivityTestDisconnect; 717 break; 718 case ActivityType::DataPath: 719 currentActivity = &mActivityDataPath; 720 break; 721 } 722 } 723 setDelayTime(double delayTimeMillis)724 void setDelayTime(double delayTimeMillis) { 725 mActivityEcho.setDelayTime(delayTimeMillis); 726 } 727 728 ActivityTestOutput mActivityTestOutput; 729 ActivityTestInput mActivityTestInput; 730 ActivityTapToTone mActivityTapToTone; 731 ActivityRecording mActivityRecording; 732 ActivityEcho mActivityEcho; 733 ActivityRoundTripLatency mActivityRoundTripLatency; 734 ActivityGlitches mActivityGlitches; 735 ActivityDataPath mActivityDataPath; 736 ActivityTestDisconnect mActivityTestDisconnect; 737 738 739 private: 740 741 // WARNING - must match definitions in TestAudioActivity.java 742 enum ActivityType { 743 Undefined = -1, 744 TestOutput = 0, 745 TestInput = 1, 746 TapToTone = 2, 747 RecordPlay = 3, 748 Echo = 4, 749 RoundTripLatency = 5, 750 Glitches = 6, 751 TestDisconnect = 7, 752 DataPath = 8, 753 }; 754 755 ActivityType mActivityType = ActivityType::Undefined; 756 ActivityContext *currentActivity = &mActivityTestOutput; 757 758 }; 759 760 #endif //NATIVEOBOE_NATIVEAUDIOCONTEXT_H 761