Gruppe 1
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MicrophoneDetector.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. package com.example.ueberwachungssystem.Detection;
  2. import static java.lang.Math.*;
  3. import android.Manifest;
  4. import android.annotation.SuppressLint;
  5. import android.app.Activity;
  6. import android.content.Context;
  7. import android.content.pm.PackageManager;
  8. import android.media.AudioFormat;
  9. import android.media.AudioRecord;
  10. import android.media.MediaRecorder;
  11. import android.os.AsyncTask;
  12. import android.util.Log;
  13. import androidx.core.app.ActivityCompat;
  14. import androidx.core.content.ContextCompat;
  15. import com.example.ueberwachungssystem.Detection.Signalverarbeitung.Complex;
  16. import com.example.ueberwachungssystem.Detection.Signalverarbeitung.FFT;
  17. import com.example.ueberwachungssystem.Detection.DetectionReport;
  18. import com.example.ueberwachungssystem.Detection.Detector;
  19. public class MicrophoneDetector extends Detector {
  20. /**
  21. * Constructor - takes context of current activity
  22. *
  23. * @param context
  24. */
  25. private static final int RECHTEANFORDERUNG_MIKROFON = 1;
  26. private AufnahmeTask aufnahmeTask;
  27. public boolean armed = false;
  28. public int Schwellwert_Alarm = 100;
  29. private Context context;
  30. public MicrophoneDetector(Context context) {
  31. super();
  32. this.context = context;
  33. }
  34. @Override
  35. public void startDetection() {
  36. aufnahmeTask = new AufnahmeTask();
  37. aufnahmeTask.execute();
  38. }
  39. @Override
  40. public void stopDetection() {
  41. if (aufnahmeTask != null) {
  42. aufnahmeTask.cancel(true);
  43. }
  44. }
  45. class AufnahmeTask extends AsyncTask<Long, Verarbeitungsergebnis, Void> {
  46. private AudioRecord recorder;
  47. private final int sampleRateInHz = 44100;
  48. private final int channelConfig = AudioFormat.CHANNEL_IN_MONO;
  49. private final int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
  50. private int minPufferGroesseInBytes;
  51. private int pufferGroesseInBytes;
  52. private RingPuffer ringPuffer = new RingPuffer(10);
  53. private float kalibierWert;
  54. private com.example.ueberwachungssystem.Detection.DetectionReport detectionReport;
  55. @SuppressLint("MissingPermission")
  56. AufnahmeTask() {
  57. minPufferGroesseInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
  58. pufferGroesseInBytes = minPufferGroesseInBytes * 2;
  59. try {
  60. recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConfig, audioFormat, pufferGroesseInBytes);
  61. } catch (Exception e) {
  62. e.printStackTrace();
  63. }
  64. Log.d("0","Puffergroeße: "+ minPufferGroesseInBytes + " " + pufferGroesseInBytes);
  65. Log.d("0","Recorder (SR, CH): "+ recorder.getSampleRate() + " " + recorder.getChannelCount());
  66. int anzahlBytesProAbtastwert;
  67. String s;
  68. switch (recorder.getAudioFormat()) {
  69. case AudioFormat.ENCODING_PCM_8BIT:
  70. s = "8 Bit PCM ";
  71. anzahlBytesProAbtastwert = 1;
  72. break;
  73. case AudioFormat.ENCODING_PCM_16BIT:
  74. s = "16 Bit PCM";
  75. anzahlBytesProAbtastwert = 2;
  76. break;
  77. case AudioFormat.ENCODING_PCM_FLOAT:
  78. s = "Float PCM";
  79. anzahlBytesProAbtastwert = 4;
  80. break;
  81. default:
  82. throw new IllegalArgumentException();
  83. }
  84. switch (recorder.getChannelConfiguration()) {
  85. case AudioFormat.CHANNEL_IN_MONO:
  86. s = "Mono";
  87. break;
  88. case AudioFormat.CHANNEL_IN_STEREO:
  89. s = "Stereo";
  90. anzahlBytesProAbtastwert *= 2;
  91. break;
  92. case AudioFormat.CHANNEL_INVALID:
  93. s = "ungültig";
  94. break;
  95. default:
  96. throw new IllegalArgumentException();
  97. }
  98. Log.d("0","Konfiguration: "+ s);
  99. int pufferGroesseInAnzahlAbtastwerten = pufferGroesseInBytes / anzahlBytesProAbtastwert;
  100. }
  101. @Override
  102. protected Void doInBackground(Long... params) {
  103. recorder.startRecording();
  104. short[] puffer = new short[pufferGroesseInBytes / 2];
  105. long lastTime = System.currentTimeMillis();
  106. float verarbeitungsrate = 0;
  107. final int maxZaehlerZeitMessung = 10;
  108. int zaehlerZeitMessung = 0;
  109. int anzahlVerarbeitet = 0;
  110. GleitenderMittelwert gleitenderMittelwert = new GleitenderMittelwert(0.3f);
  111. //Kalibrierung
  112. try {
  113. Thread.sleep(3000); // Time to lay down the phone
  114. } catch (InterruptedException e) {
  115. e.printStackTrace();
  116. }
  117. int i = 0;
  118. for (i = 0; i < 20; i++) {
  119. int n = recorder.read(puffer, 0, puffer.length);
  120. Verarbeitungsergebnis kalibrierErgebnis = verarbeiten(puffer, n);
  121. kalibierWert += kalibrierErgebnis.maxAmp;
  122. try {
  123. Thread.sleep(50);
  124. } catch (InterruptedException e) {
  125. e.printStackTrace();
  126. }
  127. }
  128. kalibierWert = kalibierWert/i;
  129. // __Part of FFT__
  130. // Complex[] zeitSignal = new Complex[puffer.length];
  131. // for (int j = 0; j < puffer.length; j++) {
  132. // zeitSignal[j] = new Complex(puffer[j], 0);
  133. // }
  134. // Complex[] spektrum = FFT.fft(zeitSignal);
  135. // double[] spektrum = calculateFFT(puffer);
  136. // DataPoint AddPoint;
  137. // LineGraphSeries<DataPoint> series = new LineGraphSeries<DataPoint>(new DataPoint[]{});
  138. // for (i = 0; i < spektrum.length; i++) {
  139. // AddPoint = new DataPoint(i, spektrum[i]);
  140. // series.appendData(AddPoint, true, spektrum.length);
  141. // }
  142. // graph.addSeries(series);
  143. for (; ; ) {
  144. if (aufnahmeTask.isCancelled()) {
  145. break;
  146. } else {
  147. int n = recorder.read(puffer, 0, puffer.length);
  148. Verarbeitungsergebnis ergebnis = verarbeiten(puffer, n);
  149. anzahlVerarbeitet += n;
  150. // __Part of FFT__
  151. // spektrum = calculateFFT(puffer);
  152. // LineGraphSeries<DataPoint> newseries = new LineGraphSeries<DataPoint>(new DataPoint[]{});
  153. // for (i = 0; i < spektrum.length; i++) {
  154. // AddPoint = new DataPoint(i, spektrum[i]);
  155. // newseries.appendData(AddPoint, true, spektrum.length);
  156. // }
  157. zaehlerZeitMessung++;
  158. if (zaehlerZeitMessung == maxZaehlerZeitMessung) {
  159. long time = System.currentTimeMillis();
  160. long deltaTime = time - lastTime;
  161. verarbeitungsrate = 1000.0f * anzahlVerarbeitet / deltaTime;
  162. verarbeitungsrate = gleitenderMittelwert.mittel(verarbeitungsrate);
  163. zaehlerZeitMessung = 0;
  164. anzahlVerarbeitet = 0;
  165. lastTime = time;
  166. }
  167. ergebnis.verarbeitungsrate = (int) verarbeitungsrate;
  168. publishProgress(ergebnis);
  169. try {
  170. Thread.sleep(10);
  171. } catch (InterruptedException e) {
  172. e.printStackTrace();
  173. }
  174. }
  175. }
  176. recorder.release();
  177. return null;
  178. }
  179. private Verarbeitungsergebnis verarbeiten(short[] daten, int n) {
  180. String status;
  181. short maxAmp = -1;
  182. if (n == AudioRecord.ERROR_INVALID_OPERATION) {
  183. status = "ERROR_INVALID_OPERATION";
  184. } else if (n == AudioRecord.ERROR_BAD_VALUE) {
  185. status = "ERROR_BAD_VALUE";
  186. } else {
  187. status = "OK";
  188. short max = 0;
  189. for (int i = 0; i < n; i++) {
  190. if (daten[i] > max) {
  191. max = daten[i];
  192. }
  193. }
  194. ringPuffer.hinzufuegen(max);
  195. maxAmp = ringPuffer.maximum();
  196. if (maxAmp <= Schwellwert_Alarm+kalibierWert) {
  197. armed = true;
  198. }
  199. }
  200. return new Verarbeitungsergebnis(status, maxAmp, 0);
  201. }
  202. @Override
  203. protected void onProgressUpdate(Verarbeitungsergebnis... progress) {
  204. super.onProgressUpdate(progress);
  205. float maxAmpPrint = round(20*log10(abs(progress[0].maxAmp/1.0)));
  206. float kalibierWertPrint = round(20*log10(abs(kalibierWert)));
  207. Log.d("0","VR, Max, Kal:" + progress[0].verarbeitungsrate + ", " + maxAmpPrint
  208. + " dB, " + kalibierWertPrint + " dB");
  209. if (progress[0].maxAmp >= Schwellwert_Alarm+kalibierWert && armed == true) {
  210. armed = false;
  211. detectionReport = new DetectionReport(true, "Audio", maxAmpPrint);
  212. reportViolation("Audio", maxAmpPrint);
  213. Log.d("1",detectionReport.toString());
  214. }
  215. }
  216. }
  217. private double[] calculateFFT(short[] zeitsignal)
  218. {
  219. byte signal[] = new byte[zeitsignal.length];
  220. // loops through all the values of a Short
  221. for (int i = 0; i < zeitsignal.length-1; i++) {
  222. signal[i] = (byte) (zeitsignal[i]);
  223. signal[i+1] = (byte) (zeitsignal[i] >> 8);
  224. }
  225. final int mNumberOfFFTPoints =1024;
  226. double temp;
  227. Complex[] y;
  228. Complex[] complexSignal = new Complex[mNumberOfFFTPoints];
  229. double[] absSignal = new double[mNumberOfFFTPoints/2];
  230. for(int i = 0; i < mNumberOfFFTPoints; i++){
  231. temp = (double)((signal[2*i] & 0xFF) | (signal[2*i+1] << 8)) / 32768.0F;
  232. complexSignal[i] = new Complex(temp,0.0);
  233. }
  234. y = FFT.fft(complexSignal);
  235. for(int i = 0; i < (mNumberOfFFTPoints/2); i++)
  236. {
  237. absSignal[i] = y[i].abs();
  238. }
  239. return absSignal;
  240. }
  241. class Verarbeitungsergebnis {
  242. String status;
  243. short maxAmp;
  244. int verarbeitungsrate;
  245. Verarbeitungsergebnis(String status, short maxAmp, int verarbeitungsrate) {
  246. this.status = status;
  247. this.maxAmp = maxAmp;
  248. this.verarbeitungsrate = verarbeitungsrate;
  249. }
  250. }
  251. class RingPuffer {
  252. private short[] puffer;
  253. private final int laenge;
  254. private int anzahlEnthaltenerDaten;
  255. private int position;
  256. public RingPuffer(int n) {
  257. laenge = n;
  258. anzahlEnthaltenerDaten = 0;
  259. position = 0;
  260. puffer = new short[laenge];
  261. }
  262. public void hinzufuegen(short wert) {
  263. puffer[position] = wert;
  264. position++;
  265. if (position >= laenge) {
  266. position = 0;
  267. }
  268. if (anzahlEnthaltenerDaten < laenge) {
  269. anzahlEnthaltenerDaten++;
  270. }
  271. }
  272. public void hinzufuegen(short[] daten) {
  273. for (short d : daten) {
  274. puffer[position] = d;
  275. position++;
  276. if (position >= laenge) {
  277. position = 0;
  278. }
  279. }
  280. if (anzahlEnthaltenerDaten < laenge) {
  281. anzahlEnthaltenerDaten += daten.length;
  282. if (anzahlEnthaltenerDaten >= laenge) {
  283. anzahlEnthaltenerDaten = laenge;
  284. }
  285. }
  286. }
  287. public short maximum() {
  288. short max = 0;
  289. for (int i = 0; i < anzahlEnthaltenerDaten; i++) {
  290. if (puffer[i] > max) {
  291. max = puffer[i];
  292. }
  293. }
  294. return max;
  295. }
  296. public float mittelwert() {
  297. float summe = 0;
  298. for (int i = 0; i < anzahlEnthaltenerDaten; i++) {
  299. summe += puffer[i];
  300. }
  301. return summe / anzahlEnthaltenerDaten;
  302. }
  303. }
  304. class GleitenderMittelwert {
  305. private final float wichtungNeuerWert;
  306. private final float wichtungAlterWert;
  307. private float mittelwert = 0;
  308. private boolean istMittelwertGesetzt = false;
  309. GleitenderMittelwert(float wichtungNeuerWert) {
  310. this.wichtungNeuerWert = wichtungNeuerWert;
  311. this.wichtungAlterWert = 1 - this.wichtungNeuerWert;
  312. }
  313. float MittelwertPuffer(short[] puffer) {
  314. for (int i = 0; i < puffer.length; i++) {
  315. mittelwert = Math.abs(puffer[i]);
  316. }
  317. mittelwert = mittelwert/puffer.length;
  318. return mittelwert;
  319. }
  320. float mittel(float wert) {
  321. if (istMittelwertGesetzt) {
  322. mittelwert = wert * wichtungNeuerWert + mittelwert * wichtungAlterWert;
  323. } else {
  324. mittelwert = wert;
  325. istMittelwertGesetzt = true;
  326. }
  327. return mittelwert;
  328. }
  329. }
  330. }