1*d57664e9SAndroid Build Coastguard Worker /* 2*d57664e9SAndroid Build Coastguard Worker * Copyright (C) 2010 The Android Open Source Project 3*d57664e9SAndroid Build Coastguard Worker * 4*d57664e9SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*d57664e9SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*d57664e9SAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*d57664e9SAndroid Build Coastguard Worker * 8*d57664e9SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*d57664e9SAndroid Build Coastguard Worker * 10*d57664e9SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*d57664e9SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*d57664e9SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*d57664e9SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*d57664e9SAndroid Build Coastguard Worker * limitations under the License. 15*d57664e9SAndroid Build Coastguard Worker */ 16*d57664e9SAndroid Build Coastguard Worker 17*d57664e9SAndroid Build Coastguard Worker #ifndef ANDROID_MEDIA_VISUALIZER_H 18*d57664e9SAndroid Build Coastguard Worker #define ANDROID_MEDIA_VISUALIZER_H 19*d57664e9SAndroid Build Coastguard Worker 20*d57664e9SAndroid Build Coastguard Worker #include <media/AudioEffect.h> 21*d57664e9SAndroid Build Coastguard Worker #include <system/audio_effects/effect_visualizer.h> 22*d57664e9SAndroid Build Coastguard Worker #include <utils/Thread.h> 23*d57664e9SAndroid Build Coastguard Worker #include <cstdint> 24*d57664e9SAndroid Build Coastguard Worker #include <cutils/bitops.h> 25*d57664e9SAndroid Build Coastguard Worker #include "android/content/AttributionSourceState.h" 26*d57664e9SAndroid Build Coastguard Worker 27*d57664e9SAndroid Build Coastguard Worker /** 28*d57664e9SAndroid Build Coastguard Worker * The Visualizer class enables application to retrieve part of the currently playing audio for 29*d57664e9SAndroid Build Coastguard Worker * visualization purpose. It is not an audio recording interface and only returns partial and low 30*d57664e9SAndroid Build Coastguard Worker * quality audio content. However, to protect privacy of certain audio data (e.g voice mail) the use 31*d57664e9SAndroid Build Coastguard Worker * of the visualizer requires the permission android.permission.RECORD_AUDIO. 32*d57664e9SAndroid Build Coastguard Worker * The audio session ID passed to the constructor indicates which audio content should be 33*d57664e9SAndroid Build Coastguard Worker * visualized: 34*d57664e9SAndroid Build Coastguard Worker * - If the session is 0, the audio output mix is visualized 35*d57664e9SAndroid Build Coastguard Worker * - If the session is not 0, the audio from a particular MediaPlayer or AudioTrack 36*d57664e9SAndroid Build Coastguard Worker * using this audio session is visualized 37*d57664e9SAndroid Build Coastguard Worker * Two types of representation of audio content can be captured: 38*d57664e9SAndroid Build Coastguard Worker * - Waveform data: consecutive 8-bit (unsigned) mono samples by using the getWaveForm() method 39*d57664e9SAndroid Build Coastguard Worker * - Frequency data: 8-bit magnitude FFT by using the getFft() method 40*d57664e9SAndroid Build Coastguard Worker * 41*d57664e9SAndroid Build Coastguard Worker * The length of the capture can be retrieved or specified by calling respectively 42*d57664e9SAndroid Build Coastguard Worker * getCaptureSize() and setCaptureSize() methods. Note that the size of the FFT 43*d57664e9SAndroid Build Coastguard Worker * is half of the specified capture size but both sides of the spectrum are returned yielding in a 44*d57664e9SAndroid Build Coastguard Worker * number of bytes equal to the capture size. The capture size must be a power of 2 in the range 45*d57664e9SAndroid Build Coastguard Worker * returned by getMinCaptureSize() and getMaxCaptureSize(). 46*d57664e9SAndroid Build Coastguard Worker * In addition to the polling capture mode, a callback mode is also available by installing a 47*d57664e9SAndroid Build Coastguard Worker * callback function by use of the setCaptureCallBack() method. The rate at which the callback 48*d57664e9SAndroid Build Coastguard Worker * is called as well as the type of data returned is specified. 49*d57664e9SAndroid Build Coastguard Worker * Before capturing data, the Visualizer must be enabled by calling the setEnabled() method. 50*d57664e9SAndroid Build Coastguard Worker * When data capture is not needed any more, the Visualizer should be disabled. 51*d57664e9SAndroid Build Coastguard Worker */ 52*d57664e9SAndroid Build Coastguard Worker 53*d57664e9SAndroid Build Coastguard Worker 54*d57664e9SAndroid Build Coastguard Worker namespace android { 55*d57664e9SAndroid Build Coastguard Worker 56*d57664e9SAndroid Build Coastguard Worker // ---------------------------------------------------------------------------- 57*d57664e9SAndroid Build Coastguard Worker 58*d57664e9SAndroid Build Coastguard Worker class Visualizer: public AudioEffect { 59*d57664e9SAndroid Build Coastguard Worker public: 60*d57664e9SAndroid Build Coastguard Worker 61*d57664e9SAndroid Build Coastguard Worker enum callback_flags { 62*d57664e9SAndroid Build Coastguard Worker CAPTURE_WAVEFORM = 0x00000001, // capture callback returns a PCM wave form 63*d57664e9SAndroid Build Coastguard Worker CAPTURE_FFT = 0x00000002, // apture callback returns a frequency representation 64*d57664e9SAndroid Build Coastguard Worker CAPTURE_CALL_JAVA = 0x00000004 // the callback thread can call java 65*d57664e9SAndroid Build Coastguard Worker }; 66*d57664e9SAndroid Build Coastguard Worker 67*d57664e9SAndroid Build Coastguard Worker 68*d57664e9SAndroid Build Coastguard Worker /* Constructor. 69*d57664e9SAndroid Build Coastguard Worker * See AudioEffect constructor for details on parameters. 70*d57664e9SAndroid Build Coastguard Worker */ 71*d57664e9SAndroid Build Coastguard Worker explicit Visualizer(const android::content::AttributionSourceState& attributionSource); 72*d57664e9SAndroid Build Coastguard Worker 73*d57664e9SAndroid Build Coastguard Worker ~Visualizer(); 74*d57664e9SAndroid Build Coastguard Worker 75*d57664e9SAndroid Build Coastguard Worker /** 76*d57664e9SAndroid Build Coastguard Worker * Initialize an uninitialized Visualizer. 77*d57664e9SAndroid Build Coastguard Worker * See AudioEffect 'set' function for details on parameters. 78*d57664e9SAndroid Build Coastguard Worker */ 79*d57664e9SAndroid Build Coastguard Worker status_t set(int32_t priority = 0, 80*d57664e9SAndroid Build Coastguard Worker legacy_callback_t cbf = nullptr, 81*d57664e9SAndroid Build Coastguard Worker void* user = nullptr, 82*d57664e9SAndroid Build Coastguard Worker audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX, 83*d57664e9SAndroid Build Coastguard Worker audio_io_handle_t io = AUDIO_IO_HANDLE_NONE, 84*d57664e9SAndroid Build Coastguard Worker const AudioDeviceTypeAddr& device = {}, 85*d57664e9SAndroid Build Coastguard Worker bool probe = false); 86*d57664e9SAndroid Build Coastguard Worker 87*d57664e9SAndroid Build Coastguard Worker // Declared 'final' because we call this in ~Visualizer(). 88*d57664e9SAndroid Build Coastguard Worker status_t setEnabled(bool enabled) final; 89*d57664e9SAndroid Build Coastguard Worker 90*d57664e9SAndroid Build Coastguard Worker // maximum capture size in samples getMaxCaptureSize()91*d57664e9SAndroid Build Coastguard Worker static uint32_t getMaxCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MAX; } 92*d57664e9SAndroid Build Coastguard Worker // minimum capture size in samples getMinCaptureSize()93*d57664e9SAndroid Build Coastguard Worker static uint32_t getMinCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MIN; } 94*d57664e9SAndroid Build Coastguard Worker // maximum capture rate in millihertz getMaxCaptureRate()95*d57664e9SAndroid Build Coastguard Worker static uint32_t getMaxCaptureRate() { return CAPTURE_RATE_MAX; } 96*d57664e9SAndroid Build Coastguard Worker 97*d57664e9SAndroid Build Coastguard Worker // callback used to return periodic PCM or FFT captures to the application. Either one or both 98*d57664e9SAndroid Build Coastguard Worker // types of data are returned (PCM and FFT) according to flags indicated when installing the 99*d57664e9SAndroid Build Coastguard Worker // callback. When a type of data is not present, the corresponding size (waveformSize or 100*d57664e9SAndroid Build Coastguard Worker // fftSize) is 0. 101*d57664e9SAndroid Build Coastguard Worker typedef void (*capture_cbk_t)(void* user, 102*d57664e9SAndroid Build Coastguard Worker uint32_t waveformSize, 103*d57664e9SAndroid Build Coastguard Worker uint8_t *waveform, 104*d57664e9SAndroid Build Coastguard Worker uint32_t fftSize, 105*d57664e9SAndroid Build Coastguard Worker uint8_t *fft, 106*d57664e9SAndroid Build Coastguard Worker uint32_t samplingrate); 107*d57664e9SAndroid Build Coastguard Worker 108*d57664e9SAndroid Build Coastguard Worker // install a callback to receive periodic captures. The capture rate is specified in milliHertz 109*d57664e9SAndroid Build Coastguard Worker // and the capture format is according to flags (see callback_flags). 110*d57664e9SAndroid Build Coastguard Worker status_t setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate); 111*d57664e9SAndroid Build Coastguard Worker 112*d57664e9SAndroid Build Coastguard Worker // set the capture size capture size must be a power of two in the range 113*d57664e9SAndroid Build Coastguard Worker // [VISUALIZER_CAPTURE_SIZE_MAX. VISUALIZER_CAPTURE_SIZE_MIN] 114*d57664e9SAndroid Build Coastguard Worker // must be called when the visualizer is not enabled 115*d57664e9SAndroid Build Coastguard Worker status_t setCaptureSize(uint32_t size); getCaptureSize()116*d57664e9SAndroid Build Coastguard Worker uint32_t getCaptureSize() { return mCaptureSize; } 117*d57664e9SAndroid Build Coastguard Worker 118*d57664e9SAndroid Build Coastguard Worker // returns the capture rate indicated when installing the callback getCaptureRate()119*d57664e9SAndroid Build Coastguard Worker uint32_t getCaptureRate() { return mCaptureRate; } 120*d57664e9SAndroid Build Coastguard Worker 121*d57664e9SAndroid Build Coastguard Worker // returns the sampling rate of the audio being captured getSamplingRate()122*d57664e9SAndroid Build Coastguard Worker uint32_t getSamplingRate() { return mSampleRate; } 123*d57664e9SAndroid Build Coastguard Worker 124*d57664e9SAndroid Build Coastguard Worker // set the way volume affects the captured data 125*d57664e9SAndroid Build Coastguard Worker // mode must one of VISUALIZER_SCALING_MODE_NORMALIZED, 126*d57664e9SAndroid Build Coastguard Worker // VISUALIZER_SCALING_MODE_AS_PLAYED 127*d57664e9SAndroid Build Coastguard Worker status_t setScalingMode(uint32_t mode); getScalingMode()128*d57664e9SAndroid Build Coastguard Worker uint32_t getScalingMode() { return mScalingMode; } 129*d57664e9SAndroid Build Coastguard Worker 130*d57664e9SAndroid Build Coastguard Worker // set which measurements are done on the audio buffers processed by the effect. 131*d57664e9SAndroid Build Coastguard Worker // valid measurements (mask): MEASUREMENT_MODE_PEAK_RMS 132*d57664e9SAndroid Build Coastguard Worker status_t setMeasurementMode(uint32_t mode); getMeasurementMode()133*d57664e9SAndroid Build Coastguard Worker uint32_t getMeasurementMode() { return mMeasurementMode; } 134*d57664e9SAndroid Build Coastguard Worker 135*d57664e9SAndroid Build Coastguard Worker // return a set of int32_t measurements 136*d57664e9SAndroid Build Coastguard Worker status_t getIntMeasurements(uint32_t type, uint32_t number, int32_t *measurements); 137*d57664e9SAndroid Build Coastguard Worker 138*d57664e9SAndroid Build Coastguard Worker // return a capture in PCM 8 bit unsigned format. The size of the capture is equal to 139*d57664e9SAndroid Build Coastguard Worker // getCaptureSize() 140*d57664e9SAndroid Build Coastguard Worker status_t getWaveForm(uint8_t *waveform); 141*d57664e9SAndroid Build Coastguard Worker 142*d57664e9SAndroid Build Coastguard Worker // return a capture in FFT 8 bit signed format. The size of the capture is equal to 143*d57664e9SAndroid Build Coastguard Worker // getCaptureSize() but the length of the FFT is half of the size (both parts of the spectrum 144*d57664e9SAndroid Build Coastguard Worker // are returned 145*d57664e9SAndroid Build Coastguard Worker status_t getFft(uint8_t *fft); 146*d57664e9SAndroid Build Coastguard Worker void release(); 147*d57664e9SAndroid Build Coastguard Worker 148*d57664e9SAndroid Build Coastguard Worker protected: 149*d57664e9SAndroid Build Coastguard Worker // from IEffectClient 150*d57664e9SAndroid Build Coastguard Worker virtual void controlStatusChanged(bool controlGranted); 151*d57664e9SAndroid Build Coastguard Worker 152*d57664e9SAndroid Build Coastguard Worker private: 153*d57664e9SAndroid Build Coastguard Worker 154*d57664e9SAndroid Build Coastguard Worker static const uint32_t CAPTURE_RATE_MAX = 20000; 155*d57664e9SAndroid Build Coastguard Worker static const uint32_t CAPTURE_RATE_DEF = 10000; 156*d57664e9SAndroid Build Coastguard Worker static const uint32_t CAPTURE_SIZE_DEF = VISUALIZER_CAPTURE_SIZE_MAX; 157*d57664e9SAndroid Build Coastguard Worker 158*d57664e9SAndroid Build Coastguard Worker /* internal class to handle the callback */ 159*d57664e9SAndroid Build Coastguard Worker class CaptureThread : public Thread 160*d57664e9SAndroid Build Coastguard Worker { 161*d57664e9SAndroid Build Coastguard Worker public: 162*d57664e9SAndroid Build Coastguard Worker CaptureThread(const sp<Visualizer>& visualizer, 163*d57664e9SAndroid Build Coastguard Worker uint32_t captureRate, bool bCanCallJava = false); 164*d57664e9SAndroid Build Coastguard Worker 165*d57664e9SAndroid Build Coastguard Worker private: 166*d57664e9SAndroid Build Coastguard Worker friend class Visualizer; 167*d57664e9SAndroid Build Coastguard Worker virtual bool threadLoop(); 168*d57664e9SAndroid Build Coastguard Worker wp<Visualizer> mReceiver; 169*d57664e9SAndroid Build Coastguard Worker Mutex mLock; 170*d57664e9SAndroid Build Coastguard Worker uint32_t mSleepTimeUs; 171*d57664e9SAndroid Build Coastguard Worker }; 172*d57664e9SAndroid Build Coastguard Worker 173*d57664e9SAndroid Build Coastguard Worker status_t doFft(uint8_t *fft, uint8_t *waveform); 174*d57664e9SAndroid Build Coastguard Worker void periodicCapture(); 175*d57664e9SAndroid Build Coastguard Worker status_t initCaptureSize(); 176*d57664e9SAndroid Build Coastguard Worker void initSampleRate(); isCaptureSizeValid(uint32_t size)177*d57664e9SAndroid Build Coastguard Worker static constexpr bool isCaptureSizeValid(uint32_t size) { 178*d57664e9SAndroid Build Coastguard Worker return size <= VISUALIZER_CAPTURE_SIZE_MAX && size >= VISUALIZER_CAPTURE_SIZE_MIN && 179*d57664e9SAndroid Build Coastguard Worker popcount(size) == 1; 180*d57664e9SAndroid Build Coastguard Worker } 181*d57664e9SAndroid Build Coastguard Worker 182*d57664e9SAndroid Build Coastguard Worker Mutex mCaptureLock; 183*d57664e9SAndroid Build Coastguard Worker uint32_t mCaptureRate = CAPTURE_RATE_DEF; 184*d57664e9SAndroid Build Coastguard Worker uint32_t mCaptureSize = CAPTURE_SIZE_DEF; 185*d57664e9SAndroid Build Coastguard Worker uint32_t mSampleRate = 44100000; 186*d57664e9SAndroid Build Coastguard Worker uint32_t mScalingMode = VISUALIZER_SCALING_MODE_NORMALIZED; 187*d57664e9SAndroid Build Coastguard Worker uint32_t mMeasurementMode = MEASUREMENT_MODE_NONE; 188*d57664e9SAndroid Build Coastguard Worker capture_cbk_t mCaptureCallBack = nullptr; 189*d57664e9SAndroid Build Coastguard Worker void *mCaptureCbkUser = nullptr; 190*d57664e9SAndroid Build Coastguard Worker sp<CaptureThread> mCaptureThread; 191*d57664e9SAndroid Build Coastguard Worker uint32_t mCaptureFlags = 0; 192*d57664e9SAndroid Build Coastguard Worker }; 193*d57664e9SAndroid Build Coastguard Worker 194*d57664e9SAndroid Build Coastguard Worker 195*d57664e9SAndroid Build Coastguard Worker }; // namespace android 196*d57664e9SAndroid Build Coastguard Worker 197*d57664e9SAndroid Build Coastguard Worker #endif // ANDROID_MEDIA_VISUALIZER_H 198