1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tv.tuner.tvinput; 18 19 import android.app.job.JobInfo; 20 import android.app.job.JobScheduler; 21 import android.content.ComponentName; 22 import android.content.Context; 23 import android.media.tv.TvInputService; 24 import android.util.Log; 25 import com.android.tv.common.feature.CommonFeatures; 26 import com.google.android.exoplayer.audio.AudioCapabilities; 27 import com.google.android.exoplayer.audio.AudioCapabilitiesReceiver; 28 import java.util.Collections; 29 import java.util.Set; 30 import java.util.WeakHashMap; 31 import java.util.concurrent.TimeUnit; 32 33 /** {@link BaseTunerTvInputService} serves TV channels coming from a tuner device. */ 34 public class BaseTunerTvInputService extends TvInputService 35 implements AudioCapabilitiesReceiver.Listener { 36 private static final String TAG = "BaseTunerTvInputService"; 37 private static final boolean DEBUG = false; 38 39 private static final int DVR_STORAGE_CLEANUP_JOB_ID = 100; 40 41 // WeakContainer for {@link TvInputSessionImpl} 42 private final Set<TunerSession> mTunerSessions = Collections.newSetFromMap(new WeakHashMap<>()); 43 private ChannelDataManager mChannelDataManager; 44 private AudioCapabilitiesReceiver mAudioCapabilitiesReceiver; 45 private AudioCapabilities mAudioCapabilities; 46 47 @Override 48 public void onCreate() { 49 if (getApplicationContext().getSystemService(Context.TV_INPUT_SERVICE) == null) { 50 Log.wtf(TAG, "Stopping because device does not have a TvInputManager"); 51 this.stopSelf(); 52 return; 53 } 54 super.onCreate(); 55 if (DEBUG) Log.d(TAG, "onCreate"); 56 mChannelDataManager = new ChannelDataManager(getApplicationContext()); 57 mAudioCapabilitiesReceiver = new AudioCapabilitiesReceiver(getApplicationContext(), this); 58 mAudioCapabilitiesReceiver.register(); 59 if (CommonFeatures.DVR.isEnabled(this)) { 60 JobScheduler jobScheduler = 61 (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); 62 JobInfo pendingJob = jobScheduler.getPendingJob(DVR_STORAGE_CLEANUP_JOB_ID); 63 if (pendingJob != null) { 64 // storage cleaning job is already scheduled. 65 } else { 66 JobInfo job = 67 new JobInfo.Builder( 68 DVR_STORAGE_CLEANUP_JOB_ID, 69 new ComponentName(this, TunerStorageCleanUpService.class)) 70 .setPersisted(true) 71 .setPeriodic(TimeUnit.DAYS.toMillis(1)) 72 .build(); 73 jobScheduler.schedule(job); 74 } 75 } 76 } 77 78 @Override 79 public void onDestroy() { 80 if (DEBUG) Log.d(TAG, "onDestroy"); 81 super.onDestroy(); 82 mChannelDataManager.release(); 83 mAudioCapabilitiesReceiver.unregister(); 84 } 85 86 @Override 87 public RecordingSession onCreateRecordingSession(String inputId) { 88 return new TunerRecordingSession(this, inputId, mChannelDataManager); 89 } 90 91 @Override 92 public Session onCreateSession(String inputId) { 93 if (DEBUG) Log.d(TAG, "onCreateSession"); 94 try { 95 // TODO(b/65445352): Support multiple TunerSessions for multiple tuners 96 if (!allSessionsReleased()) { 97 Log.d(TAG, "abort creating an session"); 98 return null; 99 } 100 final TunerSession session = new TunerSession(this, mChannelDataManager); 101 mTunerSessions.add(session); 102 session.setAudioCapabilities(mAudioCapabilities); 103 session.setOverlayViewEnabled(true); 104 return session; 105 } catch (RuntimeException e) { 106 // There are no available DVB devices. 107 Log.e(TAG, "Creating a session for " + inputId + " failed.", e); 108 return null; 109 } 110 } 111 112 @Override 113 public void onAudioCapabilitiesChanged(AudioCapabilities audioCapabilities) { 114 mAudioCapabilities = audioCapabilities; 115 for (TunerSession session : mTunerSessions) { 116 if (!session.isReleased()) { 117 session.setAudioCapabilities(audioCapabilities); 118 } 119 } 120 } 121 122 private boolean allSessionsReleased() { 123 for (TunerSession session : mTunerSessions) { 124 if (!session.isReleased()) { 125 return false; 126 } 127 } 128 return true; 129 } 130 } 131