package com.asp.radiorake.recording;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import com.commonsware.cwac.wakeful.WakefulIntentService;
import com.asp.radiorake.NotificationHelper;
import com.asp.radiorake.RadioApplication;
import com.asp.radiorake.RadioDetails;
import com.asp.radiorake.filehandling.M3uHandler;
import com.asp.radiorake.filehandling.PlsHandler;
import com.asp.radiorake.utils.StringUtils;
import com.aspillai.R;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Calendar;
import java.util.GregorianCalendar;
public class RecorderService extends WakefulIntentService {
private static final String TAG = "com.asp.radiorake.RecorderService";
private FileOutputStream fileOutputStream;
private InputStream inputStream;
private static boolean recordingState = false;
private static boolean cancelRecordingFlag = false;
public RecorderService() {
super("RecorderService");
}
@Override
protected void doWakefulWork(Intent intent) {
Bundle bundle = intent.getExtras();
RadioApplication radioApplication = (RadioApplication) getApplication();
RadioDetails radioDetails = bundle.getParcelable(getString(R.string.radio_details_key));
if (!android.os.Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
// Cannot write to SDCARD, so stuffed!
String error = "Failed to record " + radioDetails.getStationName() + " cannot write to SD Card";
Notification errorNotification = NotificationHelper.getNotification(this, NotificationHelper.NOTIFICATION_RECORDING_ID, radioDetails, error, error, Notification.FLAG_ONLY_ALERT_ONCE);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(NotificationHelper.NOTIFICATION_RECORDING_ID, errorNotification);
updateActivity(error);
Log.e(TAG, error);
return;
}
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager.getActiveNetworkInfo() == null || !connectivityManager.getActiveNetworkInfo().isConnected()) {
// No network connection
String error = "Failed to record " + radioDetails.getStationName() + ", no network available";
Notification errorNotification = NotificationHelper.getNotification(this, NotificationHelper.NOTIFICATION_RECORDING_ID, radioDetails, error, error, Notification.FLAG_ONLY_ALERT_ONCE);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(NotificationHelper.NOTIFICATION_RECORDING_ID, errorNotification);
updateActivity(error);
Log.e(TAG, error);
return;
}
// SDCARD must be writable and network available, so here we go...
if (radioDetails.getPlaylistUrl().endsWith(".pls") || radioDetails.getPlaylistUrl().endsWith(".m3u")) {
if (radioDetails.getPlaylistUrl().endsWith(".pls")) {
radioDetails = PlsHandler.parse(radioDetails, getApplicationContext().getFilesDir().getPath());
} else {
radioDetails = M3uHandler.parse(radioDetails, this.getApplicationContext().getFilesDir().getPath());
}
} else {
radioDetails.setStreamUrl(radioDetails.getPlaylistUrl());
}
CharSequence ticketText = new StringBuilder()
.append(getString(R.string.recording_string))
.append(" ")
.append(radioDetails.getStationName())
.toString();
Notification notification = NotificationHelper.getNotification(this, NotificationHelper.NOTIFICATION_RECORDING_ID, radioDetails, ticketText, ticketText, Notification.FLAG_ONGOING_EVENT);
startForeground(NotificationHelper.NOTIFICATION_RECORDING_ID, notification);
updateActivity(ticketText.toString());
String recFolder = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + getString(R.string.app_name);
if (!new File(recFolder).exists()) {
if (!(new File(recFolder).mkdir())) {
//Failed to create dir, so have to quit
String error = "Failed to record " + radioDetails.getStationName() + " cannot create directory to store recordings";
Notification errorNotification = NotificationHelper.getNotification(this, NotificationHelper.NOTIFICATION_RECORDING_ID, radioDetails, error, error, Notification.FLAG_ONLY_ALERT_ONCE);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(NotificationHelper.NOTIFICATION_RECORDING_ID, errorNotification);
updateActivity(error);
return;
}
Log.d(TAG, "Recordio directory was not found, so created it");
}
StringBuilder outputSource = new StringBuilder()
.append(recFolder)
.append(File.separator);
if (!StringUtils.IsNullOrEmpty(radioDetails.getStationName())) {
outputSource.append(radioDetails.getStationName())
.append("-");
}
outputSource.append(getTimestamp())
.append(".mp3");
Log.d(TAG, "Writing stream to : " + outputSource);
WifiManager wm = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
WifiManager.WifiLock wifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL, "MyWifiLock");
if (!wifiLock.isHeld()) {
wifiLock.acquire();
}
radioApplication.setRecordingStation(radioDetails);
try {
byte[] buffer = new byte[4096];
URLConnection url = new URL(radioDetails.getStreamUrl()).openConnection();
inputStream = url.getInputStream();
fileOutputStream = new FileOutputStream(outputSource.toString());
recordingState = true;
long endTime = radioDetails.getDuration() > 0 ? System.currentTimeMillis() + radioDetails.getDuration() : 0;
record(radioDetails, outputSource.toString(), buffer, endTime);
Log.d(TAG, "Finished writing stream");
updateActivity("");
} catch (MalformedURLException e) {
Log.e(TAG, "Uri malformed: " + e.getMessage(), e);
} catch (IOException e) {
Log.e(TAG, "IOException: " + e.getMessage(), e);
// Expected when stream closes
} finally {
try {
if (inputStream != null) {
inputStream.close();
inputStream = null;
}
if (fileOutputStream != null) {
fileOutputStream.flush();
fileOutputStream.close();
fileOutputStream = null;
}
wifiLock.release();
recordingState = false;
cancelRecordingFlag = false;
} catch (IOException e) {
Log.e(TAG, "Error flushing and close output stream", e);
}
}
}
private void record(RadioDetails radioDetails, String outputSource, byte[] buffer, long endTime) {
try {
int len;
URLConnection url = new URL(radioDetails.getStreamUrl()).openConnection();
inputStream = url.getInputStream();
fileOutputStream = new FileOutputStream(outputSource, true);
if (endTime > 0) {
Log.d(TAG, "Starting timed recording for " + radioDetails.getStreamUrl());
while (!cancelRecordingFlag && (System.currentTimeMillis() < endTime) && (len = inputStream.read(buffer)) > 0) {
fileOutputStream.write(buffer, 0, len);
}
} else {
Log.d(TAG, "Starting manual recording for " + radioDetails.getStreamUrl());
while (!cancelRecordingFlag && (len = inputStream.read(buffer)) > 0) {
fileOutputStream.write(buffer, 0, len);
}
}
} catch (IOException ignored) {
try {
// 1 second delay
Thread.sleep(1000);
} catch (InterruptedException ignored2) {
Log.d(TAG, "Sleep interrupted");
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onLowMemory() {
super.onDestroy();
Log.d(TAG, "onLowMemory called");
}
private String getTimestamp() {
Calendar calendar = new GregorianCalendar();
StringBuilder timestamp = new StringBuilder();
timestamp.append(calendar.get(Calendar.YEAR));
timestamp.append(("."));
// As months are 0 indexed + 1
timestamp.append(StringUtils.pad(calendar.get(Calendar.MONTH) + 1));
timestamp.append(("."));
timestamp.append(StringUtils.pad(calendar.get(Calendar.DAY_OF_MONTH)));
timestamp.append(("-"));
timestamp.append(StringUtils.pad(calendar.get(Calendar.HOUR_OF_DAY)));
timestamp.append(("."));
timestamp.append(StringUtils.pad(calendar.get(Calendar.MINUTE)));
timestamp.append(("."));
timestamp.append(StringUtils.pad(calendar.get(Calendar.SECOND)));
return timestamp.toString();
}
public static boolean alreadyRecording() {
return recordingState;
}
public static void cancelRecording() {
Log.d(TAG, "Cancel recording stream");
cancelRecordingFlag = true;
}
private void updateActivity(String text) {
Intent intent = new Intent(getString(R.string.player_service_update_playing_key));
((RadioApplication) getApplication()).setRecordingStatus(text);
getApplicationContext().sendBroadcast(intent);
}
}