Home | History | Annotate | Download | only in tvinput
      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.TvContract;
     24 import android.media.tv.TvInputService;
     25 import android.util.Log;
     26 
     27 import com.google.android.exoplayer.audio.AudioCapabilities;
     28 import com.google.android.exoplayer.audio.AudioCapabilitiesReceiver;
     29 import com.android.tv.TvApplication;
     30 import com.android.tv.common.feature.CommonFeatures;
     31 import com.android.tv.tuner.exoplayer.buffer.BufferManager;
     32 import com.android.tv.tuner.exoplayer.buffer.TrickplayStorageManager;
     33 import com.android.tv.tuner.util.SystemPropertiesProxy;
     34 
     35 import java.util.Collections;
     36 import java.util.Set;
     37 import java.util.WeakHashMap;
     38 import java.util.concurrent.TimeUnit;
     39 
     40 /**
     41  * {@link TunerTvInputService} serves TV channels coming from a tuner device.
     42  */
     43 public class TunerTvInputService extends TvInputService
     44         implements AudioCapabilitiesReceiver.Listener{
     45     private static final String TAG = "TunerTvInputService";
     46     private static final boolean DEBUG = false;
     47 
     48     private static final String MAX_BUFFER_SIZE_KEY = "tv.tuner.buffersize_mbytes";
     49     private static final int MAX_BUFFER_SIZE_DEF = 2 * 1024;  // 2GB
     50     private static final int MIN_BUFFER_SIZE_DEF = 256;  // 256MB
     51     private static final int DVR_STORAGE_CLEANUP_JOB_ID = 100;
     52 
     53     // WeakContainer for {@link TvInputSessionImpl}
     54     private final Set<TunerSession> mTunerSessions = Collections.newSetFromMap(new WeakHashMap<>());
     55     private ChannelDataManager mChannelDataManager;
     56     private AudioCapabilitiesReceiver mAudioCapabilitiesReceiver;
     57     private AudioCapabilities mAudioCapabilities;
     58     private BufferManager mBufferManager;
     59 
     60     @Override
     61     public void onCreate() {
     62         TvApplication.setCurrentRunningProcess(this, false);
     63         super.onCreate();
     64         if (DEBUG) Log.d(TAG, "onCreate");
     65         mChannelDataManager = new ChannelDataManager(getApplicationContext());
     66         mAudioCapabilitiesReceiver = new AudioCapabilitiesReceiver(getApplicationContext(), this);
     67         mAudioCapabilitiesReceiver.register();
     68         mBufferManager = createBufferManager();
     69         if (CommonFeatures.DVR.isEnabled(this)) {
     70             JobScheduler jobScheduler =
     71                     (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
     72             JobInfo pendingJob = jobScheduler.getPendingJob(DVR_STORAGE_CLEANUP_JOB_ID);
     73             if (pendingJob != null) {
     74                 // storage cleaning job is already scheduled.
     75             } else {
     76                 JobInfo job = new JobInfo.Builder(DVR_STORAGE_CLEANUP_JOB_ID,
     77                         new ComponentName(this, TunerStorageCleanUpService.class))
     78                         .setPersisted(true).setPeriodic(TimeUnit.DAYS.toMillis(1)).build();
     79                 jobScheduler.schedule(job);
     80             }
     81         }
     82         if (mBufferManager == null) {
     83             Log.i(TAG, "Trickplay is disabled");
     84         } else {
     85             Log.i(TAG, "Trickplay is enabled");
     86         }
     87     }
     88 
     89     @Override
     90     public void onDestroy() {
     91         if (DEBUG) Log.d(TAG, "onDestroy");
     92         super.onDestroy();
     93         mChannelDataManager.release();
     94         mAudioCapabilitiesReceiver.unregister();
     95         if (mBufferManager != null) {
     96             mBufferManager.close();
     97         }
     98     }
     99 
    100     @Override
    101     public RecordingSession onCreateRecordingSession(String inputId) {
    102         return new TunerRecordingSession(this, inputId, mChannelDataManager);
    103     }
    104 
    105     @Override
    106     public Session onCreateSession(String inputId) {
    107         if (DEBUG) Log.d(TAG, "onCreateSession");
    108         try {
    109             final TunerSession session = new TunerSession(
    110                     this, mChannelDataManager, mBufferManager);
    111             mTunerSessions.add(session);
    112             session.setAudioCapabilities(mAudioCapabilities);
    113             session.setOverlayViewEnabled(true);
    114             return session;
    115         } catch (RuntimeException e) {
    116             // There are no available DVB devices.
    117             Log.e(TAG, "Creating a session for " + inputId + " failed.", e);
    118             return null;
    119         }
    120     }
    121 
    122     @Override
    123     public void onAudioCapabilitiesChanged(AudioCapabilities audioCapabilities) {
    124         mAudioCapabilities = audioCapabilities;
    125         for (TunerSession session : mTunerSessions) {
    126             if (!session.isReleased()) {
    127                 session.setAudioCapabilities(audioCapabilities);
    128             }
    129         }
    130     }
    131 
    132     private BufferManager createBufferManager() {
    133         int maxBufferSizeMb =
    134                 SystemPropertiesProxy.getInt(MAX_BUFFER_SIZE_KEY, MAX_BUFFER_SIZE_DEF);
    135         if (maxBufferSizeMb >= MIN_BUFFER_SIZE_DEF) {
    136             return new BufferManager(
    137                     new TrickplayStorageManager(getApplicationContext(), getCacheDir(),
    138                             1024L * 1024 * maxBufferSizeMb));
    139         }
    140         return null;
    141     }
    142 
    143     public static String getInputId(Context context) {
    144         return TvContract.buildInputId(new ComponentName(context, TunerTvInputService.class));
    145     }
    146 }
    147