1f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol/* 2f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol * Copyright (C) 2017 The Android Open Source Project 3f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol * 4f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol * Licensed under the Apache License, Version 2.0 (the "License"); 5f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol * you may not use this file except in compliance with the License. 6f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol * You may obtain a copy of the License at 7f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol * 8f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol * http://www.apache.org/licenses/LICENSE-2.0 9f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol * 10f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol * Unless required by applicable law or agreed to in writing, software 11f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol * distributed under the License is distributed on an "AS IS" BASIS, 12f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol * See the License for the specific language governing permissions and 14f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol * limitations under the License. 15f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol */ 16f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol 17f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol#include <chre.h> 18f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol#include <cinttypes> 19344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol#include <cmath> 20f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol 21344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol#include "chre/util/macros.h" 229661bd5953f2668d89de40e376a939f1f345af11Andrew Rossignol#include "chre/util/nanoapp/audio.h" 23f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol#include "chre/util/nanoapp/log.h" 24344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol#include "chre/util/time.h" 25344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol#include "kiss_fftr.h" 26f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol 27f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol#define LOG_TAG "[AudioWorld]" 28f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol 29f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol#ifdef CHRE_NANOAPP_INTERNAL 30f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignolnamespace chre { 31f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignolnamespace { 32f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol#endif // CHRE_NANOAPP_INTERNAL 33f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol 34742d1da96b54b55cbd33c7a57273389149e9179bAndrew Rossignolusing chre::Milliseconds; 35742d1da96b54b55cbd33c7a57273389149e9179bAndrew Rossignolusing chre::Nanoseconds; 36742d1da96b54b55cbd33c7a57273389149e9179bAndrew Rossignol 37344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol//! The number of frequencies to generate an FFT over. 38344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignolconstexpr size_t kNumFrequencies = 128; 39344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol 40344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol//! State for Kiss FFT and logging. 41344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignoluint8_t gKissFftBuffer[4096]; 42344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignolkiss_fftr_cfg gKissFftConfig; 43344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignolkiss_fft_cpx gKissFftOutput[(kNumFrequencies / 2) + 1]; 44742d1da96b54b55cbd33c7a57273389149e9179bAndrew RossignolMilliseconds gFirstAudioEventTimestamp = Milliseconds(0); 45344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol 46344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol/** 47344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol * Returns a graphical representation of a uint16_t value. 48344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol * 49344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol * @param value the value to visualize. 50344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol * @return a character that visually represents the value. 51344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol */ 52344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignolchar getFftCharForValue(uint16_t value) { 532da3902580409536642180b587cba8092c1f26beAndrew Rossignol constexpr uint16_t kFftLowLimit = 128; 542da3902580409536642180b587cba8092c1f26beAndrew Rossignol constexpr uint16_t kFftMedLimit = 256; 552da3902580409536642180b587cba8092c1f26beAndrew Rossignol constexpr uint16_t kFftHighLimit = 512; // Texas Hold'em ༼⁰o⁰;༽ 562da3902580409536642180b587cba8092c1f26beAndrew Rossignol constexpr uint16_t kFftVeryHighLimit = 1024; 572da3902580409536642180b587cba8092c1f26beAndrew Rossignol 582da3902580409536642180b587cba8092c1f26beAndrew Rossignol if (value < kFftLowLimit) { 592da3902580409536642180b587cba8092c1f26beAndrew Rossignol return ' '; 602da3902580409536642180b587cba8092c1f26beAndrew Rossignol } else if (value >= kFftLowLimit && value < kFftMedLimit) { 61344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol return '_'; 622da3902580409536642180b587cba8092c1f26beAndrew Rossignol } else if (value >= kFftMedLimit && value < kFftHighLimit) { 63344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol return '.'; 642da3902580409536642180b587cba8092c1f26beAndrew Rossignol } else if (value >= kFftHighLimit && value < kFftVeryHighLimit) { 65344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol return 'x'; 66344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol } else { 67344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol return 'X'; 68344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol } 69344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol} 70344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol 71344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol/** 72344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol * Initializes Kiss FFT. 73344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol */ 74344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignolvoid initKissFft() { 75344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol size_t kissFftBufferSize = sizeof(gKissFftBuffer); 76344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol gKissFftConfig = kiss_fftr_alloc(kNumFrequencies, false, 77344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol gKissFftBuffer, &kissFftBufferSize); 78344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol if (gKissFftConfig == NULL) { 79344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol LOGE("Failed to init Kiss FFT, needs minimum %zu buffer size", 80344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol kissFftBufferSize); 81344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol } else { 82344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol LOGI("Initialized Kiss FFT, using %zu/%zu of the buffer", 83344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol kissFftBufferSize, sizeof(gKissFftBuffer)); 84344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol } 85344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol} 86344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol 87344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol/** 88344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol * Logs an audio data event with an FFT visualization of the received audio 89344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol * data. 90344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol * 91344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol * @param event the audio data event to log. 92344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol */ 93e5247e8a8cd777649b3c3d13843c4a9867e78c90Andrew Rossignolvoid handleAudioDataEvent(const struct chreAudioDataEvent *event) { 94344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol kiss_fftr(gKissFftConfig, event->samplesS16, gKissFftOutput); 95344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol 96344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol char fftStr[ARRAY_SIZE(gKissFftOutput) + 1]; 97344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol fftStr[ARRAY_SIZE(gKissFftOutput)] = '\0'; 98344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol 99344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol for (size_t i = 0; i < ARRAY_SIZE(gKissFftOutput); i++) { 100344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol float value = sqrtf(powf(gKissFftOutput[i].r, 2) 101344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol + powf(gKissFftOutput[i].i, 2)); 102344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol fftStr[i] = getFftCharForValue(static_cast<uint16_t>(value)); 103344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol } 104344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol 105344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol Milliseconds timestamp = Milliseconds(Nanoseconds(event->timestamp)); 106344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol if (gFirstAudioEventTimestamp == Milliseconds(0)) { 107344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol gFirstAudioEventTimestamp = timestamp; 108344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol } 109344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol 110344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol Milliseconds adjustedTimestamp = timestamp - gFirstAudioEventTimestamp; 111344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol LOGD("Audio data - FFT [%s] at %" PRIu64 "ms with %" PRIu32 " samples", 112344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol fftStr, adjustedTimestamp.getMilliseconds(), event->sampleCount); 113344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol} 114344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol 115e5247e8a8cd777649b3c3d13843c4a9867e78c90Andrew Rossignolvoid handleAudioSamplingChangeEvent( 116e5247e8a8cd777649b3c3d13843c4a9867e78c90Andrew Rossignol const struct chreAudioSourceStatusEvent *event) { 117e5247e8a8cd777649b3c3d13843c4a9867e78c90Andrew Rossignol LOGD("Audio sampling status event for handle %" PRIu32 ", suspended: %d", 118e5247e8a8cd777649b3c3d13843c4a9867e78c90Andrew Rossignol event->handle, event->status.suspended); 119e5247e8a8cd777649b3c3d13843c4a9867e78c90Andrew Rossignol} 120e5247e8a8cd777649b3c3d13843c4a9867e78c90Andrew Rossignol 121f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignolbool nanoappStart() { 122f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol LOGI("Started"); 1239661bd5953f2668d89de40e376a939f1f345af11Andrew Rossignol 1249661bd5953f2668d89de40e376a939f1f345af11Andrew Rossignol struct chreAudioSource audioSource; 1259661bd5953f2668d89de40e376a939f1f345af11Andrew Rossignol for (uint32_t i = 0; chreAudioGetSource(i, &audioSource); i++) { 126dad92ae023e7c90058c0354d4f3f272b7e73dcddAndrew Rossignol LOGI("Found audio source '%s' with %" PRIu32 "Hz %s data", 1279661bd5953f2668d89de40e376a939f1f345af11Andrew Rossignol audioSource.name, audioSource.sampleRate, 128742d1da96b54b55cbd33c7a57273389149e9179bAndrew Rossignol chre::getChreAudioFormatString(audioSource.format)); 129dad92ae023e7c90058c0354d4f3f272b7e73dcddAndrew Rossignol LOGI(" buffer duration: [%" PRIu64 "ns, %" PRIu64 "ns]", 130dad92ae023e7c90058c0354d4f3f272b7e73dcddAndrew Rossignol audioSource.minBufferDuration, audioSource.maxBufferDuration); 131dad92ae023e7c90058c0354d4f3f272b7e73dcddAndrew Rossignol 132dad92ae023e7c90058c0354d4f3f272b7e73dcddAndrew Rossignol if (i == 0) { 133dad92ae023e7c90058c0354d4f3f272b7e73dcddAndrew Rossignol // Only request audio data from the first source, but continue discovery. 134dad92ae023e7c90058c0354d4f3f272b7e73dcddAndrew Rossignol if (chreAudioConfigureSource(i, true, 135dad92ae023e7c90058c0354d4f3f272b7e73dcddAndrew Rossignol audioSource.minBufferDuration, audioSource.minBufferDuration)) { 136dad92ae023e7c90058c0354d4f3f272b7e73dcddAndrew Rossignol LOGI("Requested audio from handle %" PRIu32 " successfully", i); 137dad92ae023e7c90058c0354d4f3f272b7e73dcddAndrew Rossignol } else { 138dad92ae023e7c90058c0354d4f3f272b7e73dcddAndrew Rossignol LOGE("Failed to request audio from handle %" PRIu32, i); 139dad92ae023e7c90058c0354d4f3f272b7e73dcddAndrew Rossignol } 140be4aae1e34fb0025ad0bb185ae0dcfb9a50fe9cbAndrew Rossignol } 1419661bd5953f2668d89de40e376a939f1f345af11Andrew Rossignol } 1429661bd5953f2668d89de40e376a939f1f345af11Andrew Rossignol 143344da157341b647ff001bdfe8690c902ce80bc9aAndrew Rossignol initKissFft(); 144f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol return true; 145f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol} 146f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol 147f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignolvoid nanoappHandleEvent(uint32_t senderInstanceId, 148f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol uint16_t eventType, 149f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol const void *eventData) { 150f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol switch (eventType) { 151e5247e8a8cd777649b3c3d13843c4a9867e78c90Andrew Rossignol case CHRE_EVENT_AUDIO_DATA: 152e5247e8a8cd777649b3c3d13843c4a9867e78c90Andrew Rossignol handleAudioDataEvent( 153e5247e8a8cd777649b3c3d13843c4a9867e78c90Andrew Rossignol static_cast<const struct chreAudioDataEvent *>(eventData)); 154e5247e8a8cd777649b3c3d13843c4a9867e78c90Andrew Rossignol break; 155e5247e8a8cd777649b3c3d13843c4a9867e78c90Andrew Rossignol case CHRE_EVENT_AUDIO_SAMPLING_CHANGE: 156e5247e8a8cd777649b3c3d13843c4a9867e78c90Andrew Rossignol handleAudioSamplingChangeEvent( 157e5247e8a8cd777649b3c3d13843c4a9867e78c90Andrew Rossignol static_cast<const struct chreAudioSourceStatusEvent *>(eventData)); 158be4aae1e34fb0025ad0bb185ae0dcfb9a50fe9cbAndrew Rossignol break; 159f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol default: 160f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol LOGW("Unknown event received"); 161f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol break; 162f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol } 163f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol} 164f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol 165f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignolvoid nanoappEnd() { 166f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol LOGI("Stopped"); 167f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol} 168f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol 169f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol#ifdef CHRE_NANOAPP_INTERNAL 170f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol} // anonymous namespace 171f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol} // namespace chre 172f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol 173f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol#include "chre/util/nanoapp/app_id.h" 174f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol#include "chre/platform/static_nanoapp_init.h" 175f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol 176f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew RossignolCHRE_STATIC_NANOAPP_INIT(AudioWorld, chre::kAudioWorldAppId, 0); 177f43dfa6d0b0b4005ee2643f8a1e898b7dde78cc3Andrew Rossignol#endif // CHRE_NANOAPP_INTERNAL 178