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 15KB

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