3
0

MicrophoneSystemComponent_Android.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "MicrophoneSystemComponent.h"
  9. #include "SimpleDownsample.h"
  10. #include <AzCore/std/chrono/chrono.h>
  11. #include <AzCore/std/parallel/atomic.h>
  12. #include <AzCore/std/parallel/thread.h>
  13. #include <AzCore/std/smart_ptr/unique_ptr.h>
  14. #include <AzCore/EBus/EBus.h>
  15. #include <AudioRingBuffer.h>
  16. #include <IAudioInterfacesCommonData.h>
  17. #if defined(USE_LIBSAMPLERATE)
  18. #include <samplerate.h>
  19. #endif // USE_LIBSAMPLERATE
  20. #include <AzCore/Android/Utils.h>
  21. #include <AzCore/Android/JNI/Object.h>
  22. namespace Audio
  23. {
  24. class MicrophoneSystemEventsAndroid : public AZ::EBusTraits
  25. {
  26. public:
  27. static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
  28. static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
  29. virtual ~MicrophoneSystemEventsAndroid() = default;
  30. virtual void HandleIncomingData(AZ::s8* data, int size) {}
  31. };
  32. using MicrophoneSystemEventsAndroidBus = AZ::EBus<MicrophoneSystemEventsAndroid>;
  33. static void JNI_SendCurrentData(JNIEnv* jniEnv, jobject objectRef, jbyteArray data, jint size)
  34. {
  35. jbyte* bufferPtr = jniEnv->GetByteArrayElements(data, nullptr);
  36. MicrophoneSystemEventsAndroidBus::Broadcast(&MicrophoneSystemEventsAndroid::HandleIncomingData, bufferPtr, size);
  37. jniEnv->ReleaseByteArrayElements(data, bufferPtr, JNI_ABORT);
  38. }
  39. ///////////////////////////////////////////////////////////////////////////////////////////////
  40. class MicrophoneSystemComponentAndroid : public MicrophoneSystemComponent::Implementation
  41. , public MicrophoneSystemEventsAndroidBus::Handler
  42. {
  43. public:
  44. AZ_CLASS_ALLOCATOR(MicrophoneSystemComponentAndroid, AZ::SystemAllocator);
  45. bool InitializeDevice() override
  46. {
  47. AZ_TracePrintf("AndroidMicrophone", "Initializing Microphone device - Android!!\n");
  48. MicrophoneSystemEventsAndroidBus::Handler::BusConnect();
  49. m_JNIobject.RegisterStaticMethod("InitializeDevice", "()Z");
  50. m_JNIobject.RegisterStaticMethod("ShutdownDevice", "()V");
  51. m_JNIobject.RegisterStaticMethod("StartSession", "()Z");
  52. m_JNIobject.RegisterStaticMethod("EndSession", "()V");
  53. m_JNIobject.RegisterStaticMethod("IsCapturing", "()Z");
  54. m_JNIobject.RegisterNativeMethods(
  55. {
  56. {"SendCurrentData", "([BI)V", (void*)JNI_SendCurrentData}
  57. }
  58. );
  59. // These are the Android "guaranteed" parameters
  60. // Note that this must match what is setup in MicrophoneSystemComponent.java
  61. // as this is the config that's will reflect the incoming data
  62. // and it will need to be compared to see if downsampling is required
  63. m_config.m_sampleRate = 44100;
  64. m_config.m_numChannels = 1;
  65. m_config.m_bitsPerSample = 16;
  66. m_config.m_sourceType = AudioInputSourceType::Microphone;
  67. m_config.m_sampleType = AudioInputSampleType::Int;
  68. m_config.SetBufferSizeFromFrameCount(512);
  69. return m_JNIobject.InvokeStaticBooleanMethod("InitializeDevice");
  70. }
  71. void ShutdownDevice() override
  72. {
  73. m_JNIobject.InvokeStaticVoidMethod("ShutdownDevice");
  74. MicrophoneSystemEventsAndroidBus::Handler::BusDisconnect();
  75. }
  76. bool StartSession() override
  77. {
  78. m_captureData.reset(aznew Audio::RingBuffer<AZ::s16>(4096)); // this is a good size to keep buffer filling and draining without gaps
  79. return m_JNIobject.InvokeStaticBooleanMethod("StartSession");
  80. }
  81. void EndSession() override
  82. {
  83. m_JNIobject.InvokeStaticVoidMethod("EndSession");
  84. if(m_captureData)
  85. {
  86. m_captureData.reset();
  87. }
  88. }
  89. bool IsCapturing() override
  90. {
  91. return m_JNIobject.InvokeStaticBooleanMethod("IsCapturing");
  92. }
  93. SAudioInputConfig GetFormatConfig() const override
  94. {
  95. return m_config;
  96. }
  97. AZStd::size_t GetData(void** outputData, AZStd::size_t numFrames, const SAudioInputConfig& targetConfig, bool shouldDeinterleave)
  98. {
  99. #if defined(USE_LIBSAMPLERATE)
  100. return {};
  101. #else
  102. bool changeSampleType = (targetConfig.m_sampleType != m_config.m_sampleType);
  103. bool changeSampleRate = (targetConfig.m_sampleRate != m_config.m_sampleRate);
  104. bool changeNumChannels = (targetConfig.m_numChannels != m_config.m_numChannels);
  105. if (changeSampleType || changeNumChannels)
  106. {
  107. // Without the SRC library, any change is unsupported!
  108. return {};
  109. }
  110. else if (changeSampleRate)
  111. {
  112. if(targetConfig.m_sampleRate > m_config.m_sampleRate)
  113. {
  114. AZ_Error("MacOSMicrophone", false, "Target sample rate is larger than source sample rate, this is not supported");
  115. return {};
  116. }
  117. auto sourceBuffer = new AZ::s16[numFrames];
  118. AZStd::size_t targetSize = GetDownsampleSize(numFrames, m_config.m_sampleRate, targetConfig.m_sampleRate);
  119. auto targetBuffer = new AZ::s16[targetSize];
  120. numFrames = m_captureData->ConsumeData(reinterpret_cast<void**>(&sourceBuffer), numFrames, m_config.m_numChannels, false);
  121. if(numFrames > 0)
  122. {
  123. Downsample(sourceBuffer, numFrames, m_config.m_sampleRate, targetBuffer, targetSize, targetConfig.m_sampleRate);
  124. numFrames = targetSize;
  125. // swap target data to output
  126. ::memcpy(*outputData, targetBuffer, targetSize * 2); //*2 as two bytes per frame
  127. }
  128. delete [] sourceBuffer;
  129. delete [] targetBuffer;
  130. return numFrames;
  131. }
  132. else
  133. {
  134. // No change to the data from Input to Output
  135. return m_captureData->ConsumeData(outputData, numFrames, m_config.m_numChannels, shouldDeinterleave);
  136. }
  137. #endif
  138. }
  139. void HandleIncomingData(AZ::s8* data, int size) override
  140. {
  141. m_captureData->AddData((AZ::s16*)data, size / 2, m_config.m_numChannels);
  142. }
  143. private:
  144. AZ::Android::JNI::Object m_JNIobject {"com/amazon/lumberyard/Microphone/MicrophoneSystemComponent"};
  145. Audio::SAudioInputConfig m_config;
  146. AZStd::unique_ptr<Audio::RingBufferBase> m_captureData = nullptr;
  147. };
  148. ///////////////////////////////////////////////////////////////////////////////////////////////
  149. MicrophoneSystemComponent::Implementation* MicrophoneSystemComponent::Implementation::Create()
  150. {
  151. return aznew MicrophoneSystemComponentAndroid();
  152. }
  153. }