package com.example.ueberwachungssystem.Detection; import static java.lang.Math.*; import android.annotation.SuppressLint; import android.content.Context; import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaRecorder; import android.os.AsyncTask; import android.util.Log; import com.example.ueberwachungssystem.Detection.Signalverarbeitung.Complex; import com.example.ueberwachungssystem.Detection.Signalverarbeitung.FFT; public class MicrophoneDetector extends Detector { /** * Constructor - takes context of current activity * * @param context */ private AufnahmeTask aufnahmeTask; public boolean armed = false; public int schwellwertAlarm = 100; private Context context; public MicrophoneDetector(Context context) { super(); this.context = context; } @Override public void startDetection() { aufnahmeTask = new AufnahmeTask(); aufnahmeTask.execute(); } @Override public void stopDetection() { if (aufnahmeTask != null) { aufnahmeTask.cancel(true); } } class AufnahmeTask extends AsyncTask { private AudioRecord recorder; private final int sampleRateInHz = 44100; private final int channelConfig = AudioFormat.CHANNEL_IN_MONO; private final int audioFormat = AudioFormat.ENCODING_PCM_16BIT; private final int startDelay = 2000; private final int threadSleeptime = 10; private int minPufferGroesseInBytes; private int pufferGroesseInBytes; private RingPuffer ringPuffer = new RingPuffer(10); private float kalibierWert; private com.example.ueberwachungssystem.Detection.DetectionReport detectionReport; @SuppressLint("MissingPermission") AufnahmeTask() { minPufferGroesseInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat); pufferGroesseInBytes = minPufferGroesseInBytes * 2; try { recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConfig, audioFormat, pufferGroesseInBytes); } catch (Exception e) { e.printStackTrace(); } Log.d("0","Puffergroeße: "+ minPufferGroesseInBytes + " " + pufferGroesseInBytes); Log.d("0","Recorder (SR, CH): "+ recorder.getSampleRate() + " " + recorder.getChannelCount()); int anzahlBytesProAbtastwert; String s; switch (recorder.getAudioFormat()) { case AudioFormat.ENCODING_PCM_8BIT: s = "8 Bit PCM "; anzahlBytesProAbtastwert = 1; break; case AudioFormat.ENCODING_PCM_16BIT: s = "16 Bit PCM"; anzahlBytesProAbtastwert = 2; break; case AudioFormat.ENCODING_PCM_FLOAT: s = "Float PCM"; anzahlBytesProAbtastwert = 4; break; default: throw new IllegalArgumentException(); } switch (recorder.getChannelConfiguration()) { case AudioFormat.CHANNEL_IN_MONO: s = "Mono"; break; case AudioFormat.CHANNEL_IN_STEREO: s = "Stereo"; anzahlBytesProAbtastwert *= 2; break; case AudioFormat.CHANNEL_INVALID: s = "ungültig"; break; default: throw new IllegalArgumentException(); } Log.d("0","Konfiguration: "+ s); } @Override protected Void doInBackground(Long... params) { recorder.startRecording(); short[] puffer = new short[pufferGroesseInBytes / 2]; long lastTime = System.currentTimeMillis(); float verarbeitungsrate = 0; final int maxZaehlerZeitMessung = 10; int zaehlerZeitMessung = 0; int anzahlVerarbeitet = 0; GleitenderMittelwert gleitenderMittelwert = new GleitenderMittelwert(0.3f); //Kalibrierung try { Thread.sleep(startDelay); // Time to lay down the phone } catch (InterruptedException e) { e.printStackTrace(); } int i = 0; for (i = 0; i < 20; i++) { int n = recorder.read(puffer, 0, puffer.length); Verarbeitungsergebnis kalibrierErgebnis = verarbeiten(puffer, n); kalibierWert += kalibrierErgebnis.maxAmp; try { Thread.sleep(threadSleeptime); } catch (InterruptedException e) { e.printStackTrace(); } } kalibierWert = kalibierWert/i; // __Part of FFT__ // Complex[] zeitSignal = new Complex[puffer.length]; // for (int j = 0; j < puffer.length; j++) { // zeitSignal[j] = new Complex(puffer[j], 0); // } // Complex[] spektrum = FFT.fft(zeitSignal); // double[] spektrum = calculateFFT(puffer); // DataPoint AddPoint; // LineGraphSeries series = new LineGraphSeries(new DataPoint[]{}); // for (i = 0; i < spektrum.length; i++) { // AddPoint = new DataPoint(i, spektrum[i]); // series.appendData(AddPoint, true, spektrum.length); // } // graph.addSeries(series); for (; ; ) { if (aufnahmeTask.isCancelled()) { break; } else { int n = recorder.read(puffer, 0, puffer.length); Verarbeitungsergebnis ergebnis = verarbeiten(puffer, n); anzahlVerarbeitet += n; // __Part of FFT__ // spektrum = calculateFFT(puffer); // LineGraphSeries newseries = new LineGraphSeries(new DataPoint[]{}); // for (i = 0; i < spektrum.length; i++) { // AddPoint = new DataPoint(i, spektrum[i]); // newseries.appendData(AddPoint, true, spektrum.length); // } zaehlerZeitMessung++; if (zaehlerZeitMessung == maxZaehlerZeitMessung) { long time = System.currentTimeMillis(); long deltaTime = time - lastTime; verarbeitungsrate = 1000.0f * anzahlVerarbeitet / deltaTime; verarbeitungsrate = gleitenderMittelwert.mittel(verarbeitungsrate); zaehlerZeitMessung = 0; anzahlVerarbeitet = 0; lastTime = time; } ergebnis.verarbeitungsrate = (int) verarbeitungsrate; publishProgress(ergebnis); try { Thread.sleep(threadSleeptime); } catch (InterruptedException e) { e.printStackTrace(); } } } recorder.release(); return null; } private Verarbeitungsergebnis verarbeiten(short[] daten, int n) { String status; short maxAmp = -1; if (n == AudioRecord.ERROR_INVALID_OPERATION) { status = "ERROR_INVALID_OPERATION"; } else if (n == AudioRecord.ERROR_BAD_VALUE) { status = "ERROR_BAD_VALUE"; } else { status = "OK"; short max = 0; for (int i = 0; i < n; i++) { if (daten[i] > max) { max = daten[i]; } } ringPuffer.hinzufuegen(max); maxAmp = ringPuffer.maximum(); if (maxAmp <= schwellwertAlarm + kalibierWert) { armed = true; } } return new Verarbeitungsergebnis(status, maxAmp, 0); } @Override protected void onProgressUpdate(Verarbeitungsergebnis... progress) { super.onProgressUpdate(progress); float maxAmpPrint = round(20*log10(abs(progress[0].maxAmp/1.0))); float kalibierWertPrint = round(20*log10(abs(kalibierWert))); Log.d("alarmAudio","VR: " + progress[0].verarbeitungsrate + ", Amp: " + maxAmpPrint + " dB, Kal: " + kalibierWertPrint + " dB"); if (progress[0].maxAmp >= schwellwertAlarm + kalibierWert && armed == true) { armed = false; detectionReport = new DetectionReport(true, "Audio", maxAmpPrint); reportViolation("Audio", maxAmpPrint); Log.d("1",detectionReport.toString()); } } } private double[] calculateFFT(short[] zeitsignal) { byte signal[] = new byte[zeitsignal.length]; // loops through all the values of a Short for (int i = 0; i < zeitsignal.length-1; i++) { signal[i] = (byte) (zeitsignal[i]); signal[i+1] = (byte) (zeitsignal[i] >> 8); } final int mNumberOfFFTPoints =1024; double temp; Complex[] y; Complex[] complexSignal = new Complex[mNumberOfFFTPoints]; double[] absSignal = new double[mNumberOfFFTPoints/2]; for(int i = 0; i < mNumberOfFFTPoints; i++){ temp = (double)((signal[2*i] & 0xFF) | (signal[2*i+1] << 8)) / 32768.0F; complexSignal[i] = new Complex(temp,0.0); } y = FFT.fft(complexSignal); for(int i = 0; i < (mNumberOfFFTPoints/2); i++) { absSignal[i] = y[i].abs(); } return absSignal; } class Verarbeitungsergebnis { String status; short maxAmp; int verarbeitungsrate; Verarbeitungsergebnis(String status, short maxAmp, int verarbeitungsrate) { this.status = status; this.maxAmp = maxAmp; this.verarbeitungsrate = verarbeitungsrate; } } class RingPuffer { private short[] puffer; private final int laenge; private int anzahlEnthaltenerDaten; private int position; public RingPuffer(int n) { laenge = n; anzahlEnthaltenerDaten = 0; position = 0; puffer = new short[laenge]; } public void hinzufuegen(short wert) { puffer[position] = wert; position++; if (position >= laenge) { position = 0; } if (anzahlEnthaltenerDaten < laenge) { anzahlEnthaltenerDaten++; } } public void hinzufuegen(short[] daten) { for (short d : daten) { puffer[position] = d; position++; if (position >= laenge) { position = 0; } } if (anzahlEnthaltenerDaten < laenge) { anzahlEnthaltenerDaten += daten.length; if (anzahlEnthaltenerDaten >= laenge) { anzahlEnthaltenerDaten = laenge; } } } public short maximum() { short max = 0; for (int i = 0; i < anzahlEnthaltenerDaten; i++) { if (puffer[i] > max) { max = puffer[i]; } } return max; } public float mittelwert() { float summe = 0; for (int i = 0; i < anzahlEnthaltenerDaten; i++) { summe += puffer[i]; } return summe / anzahlEnthaltenerDaten; } } class GleitenderMittelwert { private final float wichtungNeuerWert; private final float wichtungAlterWert; private float mittelwert = 0; private boolean istMittelwertGesetzt = false; GleitenderMittelwert(float wichtungNeuerWert) { this.wichtungNeuerWert = wichtungNeuerWert; this.wichtungAlterWert = 1 - this.wichtungNeuerWert; } float mittel(float wert) { if (istMittelwertGesetzt) { mittelwert = wert * wichtungNeuerWert + mittelwert * wichtungAlterWert; } else { mittelwert = wert; istMittelwertGesetzt = true; } return mittelwert; } } }