123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 |
- package com.example.ueberwachungssystem.Detection;
-
- import static java.lang.Math.*;
-
- import android.Manifest;
- import android.annotation.SuppressLint;
- import android.app.Activity;
- import android.content.Context;
- import android.content.pm.PackageManager;
- import android.media.AudioFormat;
- import android.media.AudioRecord;
- import android.media.MediaRecorder;
- import android.os.AsyncTask;
- import android.util.Log;
-
- import androidx.core.app.ActivityCompat;
- import androidx.core.content.ContextCompat;
-
- import com.example.ueberwachungssystem.Detection.Signalverarbeitung.Complex;
- import com.example.ueberwachungssystem.Detection.Signalverarbeitung.FFT;
- import com.example.ueberwachungssystem.Detection.DetectionReport;
- import com.example.ueberwachungssystem.Detection.Detector;
-
- public class MicrophoneDetector extends Detector {
- /**
- * Constructor - takes context of current activity
- *
- * @param context
- */
-
- private static final int RECHTEANFORDERUNG_MIKROFON = 1;
-
- private AufnahmeTask aufnahmeTask;
- public boolean armed = false;
- public int Schwellwert_Alarm = 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<Long, Verarbeitungsergebnis, Void> {
- 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 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);
-
- int pufferGroesseInAnzahlAbtastwerten = pufferGroesseInBytes / anzahlBytesProAbtastwert;
-
- }
-
- @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(3000); // 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(50);
- } 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<DataPoint> series = new LineGraphSeries<DataPoint>(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<DataPoint> newseries = new LineGraphSeries<DataPoint>(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(10);
- } 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 <= Schwellwert_Alarm+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("0","VR, Max, Kal:" + progress[0].verarbeitungsrate + ", " + maxAmpPrint
- + " dB, " + kalibierWertPrint + " dB");
-
- if (progress[0].maxAmp >= Schwellwert_Alarm+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 MittelwertPuffer(short[] puffer) {
-
- for (int i = 0; i < puffer.length; i++) {
- mittelwert = Math.abs(puffer[i]);
- }
- mittelwert = mittelwert/puffer.length;
-
- return mittelwert;
- }
-
- float mittel(float wert) {
- if (istMittelwertGesetzt) {
- mittelwert = wert * wichtungNeuerWert + mittelwert * wichtungAlterWert;
- } else {
- mittelwert = wert;
- istMittelwertGesetzt = true;
- }
- return mittelwert;
- }
- }
- }
|