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