edu.rutgers.winlab.crowdpp.service.SpeakerCountService.java Source code

Java tutorial

Introduction

Here is the source code for edu.rutgers.winlab.crowdpp.service.SpeakerCountService.java

Source

/*
 * Copyright (c) 2012-2014 Chenren Xu, Sugang Li
 * Acknowledgments: Yanyong Zhang, Yih-Farn (Robin) Chen, Emiliano Miluzzo, Jun Li
 * Contact: lendlice@winlab.rutgers.edu
 *
 * This file is part of the Crowdpp.
 *
 * Crowdpp is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Crowdpp is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with the Crowdpp. If not, see <http://www.gnu.org/licenses/>.
 * 
 */

package edu.rutgers.winlab.crowdpp.service;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.PutObjectRequest;

import edu.rutgers.winlab.crowdpp.audio.SpeakerCount;
import edu.rutgers.winlab.crowdpp.audio.MFCC;
import edu.rutgers.winlab.crowdpp.audio.Yin;
import edu.rutgers.winlab.crowdpp.db.DataBaseHelper;
import edu.rutgers.winlab.crowdpp.sensor.LocationTracker;
import edu.rutgers.winlab.crowdpp.ui.HomeFragment;
import edu.rutgers.winlab.crowdpp.ui.MainActivity;
//import edu.rutgers.winlab.crowdpp.ui.test.MainActivity;
import edu.rutgers.winlab.crowdpp.util.Constants;
import edu.rutgers.winlab.crowdpp.util.FileProcess;
import edu.rutgers.winlab.crowdpp.util.Now;
import edu.rutgers.winlab.crowdpp.util.PhoneStatus;
import edu.rutgers.winlab.crowdpp.R;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
import android.util.Log;
import android.widget.Toast;

/**
 * The SpeakerCountService class 
 * @author Chenren Xu, Sugang Li
 */
@SuppressLint("SimpleDateFormat")
public class SpeakerCountService extends Service {

    static boolean debug = false;

    private Timer speakerCountTimer;
    private Timer audioRecordTimer;

    private DataBaseHelper mDatabase;
    private SQLiteDatabase mDB;

    private LocationTracker loc;

    // Wakelock prevents Crowdpp service from stopping
    private PowerManager.WakeLock wl;

    private AmazonS3Client s3Client;

    private SharedPreferences settings;

    private String wavFile;
    private File serviceDir;

    static boolean recording = false;

    // default values when the data is not available
    static int speaker_count = 0;
    static double percentage = -1;
    static double latitude = -1;
    static double longitude = -1;

    // read from settings
    static String start_hr, end_hr, interval_min, duration_min, location, upload;

    // for database insertion
    static long sys_time;
    static String date, start, end;
    static String curr_hr, curr_min, curr_date;
    public static final int NOTIFICATIN_ID = 100;

    private void showInfo() {
        NotificationManager manager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
        //get the service of the notification                
        Notification mNotification = new Notification();
        mNotification.icon = R.drawable.ic_launcher;
        mNotification.flags |= Notification.FLAG_ONGOING_EVENT;// is running           
        Intent intent = new Intent(this, MainActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
        mNotification.contentIntent = pendingIntent;
        mNotification.setLatestEventInfo(this, "Crowdpp4.0", "The Service is Running", pendingIntent);
        manager.notify(NOTIFICATIN_ID, mNotification);
    }

    @Override
    public void onCreate() {
        Toast.makeText(this, "Speaker Count Service Started ", Toast.LENGTH_SHORT).show();
        serviceDir = new File(Constants.servicePath);
        showInfo();
        if (!serviceDir.exists() || !serviceDir.isDirectory()) {
            serviceDir.mkdir();
        }

        mDatabase = new DataBaseHelper(getApplicationContext());
        mDB = mDatabase.getWritableDatabase();

        loc = new LocationTracker(getApplicationContext());

        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "No sleep");
        wl.acquire();

        s3Client = new AmazonS3Client(new BasicAWSCredentials(Constants.ACCESS_KEY_ID, Constants.SECRET_KEY));
        s3Client.setRegion(Region.getRegion(Regions.US_WEST_2));
    }

