1c72fcc34Sopenharmony_ci/* 2c72fcc34Sopenharmony_ci * Copyright (C) 2013-2015 Intel Corporation 3c72fcc34Sopenharmony_ci * 4c72fcc34Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 5c72fcc34Sopenharmony_ci * it under the terms of the GNU General Public License as published by 6c72fcc34Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 7c72fcc34Sopenharmony_ci * (at your option) any later version. 8c72fcc34Sopenharmony_ci * 9c72fcc34Sopenharmony_ci * This program is distributed in the hope that it will be useful, 10c72fcc34Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 11c72fcc34Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12c72fcc34Sopenharmony_ci * GNU General Public License for more details. 13c72fcc34Sopenharmony_ci * 14c72fcc34Sopenharmony_ci */ 15c72fcc34Sopenharmony_ci 16c72fcc34Sopenharmony_ci#include "aconfig.h" 17c72fcc34Sopenharmony_ci 18c72fcc34Sopenharmony_ci#include <math.h> 19c72fcc34Sopenharmony_ci#include <stdio.h> 20c72fcc34Sopenharmony_ci#include <stdlib.h> 21c72fcc34Sopenharmony_ci#include <string.h> 22c72fcc34Sopenharmony_ci#include <stdbool.h> 23c72fcc34Sopenharmony_ci 24c72fcc34Sopenharmony_ci#include "common.h" 25c72fcc34Sopenharmony_ci#include "bat-signal.h" 26c72fcc34Sopenharmony_ci#include "gettext.h" 27c72fcc34Sopenharmony_ci 28c72fcc34Sopenharmony_ci/* How one measurement step works: 29c72fcc34Sopenharmony_ci - Listen and measure the average loudness of the environment for 1 second. 30c72fcc34Sopenharmony_ci - Create a threshold value 16 decibels higher than the average loudness. 31c72fcc34Sopenharmony_ci - Begin playing a ~1000 Hz sine wave and start counting the samples elapsed. 32c72fcc34Sopenharmony_ci - Stop counting and playing if the input's loudness is higher than the 33c72fcc34Sopenharmony_ci threshold, as the output wave is probably coming back. 34c72fcc34Sopenharmony_ci - Calculate the round trip audio latency value in milliseconds. */ 35c72fcc34Sopenharmony_ci 36c72fcc34Sopenharmony_cistatic float sumaudio(struct bat *bat, short int *buffer, int frames) 37c72fcc34Sopenharmony_ci{ 38c72fcc34Sopenharmony_ci float sum = 0; 39c72fcc34Sopenharmony_ci int n = 0; 40c72fcc34Sopenharmony_ci 41c72fcc34Sopenharmony_ci while (frames) { 42c72fcc34Sopenharmony_ci frames--; 43c72fcc34Sopenharmony_ci 44c72fcc34Sopenharmony_ci for (n = 0; n < bat->channels; n++) { 45c72fcc34Sopenharmony_ci sum += abs(buffer[0]); 46c72fcc34Sopenharmony_ci buffer++; 47c72fcc34Sopenharmony_ci } 48c72fcc34Sopenharmony_ci } 49c72fcc34Sopenharmony_ci 50c72fcc34Sopenharmony_ci sum = sum / bat->channels; 51c72fcc34Sopenharmony_ci 52c72fcc34Sopenharmony_ci return sum; 53c72fcc34Sopenharmony_ci} 54c72fcc34Sopenharmony_ci 55c72fcc34Sopenharmony_cistatic void play_and_listen(struct bat *bat, void *buffer, int frames) 56c72fcc34Sopenharmony_ci{ 57c72fcc34Sopenharmony_ci int averageinput; 58c72fcc34Sopenharmony_ci int n = 0; 59c72fcc34Sopenharmony_ci float sum = 0; 60c72fcc34Sopenharmony_ci float max = 0; 61c72fcc34Sopenharmony_ci float min = 100000.0f; 62c72fcc34Sopenharmony_ci short int *input; 63c72fcc34Sopenharmony_ci int num = bat->latency.number; 64c72fcc34Sopenharmony_ci 65c72fcc34Sopenharmony_ci averageinput = (int) (sumaudio(bat, buffer, frames) / frames); 66c72fcc34Sopenharmony_ci 67c72fcc34Sopenharmony_ci /* The signal is above threshold 68c72fcc34Sopenharmony_ci So our sine wave comes back on the input */ 69c72fcc34Sopenharmony_ci if (averageinput > bat->latency.threshold) { 70c72fcc34Sopenharmony_ci input = buffer; 71c72fcc34Sopenharmony_ci 72c72fcc34Sopenharmony_ci /* Check the location when it became loud enough */ 73c72fcc34Sopenharmony_ci while (n < frames) { 74c72fcc34Sopenharmony_ci if (*input++ > bat->latency.threshold) 75c72fcc34Sopenharmony_ci break; 76c72fcc34Sopenharmony_ci *input += bat->channels; 77c72fcc34Sopenharmony_ci n++; 78c72fcc34Sopenharmony_ci } 79c72fcc34Sopenharmony_ci 80c72fcc34Sopenharmony_ci /* Now we get the total round trip latency*/ 81c72fcc34Sopenharmony_ci bat->latency.samples += n; 82c72fcc34Sopenharmony_ci 83c72fcc34Sopenharmony_ci /* Expect at least 1 buffer of round trip latency. */ 84c72fcc34Sopenharmony_ci if (bat->latency.samples > frames) { 85c72fcc34Sopenharmony_ci bat->latency.result[num - 1] = 86c72fcc34Sopenharmony_ci (float) bat->latency.samples * 1000 / bat->rate; 87c72fcc34Sopenharmony_ci fprintf(bat->log, 88c72fcc34Sopenharmony_ci _("Test%d, round trip latency %dms\n"), 89c72fcc34Sopenharmony_ci num, 90c72fcc34Sopenharmony_ci (int) bat->latency.result[num - 1]); 91c72fcc34Sopenharmony_ci 92c72fcc34Sopenharmony_ci for (n = 0; n < num; n++) { 93c72fcc34Sopenharmony_ci if (bat->latency.result[n] > max) 94c72fcc34Sopenharmony_ci max = bat->latency.result[n]; 95c72fcc34Sopenharmony_ci if (bat->latency.result[n] < min) 96c72fcc34Sopenharmony_ci min = bat->latency.result[n]; 97c72fcc34Sopenharmony_ci sum += bat->latency.result[n]; 98c72fcc34Sopenharmony_ci } 99c72fcc34Sopenharmony_ci 100c72fcc34Sopenharmony_ci /* The maximum is higher than the minimum's double */ 101c72fcc34Sopenharmony_ci if (max / min > 2.0f) { 102c72fcc34Sopenharmony_ci bat->latency.state = 103c72fcc34Sopenharmony_ci LATENCY_STATE_COMPLETE_FAILURE; 104c72fcc34Sopenharmony_ci bat->latency.is_capturing = false; 105c72fcc34Sopenharmony_ci return; 106c72fcc34Sopenharmony_ci 107c72fcc34Sopenharmony_ci /* Final results */ 108c72fcc34Sopenharmony_ci } else if (num == LATENCY_TEST_NUMBER) { 109c72fcc34Sopenharmony_ci bat->latency.final_result = 110c72fcc34Sopenharmony_ci (int) (sum / LATENCY_TEST_NUMBER); 111c72fcc34Sopenharmony_ci fprintf(bat->log, 112c72fcc34Sopenharmony_ci _("Final round trip latency: %dms\n"), 113c72fcc34Sopenharmony_ci bat->latency.final_result); 114c72fcc34Sopenharmony_ci 115c72fcc34Sopenharmony_ci bat->latency.state = 116c72fcc34Sopenharmony_ci LATENCY_STATE_COMPLETE_SUCCESS; 117c72fcc34Sopenharmony_ci bat->latency.is_capturing = false; 118c72fcc34Sopenharmony_ci return; 119c72fcc34Sopenharmony_ci 120c72fcc34Sopenharmony_ci /* Next step */ 121c72fcc34Sopenharmony_ci } else 122c72fcc34Sopenharmony_ci bat->latency.state = LATENCY_STATE_WAITING; 123c72fcc34Sopenharmony_ci 124c72fcc34Sopenharmony_ci bat->latency.number++; 125c72fcc34Sopenharmony_ci 126c72fcc34Sopenharmony_ci } else 127c72fcc34Sopenharmony_ci /* Happens when an early noise comes in */ 128c72fcc34Sopenharmony_ci bat->latency.state = LATENCY_STATE_WAITING; 129c72fcc34Sopenharmony_ci 130c72fcc34Sopenharmony_ci } else { 131c72fcc34Sopenharmony_ci /* Still listening */ 132c72fcc34Sopenharmony_ci bat->latency.samples += frames; 133c72fcc34Sopenharmony_ci 134c72fcc34Sopenharmony_ci /* Do not listen to more than a second 135c72fcc34Sopenharmony_ci Maybe too much background noise */ 136c72fcc34Sopenharmony_ci if ((unsigned int)bat->latency.samples > bat->rate) { 137c72fcc34Sopenharmony_ci bat->latency.error++; 138c72fcc34Sopenharmony_ci 139c72fcc34Sopenharmony_ci if (bat->latency.error > LATENCY_TEST_NUMBER) { 140c72fcc34Sopenharmony_ci fprintf(bat->err, 141c72fcc34Sopenharmony_ci _("Could not detect signal.")); 142c72fcc34Sopenharmony_ci fprintf(bat->err, 143c72fcc34Sopenharmony_ci _("Too much background noise?\n")); 144c72fcc34Sopenharmony_ci bat->latency.state = 145c72fcc34Sopenharmony_ci LATENCY_STATE_COMPLETE_FAILURE; 146c72fcc34Sopenharmony_ci bat->latency.is_capturing = false; 147c72fcc34Sopenharmony_ci return; 148c72fcc34Sopenharmony_ci } 149c72fcc34Sopenharmony_ci 150c72fcc34Sopenharmony_ci /* let's start over */ 151c72fcc34Sopenharmony_ci bat->latency.state = LATENCY_STATE_WAITING; 152c72fcc34Sopenharmony_ci } 153c72fcc34Sopenharmony_ci } 154c72fcc34Sopenharmony_ci 155c72fcc34Sopenharmony_ci return; 156c72fcc34Sopenharmony_ci} 157c72fcc34Sopenharmony_ci 158c72fcc34Sopenharmony_cistatic void calculate_threshold(struct bat *bat) 159c72fcc34Sopenharmony_ci{ 160c72fcc34Sopenharmony_ci float average; 161c72fcc34Sopenharmony_ci float reference; 162c72fcc34Sopenharmony_ci 163c72fcc34Sopenharmony_ci /* Calculate the average loudness of the environment and create 164c72fcc34Sopenharmony_ci a threshold value 16 decibels higher than the average loudness */ 165c72fcc34Sopenharmony_ci average = bat->latency.sum / bat->latency.samples / 32767.0f; 166c72fcc34Sopenharmony_ci reference = 20.0f * log10f(average) + 16.0f; 167c72fcc34Sopenharmony_ci bat->latency.threshold = (int) (powf(10.0f, reference / 20.0f) 168c72fcc34Sopenharmony_ci * 32767.0f); 169c72fcc34Sopenharmony_ci} 170c72fcc34Sopenharmony_ci 171c72fcc34Sopenharmony_civoid roundtrip_latency_init(struct bat *bat) 172c72fcc34Sopenharmony_ci{ 173c72fcc34Sopenharmony_ci bat->latency.number = 1; 174c72fcc34Sopenharmony_ci bat->latency.state = LATENCY_STATE_MEASURE_FOR_1_SECOND; 175c72fcc34Sopenharmony_ci bat->latency.final_result = 0; 176c72fcc34Sopenharmony_ci bat->latency.samples = 0; 177c72fcc34Sopenharmony_ci bat->latency.sum = 0; 178c72fcc34Sopenharmony_ci bat->latency.threshold = 0; 179c72fcc34Sopenharmony_ci bat->latency.is_capturing = false; 180c72fcc34Sopenharmony_ci bat->latency.is_playing = false; 181c72fcc34Sopenharmony_ci bat->latency.error = 0; 182c72fcc34Sopenharmony_ci bat->latency.xrun_error = false; 183c72fcc34Sopenharmony_ci bat->frames = LATENCY_TEST_TIME_LIMIT * bat->rate; 184c72fcc34Sopenharmony_ci bat->periods_played = 0; 185c72fcc34Sopenharmony_ci} 186c72fcc34Sopenharmony_ci 187c72fcc34Sopenharmony_ciint handleinput(struct bat *bat, void *buffer, int frames) 188c72fcc34Sopenharmony_ci{ 189c72fcc34Sopenharmony_ci switch (bat->latency.state) { 190c72fcc34Sopenharmony_ci /* Measuring average loudness for 1 second */ 191c72fcc34Sopenharmony_ci case LATENCY_STATE_MEASURE_FOR_1_SECOND: 192c72fcc34Sopenharmony_ci bat->latency.sum += sumaudio(bat, buffer, frames); 193c72fcc34Sopenharmony_ci bat->latency.samples += frames; 194c72fcc34Sopenharmony_ci 195c72fcc34Sopenharmony_ci /* 1 second elapsed */ 196c72fcc34Sopenharmony_ci if ((unsigned int)bat->latency.samples >= bat->rate) { 197c72fcc34Sopenharmony_ci calculate_threshold(bat); 198c72fcc34Sopenharmony_ci bat->latency.state = LATENCY_STATE_PLAY_AND_LISTEN; 199c72fcc34Sopenharmony_ci bat->latency.samples = 0; 200c72fcc34Sopenharmony_ci bat->latency.sum = 0; 201c72fcc34Sopenharmony_ci } 202c72fcc34Sopenharmony_ci break; 203c72fcc34Sopenharmony_ci 204c72fcc34Sopenharmony_ci /* Playing sine wave and listening if it comes back */ 205c72fcc34Sopenharmony_ci case LATENCY_STATE_PLAY_AND_LISTEN: 206c72fcc34Sopenharmony_ci play_and_listen(bat, buffer, frames); 207c72fcc34Sopenharmony_ci break; 208c72fcc34Sopenharmony_ci 209c72fcc34Sopenharmony_ci /* Waiting 1 second */ 210c72fcc34Sopenharmony_ci case LATENCY_STATE_WAITING: 211c72fcc34Sopenharmony_ci bat->latency.samples += frames; 212c72fcc34Sopenharmony_ci 213c72fcc34Sopenharmony_ci if ((unsigned int)bat->latency.samples > bat->rate) { 214c72fcc34Sopenharmony_ci /* 1 second elapsed, start over */ 215c72fcc34Sopenharmony_ci bat->latency.samples = 0; 216c72fcc34Sopenharmony_ci bat->latency.state = LATENCY_STATE_MEASURE_FOR_1_SECOND; 217c72fcc34Sopenharmony_ci } 218c72fcc34Sopenharmony_ci break; 219c72fcc34Sopenharmony_ci 220c72fcc34Sopenharmony_ci default: 221c72fcc34Sopenharmony_ci return 0; 222c72fcc34Sopenharmony_ci } 223c72fcc34Sopenharmony_ci 224c72fcc34Sopenharmony_ci return 0; 225c72fcc34Sopenharmony_ci} 226c72fcc34Sopenharmony_ci 227c72fcc34Sopenharmony_ciint handleoutput(struct bat *bat, void *buffer, int bytes, int frames) 228c72fcc34Sopenharmony_ci{ 229c72fcc34Sopenharmony_ci int err = 0; 230c72fcc34Sopenharmony_ci 231c72fcc34Sopenharmony_ci /* If capture completed, terminate the playback */ 232c72fcc34Sopenharmony_ci if (bat->periods_played * frames > 2 * bat->rate 233c72fcc34Sopenharmony_ci && bat->latency.is_capturing == false) 234c72fcc34Sopenharmony_ci return bat->latency.state; 235c72fcc34Sopenharmony_ci 236c72fcc34Sopenharmony_ci if (bat->latency.state == LATENCY_STATE_PLAY_AND_LISTEN) 237c72fcc34Sopenharmony_ci err = generate_sine_wave(bat, frames, buffer); 238c72fcc34Sopenharmony_ci else 239c72fcc34Sopenharmony_ci /* Output silence */ 240c72fcc34Sopenharmony_ci memset(buffer, 0, bytes); 241c72fcc34Sopenharmony_ci 242c72fcc34Sopenharmony_ci return err; 243c72fcc34Sopenharmony_ci} 244