Java tutorial
/** DR Radio 2 is developed by Jacob Nordfalk, Hanafi Mughrabi and Frederik Aagaard. Some parts of the code are loosely based on Sveriges Radio Play for Android. DR Radio 2 for Android is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. DR Radio 2 for Android 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 DR Radio 2 for Android. If not, see <http://www.gnu.org/licenses/>. */ package dk.dr.radio.afspilning; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; import android.appwidget.AppWidgetManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.media.AudioManager; import android.media.AudioManager.OnAudioFocusChangeListener; import android.media.MediaPlayer; import android.media.RingtoneManager; import android.net.Uri; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.os.Build; import android.os.Handler; import android.os.PowerManager; import android.os.Vibrator; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import com.android.volley.Request; import com.android.volley.VolleyError; import org.json.JSONObject; import java.util.ArrayList; import java.util.Date; import java.util.List; import dk.dr.radio.afspilning.wrapper.AndroidMediaPlayerWrapper; import dk.dr.radio.afspilning.wrapper.ExoPlayerWrapper; import dk.dr.radio.afspilning.wrapper.MediaPlayerLytter; import dk.dr.radio.afspilning.wrapper.MediaPlayerWrapper; import dk.dr.radio.data.DRData; import dk.dr.radio.data.Kanal; import dk.dr.radio.data.Lydkilde; import dk.dr.radio.data.Lydstream; import dk.dr.radio.data.Playlisteelement; import dk.dr.radio.data.Udsendelse; import dk.dr.radio.diverse.App; import dk.dr.radio.diverse.Log; import dk.dr.radio.net.volley.DrVolleyResonseListener; import dk.dr.radio.net.volley.DrVolleyStringRequest; import dk.dr.radio.v3.R; import dk.dr.radio.vaekning.AlarmAlertWakeLock; /** * @author j */ public class Afspiller { private final GemiusStatistik gemiusStatistik; class Afspillerlyd { MediaPlayer start; MediaPlayer fejl; MediaPlayer spiller; MediaPlayer stop; MediaPlayer forbinder; { start = MediaPlayer.create(App.instans, R.raw.afspiller_start); stop = MediaPlayer.create(App.instans, R.raw.afspiller_stop); forbinder = MediaPlayer.create(App.instans, R.raw.afspiller_forbinder); fejl = MediaPlayer.create(App.instans, R.raw.afspiller_fejl); spiller = MediaPlayer.create(App.instans, R.raw.afspiller_spiller); } } Afspillerlyd afspillerlyd; boolean afspillerlyde = false; public Status afspillerstatus = Status.STOPPET; // Burde vre en del af afspillerstatus private boolean afspilningPPause; private MediaPlayerWrapper mediaPlayer; private MediaPlayerLytter lytter = new MediaPlayerLytterImpl(); public List<Runnable> observatrer=new ArrayList<Runnable>(); public List<Runnable> forbindelseobservatrer=new ArrayList<Runnable>(); public List<Runnable> positionsobservatrer=new ArrayList<Runnable>(); private Lydstream lydstream; private int forbinderProcent; private Lydkilde lydkilde; public boolean vkningIGang; public PowerManager.WakeLock vkkeurWakeLock; AudioManager audioManager = (AudioManager) App.instans.getSystemService(Context.AUDIO_SERVICE); private static void stMediaPlayerLytter(MediaPlayerWrapper mediaPlayer, MediaPlayerLytter lytter) { mediaPlayer.setMediaPlayerLytter(lytter); if (lytter != null) { // http://developer.android.com/guide/topics/media/mediaplayer.html#wakelocks if (App.prefs.getBoolean("cpuls", true)) mediaPlayer.setWakeMode(App.instans,PowerManager.PARTIAL_WAKE_LOCK); } } private WifiLock wifilock = null; /** * Forudstter DRData er initialiseret */ public Afspiller() { mediaPlayer = AndroidMediaPlayerWrapper.opret(); stMediaPlayerLytter(mediaPlayer, this.lytter); // Indls gamle vrdier s vi har nogle... // Fjernet. Skulle ikke vre ndvendigt. Jacob 22/10-2011 // kanalNavn = p.getString("kanalNavn", "P1"); // lydUrl = p.getString("lydUrl", "rtsp://live-rtsp.dr.dk/rtplive/_definst_/Channel5_LQ.stream"); /* // Gem vrdi hvis den ikke findes, sdan at indstillingsskrm viser det rigtige if (!App.prefs.contains(NGLEholdSkrmTndt)) { // Xperia Play har brug for at holde skrmen tndt. Muligvis ogs andre.... boolean holdSkrmTndt = "R800i".equals(Build.MODEL); App.prefs.edit().putBoolean(NGLEholdSkrmTndt, holdSkrmTndt).commit(); } */ wifilock = ((WifiManager) App.instans.getSystemService(Context.WIFI_SERVICE)).createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "DR Radio"); wifilock.setReferenceCounted(false); Opkaldshaandtering opkaldshndtering = new Opkaldshaandtering(this); TelephonyManager tm = (TelephonyManager) App.instans.getSystemService(Context.TELEPHONY_SERVICE); tm.listen(opkaldshndtering, PhoneStateListener.LISTEN_CALL_STATE); /* // Opret en baggrundstrd med en Handler til at sende Runnables ind i new Thread() { public void run() { Looper.prepare(); baggrundstrd = new Handler(); Looper.loop(); } }.start(); */ if (App.fejlsgning) tjekLydAktiv.run(); gemiusStatistik = new GemiusStatistik(); } private int onErrorTller; private long onErrorTllerNultid; public void startAfspilning() { if (lydkilde.hentetStream == null && !App.erOnline()) { App.kortToast(R.string.Internetforbindelse_mangler); if (vkningIGang) ringDenAlarm(); return; } if (!lydkilde.harStreams()) { Request<?> req = new DrVolleyStringRequest(lydkilde.getStreamsUrl(), new DrVolleyResonseListener() { @Override public void fikSvar(String json, boolean fraCache, boolean undret) throws Exception { if (undret) return; // ingen grund til at parse det igen JSONObject o = new JSONObject(json); lydkilde.setStreams(o); Log.d("hentStreams afsp fraCache=" + fraCache + " => " + lydkilde); if (onErrorTller++>2) { App.kortToast(R.string.Kunne_ikke_oprette_forbindelse_til_DR); //Log.rapporterFejl(new Exception("onErrorTller++>10, uendelig lkke afvrget"), lydkilde); if (vkningIGang) ringDenAlarm(); } else { startAfspilning(); // Opdatr igen - men kun n gang } } @Override protected void fikFejl(VolleyError error) { App.kortToast(R.string.Kunne_ikke_oprette_forbindelse_til_DR); if (vkningIGang) ringDenAlarm(); super.fikFejl(error); } }) { public Priority getPriority() { return Priority.IMMEDIATE; }};App.volleyRequestQueue.add(req);return;}Log.d("startAfspilning() "+lydkilde); onErrorTller=0;onErrorTllerNultid=System.currentTimeMillis(); if(afspillerstatus==Status.STOPPET){App.fjernbetjening.registrr(); //opdaterNotification(); // Start afspillerservicen s programmet ikke bliver lukket // nr det krer i baggrunden under afspilning App.instans.startService(new Intent(App.instans,HoldAppIHukommelsenService.class));if(App.prefs.getBoolean("wifils",true)&&wifilock!=null){wifilock.acquire();} if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.FROYO){ // Se http://developer.android.com/training/managing-audio/audio-focus.html int result = audioManager.requestAudioFocus(getOnAudioFocusChangeListener(), AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);Log.d("requestAudioFocus res="+result);if(result==AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { App.fjernbetjening.registrr(); }}startAfspilningIntern(); // Skru op til 1/5 styrke hvis volumen er lavere end det tjekVolumenMindst5tedele(1); }else Log.d(" forkert status="+afspillerstatus); // Hvis det er en favorit s opdater favoritter s der ikke mere optrder nye udsendelser i denne programserie if(lydkilde instanceof Udsendelse){ String programserieSlug = ((Udsendelse) lydkilde).programserieSlug;if(DRData.instans.favoritter.erFavorit(programserieSlug)) { DRData.instans.favoritter.stFavorit(programserieSlug, true); } } afspillerlyde=App.prefs.getBoolean("afspillerlyde",false);if(afspillerlyde&&afspillerlyd==null)afspillerlyd=new Afspillerlyd();if(afspillerlyde)afspillerlyd.start.start();} /** Srg for at volumen er skruet op til en minimumsvrdi, angivet i 5'tedele af fuld styrke */ public void tjekVolumenMindst5tedele(int min5) { int max = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); int nu = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); if (nu < min5 * max / 5) { audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, min5 * max / 5, AudioManager.FLAG_SHOW_UI); } } /** * Typen er OnAudioFocusChangeListener, men da den ikke findes i API<8 kan vi ikke bruge klassen her */ Object onAudioFocusChangeListener; /** * Responding to the loss of audio focus */ @SuppressLint("NewApi") private OnAudioFocusChangeListener getOnAudioFocusChangeListener() { if (onAudioFocusChangeListener == null) onAudioFocusChangeListener = new OnAudioFocusChangeListener() { //private int lydstyreFrDuck = -1; @TargetApi(Build.VERSION_CODES.FROYO) public void onAudioFocusChange(int focusChange) { Log.d("onAudioFocusChange " + focusChange); AudioManager am = (AudioManager) App.instans.getSystemService(Context.AUDIO_SERVICE); switch (focusChange) { // Kommer ved f.eks. en SMS eller taleinstruktion i Google Maps case (AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK): Log.d("JPER duck"); if (afspillerstatus != Status.STOPPET) { // Vi 'dukker' lyden mens den vigtigere lyd hres // St lydstyrken ned til en 1/3-del //lydstyreFrDuck = am.getStreamVolume(AudioManager.STREAM_MUSIC); //am.setStreamVolume(AudioManager.STREAM_MUSIC, (lydstyreFrDuck + 2) / 3, 0); mediaPlayer.setVolume(0.1f, 0.1f); // logaritmisk skala - 0.1 svarer til 1/3-del } break; // Dette sker ved f.eks. opkald case (AudioManager.AUDIOFOCUS_LOSS_TRANSIENT): Log.d("JPER pause"); if (afspillerstatus != Status.STOPPET) { pauseAfspilning(); // stter afspilningPPause=false if (afspillerlyde) afspillerlyd.stop.start(); afspilningPPause = true; } break; // Dette sker hvis en anden app med lyd startes, f.eks. et spil case (AudioManager.AUDIOFOCUS_LOSS): Log.d("JPER stop"); stopAfspilning(); am.abandonAudioFocus(this); break; // Dette sker nr opkaldet er slut og ved f.eks. opkald case (AudioManager.AUDIOFOCUS_GAIN): Log.d("JPER Gain"); if (afspillerstatus == Status.STOPPET) { if (afspilningPPause) startAfspilningIntern(); } else { // Genskab lydstyrke fr den blev dukket mediaPlayer.setVolume(1f, 1f); //if (lydstyreFrDuck > 0) { // am.setStreamVolume(AudioManager.STREAM_MUSIC, lydstyreFrDuck, 0); //} // Genstart ikke afspilning, der spilles allerede! //startAfspilningIntern(); } } } }; return (OnAudioFocusChangeListener) onAudioFocusChangeListener; } long setDataSourceTid = 0; boolean setDataSourceLyd = false; private String mpTils() { AudioManager ar = (AudioManager) App.instans.getSystemService(App.AUDIO_SERVICE); //return mediaPlayer.getCurrentPosition()+ "/"+mediaPlayer.getDuration() + " "+mediaPlayer.isPlaying()+ar.isMusicActive(); if (!setDataSourceLyd && ar.isMusicActive()) { setDataSourceLyd = true; String str = "Det tog " + (System.currentTimeMillis() - setDataSourceTid) / 100 / 10.0 + " sek fr lyden kom"; Log.d(str); if (App.fejlsgning) { App.langToast(str); } } return " " + ar.isMusicActive() + " dt=" + (System.currentTimeMillis() - setDataSourceTid) + "ms"; } synchronized private void startAfspilningIntern() { afspillerstatus = Status.FORBINDER; afspilningPPause = false; sendOnAfspilningForbinder(-1); opdaterObservatrer(); handler.removeCallbacks(startAfspilningIntern); // mediaPlayer.setDataSource() br kaldes fra en baggrundstrd da det kan ske // at den hnger under visse netvrksforhold new Thread() { public void run() { setDataSourceTid = System.currentTimeMillis(); setDataSourceLyd = false; try { List<Lydstream> bs = lydkilde.findBedsteStreams(false); if (bs.size() == 0) { Log.rapporterFejl(new IllegalStateException("Ingen passende lydUrl for " + lydkilde)); App.kortToast(R.string.Kunne_ikke_oprette_forbindelse_til_DR); return; } lydstream = bs.get(0); gemiusStatistik.setLydkilde(lydkilde); DRData.instans.senestLyttede.registrrLytning(lydkilde); Log.d("mediaPlayer.setDataSource( " + lydstream); mediaPlayer.setDataSource(lydstream.url); Log.d("mediaPlayer.setDataSource() slut"); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); Log.d("mediaPlayer.setDataSource() slut " + mpTils()); mediaPlayer.prepare(); Log.d("mediaPlayer.prepare() slut " + mpTils()); } catch (Exception ex) { if (!App.PRODUKTION) Log.rapporterFejl(ex); else Log.e("Fejl for lyd-stream " + lydstream, ex); //ex = new Exception("spiller "+kanalNavn+" "+lydUrl, ex); //Log.kritiskFejlStille(ex); handler.post(new Runnable() { public void run() { // Stop afspilleren fra forgrundstrden. Jacob 14/11 lytter.onError(null, 42, 42); // kalder stopAfspilning(); og forsger igen senere og melder fejl til bruger efter 10 forsg } }); } } }.start(); } synchronized private void pauseAfspilningIntern() { handler.removeCallbacks(startAfspilningIntern); // Da mediaPlayer.reset() erfaringsmssigt kan hnge i dette tilflde afregistrerer vi // alle lyttere og bruger en ny final MediaPlayerWrapper gammelMediaPlayer = mediaPlayer; stMediaPlayerLytter(gammelMediaPlayer, null); // afregistrr alle lyttere new Thread() { @Override public void run() { try { try { // Ignorr IllegalStateException, det er fordi den allerede er stoppet gammelMediaPlayer.stop(); } catch (IllegalStateException e) { } Log.d("P gammelMediaPlayer.reset() "+gammelMediaPlayer); gammelMediaPlayer.reset(); Log.d("P gammelMediaPlayer.release()"); gammelMediaPlayer.release(); Log.d("P gammelMediaPlayer frdig"); } catch (IllegalStateException e) { e.printStackTrace(); } catch (Exception e) { Log.rapporterFejl(e); } } }.start(); mediaPlayer = AndroidMediaPlayerWrapper.opret(); stMediaPlayerLytter(mediaPlayer, this.lytter); // registrr lyttere p den nye instans afspillerstatus = Status.STOPPET; afspilningPPause = false; opdaterObservatrer(); } synchronized public void pauseAfspilning() { int pos = gemPosition(); pauseAfspilningIntern(); if (wifilock != null) wifilock.release(); gemiusStatistik.registrHndelse(GemiusStatistik.PlayerAction.Pause, pos / 1000); if (vkkeurWakeLock != null) { vkkeurWakeLock.release(); vkkeurWakeLock = null; } } /** * Gem position - og spol herhen nste gang udsendelsen spiller */ private int gemPosition() { if (!lydkilde.erDirekte() && afspillerstatus == Status.SPILLER) { int pos = mediaPlayer.getCurrentPosition(); if (pos > 0) { //senestLyttet.getUdsendelse().startposition = pos; Log.d("senestLyttede.stStartposition("+lydkilde+" , "+pos); DRData.instans.senestLyttede.stStartposition(lydkilde, pos); } return pos; } return 0; } synchronized public void stopAfspilning() { Log.d("Afspiller stopAfspilning"); gemiusStatistik.registrHndelse(GemiusStatistik.PlayerAction.Stopped, getCurrentPosition() / 1000); gemPosition(); pauseAfspilningIntern(); if (wifilock != null) wifilock.release(); // Stop afspillerservicen App.instans.stopService(new Intent(App.instans, HoldAppIHukommelsenService.class)); if (vkkeurWakeLock != null) { vkkeurWakeLock.release(); vkkeurWakeLock = null; } if (afspillerlyde) afspillerlyd.stop.start(); vkningIGang = false; App.fjernbetjening.afregistrr(); } public void setLydkilde(Lydkilde lydkilde) { Log.d("setLydkilde(" + lydkilde); if (lydkilde == this.lydkilde) return; if (lydkilde == null) { Log.rapporterFejl(new IllegalStateException("setLydkilde(null")); return; } if (lydkilde instanceof Kanal && Kanal.P4kode.equals(((Kanal) lydkilde).kode)) { // TODO - fjern tjek 9.okt 2014 // Nrmere fix for https://www.bugsense.com/dashboard/project/cd78aa05/errors/820758400 Log.rapporterFejl(new IllegalStateException("setLydkilde(P4F")); // return; // Nyt fix - vi vlger bare en underkanal. String kanalkode = App.tjekP4OgVlgUnderkanal(((Kanal) lydkilde).kode); lydkilde = DRData.instans.grunddata.kanalFraKode.get(kanalkode); } // TODO konsistenstjek - fjern efter et par mneder i drift (dec 2014) if (lydkilde.hentetStream==null && lydkilde instanceof Udsendelse) { DRData.instans.hentedeUdsendelser.tjekOmHentet((Udsendelse) lydkilde); if (lydkilde.hentetStream!=null) { Log.rapporterFejl(new IllegalStateException("Sen opdagelse af hentet udsendelse "), lydkilde); } } if ((afspillerstatus == Status.SPILLER) || (afspillerstatus == Status.FORBINDER)) { pauseAfspilning(); // gemmer lydkildens position this.lydkilde = lydkilde; try { startAfspilning(); // stter afspilleren til den nye lydkildes position } catch (Exception e) { Log.rapporterFejl(e); // TODO fjern efter et par mneder i drift (nov 2014) } } else { this.lydkilde = lydkilde; } opdaterObservatrer(); } private void opdaterObservatrer() { AppWidgetManager mAppWidgetManager = AppWidgetManager.getInstance(App.instans); int[] appWidgetId = mAppWidgetManager.getAppWidgetIds(new ComponentName(App.instans, AfspillerIkonOgNotifikation.class)); for (int id : appWidgetId) { AfspillerIkonOgNotifikation.opdaterUdseende(App.instans, mAppWidgetManager, id); } // Notificr alle i observatrlisen - fra en kopi, sdan at de kan fjerne // sig selv fra listen uden at det giver ConcurrentModificationException for (Runnable observatr : new ArrayList<Runnable>(observatrer)) { observatr.run(); } } public Status getAfspillerstatus() { return afspillerstatus; } public int getForbinderProcent() { return forbinderProcent; } public Lydkilde getLydkilde() { return lydkilde; } Handler handler = new Handler(); Runnable startAfspilningIntern=new Runnable(){public void run(){startAfspilningIntern();}}; Runnable venterPAtKommeOnline = new Runnable() { @Override public void run() { App.netvrk.observatrer.remove(venterPAtKommeOnline); //if (afspillerstatus==Status.STOPPET) return; // Spiller ikke if (lydkilde.hentetStream != null) return; // Offline afspilning - ignorr try { if (!App.erOnline()) Log.e(new IllegalStateException("Burde vre online her??!")); long dt = System.currentTimeMillis() - onErrorTllerNultid; Log.d("Vi kom online igen efter " + dt + " ms"); if (dt < 5 * 60 * 1000) { Log.d("Genstart afspilning"); startAfspilningIntern(); // Genstart } else { Log.d("Brugeren har nok glemt os, afslut"); stopAfspilning(); } } catch (Exception e) { Log.rapporterFejl(e); } } }; private void sendOnAfspilningForbinder(int procent) { forbinderProcent = procent; for (Runnable runnable : forbindelseobservatrer) { runnable.run(); } } /** Flyt til position (i millisekunder) */ public void seekTo(int offsetMs) { Log.d("afspiler seekTo " + offsetMs); mediaPlayer.seekTo(offsetMs); gemiusStatistik.registrHndelse(GemiusStatistik.PlayerAction.Seeking, offsetMs / 1000); for (Runnable runnable : positionsobservatrer) { runnable.run(); } } /** Lngde i millisekunder */ public int getDuration() { if (afspillerstatus == Status.SPILLER) return mediaPlayer.getDuration(); return 0; } /** Position i millisekunder */ public int getCurrentPosition() { if (afspillerstatus == Status.SPILLER) return mediaPlayer.getCurrentPosition(); return 0; } public void forrige() { if (lydkilde.erDirekte()) { Kanal k = lydkilde.getKanal(); // Skift til forrige kanal if (k.p4underkanal) k = DRData.instans.grunddata.kanalFraKode.get(Kanal.P4kode); // P4 overkanal int index = DRData.instans.grunddata.kanaler.indexOf(k) - 1; if (index < 0) index = DRData.instans.grunddata.kanaler.size() - 1; k = DRData.instans.grunddata.kanaler.get(index); if (k.p4underkanal) { // Vi er kommet til P4 - vlg brugerens foretrukne underkanal k = DRData.instans.grunddata.kanalFraKode.get(App.tjekP4OgVlgUnderkanal(Kanal.P4kode)); } setLydkilde(k); return; } Udsendelse u = lydkilde.getUdsendelse(); if (u == null) return; int posMs = getCurrentPosition(); // spol hen til sang, der var 10 sekunder fr denne // TODO hvis posMs<0, skal der s skiftes til forrige udsendelse/lytning? int index = u.findPlaylisteElemTilTid(posMs-10000, 0); if (index < 0) { // Skift 5% af udsendelsens varighed posMs = posMs - getDuration()*5/100; if (posMs<0) posMs=0; seekTo(posMs); return; } Playlisteelement pl = u.playliste.get(index); if (posMs-10000 < pl.offsetMs) seekTo(0); // Fr fste sang else seekTo(pl.offsetMs); } public void nste() { if (lydkilde.erDirekte()) { // Skift til nste kanal Kanal k = lydkilde.getKanal(); int index = DRData.instans.grunddata.kanaler.indexOf(k) + 1; if (index == DRData.instans.grunddata.kanaler.size()) index = 0; while (k.p4underkanal && DRData.instans.grunddata.kanaler.get(index).p4underkanal) index++; // skip underkanaler k = DRData.instans.grunddata.kanaler.get(index); // Tjek om vi er kommet til P4 - vlg brugerens foretrukne underkanal String kanalkode = App.tjekP4OgVlgUnderkanal(k.kode); k = DRData.instans.grunddata.kanalFraKode.get(kanalkode); if (k==null) { Log.rapporterFejl(new IllegalStateException( "nste() fra "+lydkilde.getKanal().kode+" gav null i="+index+" kk="+kanalkode)); return; } setLydkilde(k); return; } Udsendelse u = lydkilde.getUdsendelse(); if (u == null) return; int posMs = getCurrentPosition(); int index = u.findPlaylisteElemTilTid(posMs, 0); if (index < 0) { // Skift 5% af udsendelsens varighed posMs = posMs + getDuration()*5/100; if (posMs>getDuration()) pauseAfspilning(); else seekTo(posMs); return; } if (index + 1 == u.playliste.size()) return; // TODO nste udsendelse? Playlisteelement pl = u.playliste.get(index + 1); seekTo(pl.offsetMs); } // // TILBAGEKALD FRA MEDIAPLAYER // class MediaPlayerLytterImpl implements MediaPlayerLytter { public void onPrepared(MediaPlayer mp) { Log.d("onPrepared " + mpTils()); afspillerstatus = Status.SPILLER; //No longer buffering opdaterObservatrer(); // Det ser ud til kaldet til start() kan tage lang tid p Android 4.1 Jelly Bean // (i hvert fald p Samsung Galaxy S III), s vi kalder det i baggrunden new Thread() { public void run() { try { // Fix for https://www.bugsense.com/dashboard/project/cd78aa05/errors/825188032 Log.d("mediaPlayer.start() " + mpTils()); int startposition = DRData.instans.senestLyttede.getStartposition(lydkilde); int varighed = mediaPlayer.getDuration(); Log.d("mediaPlayer genoptager afspilning ved " + startposition + " varighed="+varighed); if (varighed>0 && startposition>0.95*varighed) { Log.d("mediaPlayer nej, det er for langt henne, starter ved starten"); startposition = 0; } gemiusStatistik.registrHndelse(GemiusStatistik.PlayerAction.Play, startposition / 1000); if (startposition > 0) { if (mediaPlayer instanceof ExoPlayerWrapper) { Log.d("exoplayer.seekTo() er slet fra - TODO fix"); //TODO fix } else { mediaPlayer.seekTo(startposition); } } mediaPlayer.start(); if (afspillerlyde) afspillerlyd.spiller.start(); Log.d("mediaPlayer.start() slut " + mpTils()); Thread.sleep(5000); // Vent lidt fr data sendes if (App.netvrk.erOnline()) { gemiusStatistik.startSendData(); } // Ellers venter vi, det kan vre vi er heldige at brugeren er online ved nste hndelse } catch (Exception e) { Log.rapporterFejl(e); } } }.start(); } public void onCompletion(MediaPlayer mp_UBRUGT) { Log.d("AfspillerService onCompletion!"); // Hvis forbindelsen mistes kommer der en onCompletion() og vi er derfor // ndt til at genstarte, medmindre brugeren trykkede stop if (afspillerstatus == Status.SPILLER) { mediaPlayer.stop(); // mediaPlayer.reset(); // Da mediaPlayer.reset() erfaringsmssigt kan hnge i dette tilflde afregistrerer vi // alle lyttere og bruger en ny final MediaPlayerWrapper gammelMediaPlayer = mediaPlayer; stMediaPlayerLytter(gammelMediaPlayer, null); // afregistrr alle lyttere new Thread() { public void run() { try { Log.d("COMPL gammelMediaPlayer.reset() "+gammelMediaPlayer); gammelMediaPlayer.reset(); Log.d("COMPL gammelMediaPlayer.release()"); gammelMediaPlayer.release(); Log.d("COMPL gammelMediaPlayer.release()"); } catch (Exception e) { Log.d(e); } } }.start(); if (lydkilde.erDirekte()) { Log.d("Genstarter afspilning!"); mediaPlayer = AndroidMediaPlayerWrapper.opret(); stMediaPlayerLytter(mediaPlayer, this); // registrr lyttere p den nye instans startAfspilningIntern(); if (afspillerlyde) afspillerlyd.forbinder.start(); } else { DRData.instans.senestLyttede.stStartposition(lydkilde, 0); gemiusStatistik.registrHndelse(GemiusStatistik.PlayerAction.Completed, getCurrentPosition() / 1000); stopAfspilning(); } } } public boolean onError(MediaPlayer mp_UBRUGT, int hvad, int extra) { //Log.d("onError(" + MedieafspillerInfo.fejlkodeTilStreng(hvad) + "(" + hvad + ") " + extra+ " onErrorTller="+onErrorTller); Log.d("onError(" + hvad + ") " + extra + " onErrorTller=" + onErrorTller); if (vkningIGang) { ringDenAlarm(); return true; } if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN && hvad == MediaPlayer.MEDIA_ERROR_UNKNOWN && "GT-I9300".equals(Build.MODEL) && mediaPlayer.isPlaying()) { // Ignorer, da Samsung Galaxy SIII p Android 4.1 Jelly Bean // sender denne fejl (onError(1) -110) men i vrigt spiller fint videre! return true; } // Iflg http://developer.android.com/guide/topics/media/index.html : // "It's important to remember that when an error occurs, the MediaPlayer moves to the Error // state and you must reset it before you can use it again." if (afspillerstatus == Status.SPILLER || afspillerstatus == Status.FORBINDER) { // Hvis der har vret // 1) frre end 10 fejl eller // 2) der hjest er 1 fejl pr 20 sekunder s prv igen long dt = System.currentTimeMillis() - onErrorTllerNultid; if (onErrorTller++ < (App.fejlsgning ? 2 : 10) || (dt / onErrorTller > 20000)) { pauseAfspilningIntern(); //mediaPlayer.stop(); //mediaPlayer.reset(); if (App.erOnline()) { // Vi venter lngere og lngere tid her int n = onErrorTller; if (n > 11) n = 11; int ventetid = 10 + 5 * (1 << n); // fra n=0:10 msek til n=10:5 sek til max n=11:10 sek Log.d("Ventetid fr vi prver igen: " + ventetid + " n=" + n + " " + onErrorTller); handler.postDelayed(startAfspilningIntern, ventetid); } else { Log.d("Vent p at vi kommer online igen"); onErrorTllerNultid = System.currentTimeMillis(); App.netvrk.observatrer.add(venterPAtKommeOnline); if (afspillerlyde) afspillerlyd.fejl.start(); } } else { pauseAfspilning(); // Vi giver op efter 10. forsg App.langToast(R.string.Beklager_kan_ikke_spille_radio); App.langToast(R.string.Tjek_din_internetforbindelse_og___); if (afspillerlyde) afspillerlyd.fejl.start(); } } else { mediaPlayer.reset(); } return true; } public void onBufferingUpdate(MediaPlayer mp, int procent) { if (App.fejlsgning) Log.d("Afspiller onBufferingUpdate : " + procent + " " + mpTils()); Log.d("Afspiller onBufferingUpdate : " + procent); if (procent < -100) procent = -1; // Ignorr vilde tal sendOnAfspilningForbinder(procent); } public void onSeekComplete(MediaPlayer mp) { Log.d("AfspillerService onSeekComplete"); //opdaterObservatrer(); } } Runnable tjekLydAktiv=new Runnable(){@Override public void run(){App.forgrundstrd.removeCallbacks(this);Log.d("tjekLydAktiv "+audioManager.isMusicActive()+" "+mediaPlayer.isPlaying()+" "+getCurrentPosition()+" "+getDuration()+" "+new Date());App.forgrundstrd.postDelayed(this,10000);}}; void ringDenAlarm() { Uri alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM); if (alert == null) { // alert is null, using backup alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); if (alert == null) { // I can't see this ever being null (as always have a default notification) but just incase // alert backup is null, using 2nd backup alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE); } } lydkilde = new AlarmLydkilde(alert.toString(), lydkilde); handler.postDelayed(startAfspilningIntern, 100); vibru(4000); } private void vibru(int ms) { Log.d("vibru " + ms); try { Vibrator vibrator = (Vibrator) App.instans.getSystemService(Activity.VIBRATOR_SERVICE); vibrator.vibrate(ms); // Tenu telefonon veka por 1/2a sekundo AlarmAlertWakeLock.createPartialWakeLock(App.instans).acquire(500); } catch (Exception e) { e.printStackTrace(); } } public String toString() { return afspillerstatus + " " + lydstream.toString(); } }