    @SuppressWarnings("deprecation")
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        settings = this.getSharedPreferences("config", Context.MODE_PRIVATE);
        start_hr = settings.getString("start", "");
        end_hr = settings.getString("end", "");
        interval_min = settings.getString("interval", "");
        duration_min = settings.getString("duration", "");
        location = settings.getString("location", "");
        upload = settings.getString("upload", "");

        java.util.Date dt = new java.util.Date();
        curr_hr = Now.getHour();
        curr_min = Now.getMinute();
        curr_date = Now.getDate();

        // immediately start in debug mode
        if (debug) {
            interval_min = "3";
            duration_min = "1";
            int i = Integer.parseInt(curr_min);
            if (i < 59) {
                dt.setHours(Integer.parseInt(curr_hr));
                dt.setMinutes(i + 1);
            } else if (i == 59) {
                dt.setHours(Integer.parseInt(curr_hr) + 1);
                dt.setMinutes(0);
            }
        } else {
            dt.setHours(Integer.parseInt(curr_hr) + 1);
            dt.setMinutes(0);
        }

        String time = Now.getTime();
        Log.i("Crowd++", "Service will start at " + time);

        long interval_ms = (long) (Integer.parseInt(interval_min) * 60 * 1000);
        speakerCountTimer = new Timer();
        speakerCountTimer.schedule(new SpeakerCountTask(), dt, interval_ms);
        return START_STICKY;
    }

    /** This timer executes every interval_ms in a periodic manner to record audio and count speakers. */
    private class SpeakerCountTask extends TimerTask {
        @Override
        public void run() {
            date = Now.getDate();
            start = Now.getTimeOfDay();
            curr_hr = Now.getHour();
            Log.i("SpeakerCountTask", Integer.parseInt(curr_hr) + " is between " + Integer.parseInt(start_hr)
                    + " and " + Integer.parseInt(end_hr) + "?");
            if (Integer.parseInt(curr_hr) >= Integer.parseInt(start_hr)
                    && Integer.parseInt(curr_hr) < Integer.parseInt(end_hr)) {
                Log.i("SpeakerCountTask", "In period.");
                String filename = FileProcess.newFileOnTime("wav");
                wavFile = serviceDir + "/" + filename;
                Bundle mbundle = new Bundle();
                mbundle.putString("audiopath", wavFile);
                recording = true;
                // start audio recording
                Intent audioRecordIntent = new Intent(SpeakerCountService.this, AudioRecordService.class);
                audioRecordIntent.putExtras(mbundle);
                Log.i("SpeakerCountTask", "Recording");
                startService(audioRecordIntent);
                long duration_ms = (long) (Integer.parseInt(duration_min) * 60 * 1000);
                audioRecordTimer = new Timer();
                audioRecordTimer.schedule(new AudioRecordTask(), duration_ms);
            } else {
                Log.i("SpeakerCountTask", "Out of time period.");
            }
        }
    }

    /** This timer is nested inside the SpeakerCountTask. It is called after "duration_ms" recording and executes speak counting */
    private class AudioRecordTask extends TimerTask {
        @Override
        public void run() {
            // stop audio recording
            Intent audioRecordIntent = new Intent(SpeakerCountService.this, AudioRecordService.class);
            stopService(audioRecordIntent);
            end = Now.getTimeOfDay();
            recording = false;

            // get location information
            if (location.equals("On")) {
                loc.getLocation();
                if (loc.canGetLocation()) {
                    latitude = loc.getLatitude();
                    longitude = loc.getLongitude();
                } else {
                    latitude = -1;
                    longitude = -1;
                }
                loc.stopUsingGPS();
            }

            // generate the MFCC and pitch feature data
            try {
                Yin.writeFile(wavFile);
                Log.i("SpeakerCountTask", "Finish YIN");
                MFCC.writeFile(wavFile);
                Log.i("SpeakerCountTask", "Finish MFCC");
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
            String[] tst_files = new String[2];
            tst_files[0] = wavFile + ".jstk.mfcc.txt";
            tst_files[1] = wavFile + ".YIN.pitch.txt";

            // semisupervised speaker counting with owner's calibration data 
            if (Constants.calibration()) {
                String[] cal_files = new String[2];
                cal_files[0] = HomeFragment.calWavFile + ".jstk.mfcc.txt";
                cal_files[1] = HomeFragment.calWavFile + ".YIN.pitch.txt";
                try {
                    double rv[] = SpeakerCount.semisupervised(tst_files, cal_files);
                    speaker_count = (int) rv[0];
                    percentage = rv[1];
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            // unsupervised speaker counting without calibration data 
            else {
                try {
                    speaker_count = SpeakerCount.unsupervised(tst_files);
                    percentage = -1;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (!Constants.service_raw_keep) {
                FileProcess.deleteFile(wavFile);
            }
            if (!Constants.service_feature_keep) {
                FileProcess.deleteFile(tst_files[0]);
                FileProcess.deleteFile(tst_files[1]);
            }
            Log.i("SpeakerCount", Integer.toString(speaker_count));

            // log the service record 
            if (Constants.log) {
                Intent bIntent = registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
                String log = wavFile + "\tDate:\t" + date + "\tstart:\t" + start + "\tend:\t" + end
                        + "\tspeaker count:\t" + Integer.toString(speaker_count) + "\tspeech percentage:\t"
                        + Double.toString(percentage) + "\tinterval (min):\t" + interval_min + "\tduration (min):\t"
                        + duration_min + "\tlatitude:\t" + Double.toString(latitude) + "\tlongitude:\t"
                        + Double.toString(longitude) + "\tbattery:\t"
                        + Float.toString(PhoneStatus.getBatteryLevel(bIntent)) + "\n";
                File logFile = new File(serviceDir, "/" + "log.txt");
                FileOutputStream fos;
                try {
                    fos = new FileOutputStream(logFile, true);
                    fos.write(log.getBytes());
                    fos.close();
                    Log.i("SpeakerCountTask", log);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            // insert the record into the social diary table
            sys_time = System.currentTimeMillis();
            mDatabase.insertDiary(mDB, sys_time, date, start, end, speaker_count, percentage, latitude, longitude);

            // upload the database after the first speaker counting task done every day
            if (upload.equals("On")) {
                if (debug) {
                    Log.i("Upload", "Begin");
                    new S3PutDataBaseTask().execute();
                    Log.i("Upload", "Finish");
                }
                if (!curr_date.equals(Now.getDate())) {
                    Log.i("Upload", "Begin");
                    new S3PutDataBaseTask().execute();
                    Log.i("Upload", "Finish");
                    curr_date = Now.getDate();
                }
            }
        }
    }

    /** Put the database into Amazon S3. */
    private class S3PutDataBaseTask extends AsyncTask<String, String, Integer> {

        protected void onPreExecute() {

        }

        protected Integer doInBackground(String... params) {
            File dbFile = new File(getApplicationContext().getDatabasePath(DataBaseHelper.dbName).toString());
            try {
                PutObjectRequest por = new PutObjectRequest(Constants.calBucket, Constants.dbName, dbFile);
                s3Client.putObject(por);
            } catch (Exception exception) {
                Log.e("Upload", "Error");
                return 0;
            }
            return 1;
        }

        protected void onPostExecute(Integer result) {

        }
    }

    @Override
    public void onDestroy() {
        Log.i("Crowd++", "Service stop...");
        Toast.makeText(this, "Crowd++ service stop...", Toast.LENGTH_SHORT).show();
        NotificationManager manager2 = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
        manager2.cancelAll();
        if (recording) {
            Intent intent = new Intent(SpeakerCountService.this, AudioRecordService.class);
            stopService(intent);
            audioRecordTimer.cancel();
            FileProcess.deleteFile(wavFile);
            Log.i("AudioRecordTask", "Cancel");
        }
        speakerCountTimer.cancel();
        Log.i("SpeakerCountTask", "Cancel");

        wl.release();
        if (mDB != null) {
            mDB.close();
        }
        if (mDatabase != null) {
            mDatabase.close();
        }
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

}