Home | History | Annotate | Download | only in observers
      1 /*
      2 // Copyright(c)2014 IntelCorporation
      3 //
      4 // LicensedundertheApacheLicense,Version2.0(the"License");
      5 // youmaynotusethisfileexceptincompliancewiththeLicense.
      6 // YoumayobtainacopyoftheLicenseat
      7 //
      8 // http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unlessrequiredbyapplicablelaworagreedtoinwriting,software
     11 // distributedundertheLicenseisdistributedonan"ASIS"BASIS,
     12 // WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
     13 // SeetheLicenseforthespecificlanguagegoverningpermissionsand
     14 // limitationsundertheLicense.
     15 */
     16 #ifdef TARGET_HAS_MULTIPLE_DISPLAY
     17 #include <HwcTrace.h>
     18 #include <binder/IServiceManager.h>
     19 #include <Hwcomposer.h>
     20 #include <DisplayAnalyzer.h>
     21 #include <ExternalDevice.h>
     22 #endif
     23 
     24 #include <MultiDisplayObserver.h>
     25 
     26 namespace android {
     27 namespace intel {
     28 
     29 #ifdef TARGET_HAS_MULTIPLE_DISPLAY
     30 
     31 ////// MultiDisplayCallback
     32 
     33 MultiDisplayCallback::MultiDisplayCallback(MultiDisplayObserver *dispObserver)
     34     : mDispObserver(dispObserver),
     35       mVideoState(MDS_VIDEO_STATE_UNKNOWN)
     36 {
     37 }
     38 
     39 MultiDisplayCallback::~MultiDisplayCallback()
     40 {
     41     CTRACE();
     42     mDispObserver = NULL;
     43 }
     44 
     45 status_t MultiDisplayCallback::blankSecondaryDisplay(bool blank)
     46 {
     47     ITRACE("blank: %d", blank);
     48     mDispObserver->blankSecondaryDisplay(blank);
     49     return NO_ERROR;
     50 }
     51 
     52 status_t MultiDisplayCallback::updateVideoState(int sessionId, MDS_VIDEO_STATE state)
     53 {
     54     mVideoState = state;
     55     ITRACE("state: %d", state);
     56     mDispObserver->updateVideoState(sessionId, state);
     57     return NO_ERROR;
     58 }
     59 
     60 status_t MultiDisplayCallback::setHdmiTiming(const MDSHdmiTiming& timing)
     61 {
     62     mDispObserver->setHdmiTiming(timing);
     63     return NO_ERROR;
     64 }
     65 
     66 status_t MultiDisplayCallback::updateInputState(bool state)
     67 {
     68     //ITRACE("input state: %d", state);
     69     mDispObserver->updateInputState(state);
     70     return NO_ERROR;
     71 }
     72 
     73 status_t MultiDisplayCallback::setHdmiScalingType(MDS_SCALING_TYPE type)
     74 {
     75     ITRACE("scaling type: %d", type);
     76     // Merrifield doesn't implement this API
     77     return INVALID_OPERATION;
     78 }
     79 
     80 status_t MultiDisplayCallback::setHdmiOverscan(int hValue, int vValue)
     81 {
     82     ITRACE("oversacn compensation, h: %d v: %d", hValue, vValue);
     83     // Merrifield doesn't implement this API
     84     return INVALID_OPERATION;
     85 }
     86 
     87 ////// MultiDisplayObserver
     88 
     89 MultiDisplayObserver::MultiDisplayObserver()
     90     : mMDSCbRegistrar(NULL),
     91       mMDSInfoProvider(NULL),
     92       mMDSConnObserver(NULL),
     93       mMDSDecoderConfig(NULL),
     94       mMDSCallback(NULL),
     95       mLock(),
     96       mCondition(),
     97       mThreadLoopCount(0),
     98       mDeviceConnected(false),
     99       mExternalHdmiTiming(false),
    100       mInitialized(false)
    101 {
    102     CTRACE();
    103 }
    104 
    105 MultiDisplayObserver::~MultiDisplayObserver()
    106 {
    107     WARN_IF_NOT_DEINIT();
    108 }
    109 
    110 bool MultiDisplayObserver::isMDSRunning()
    111 {
    112     // Check if Multi Display service is running
    113     sp<IServiceManager> sm = defaultServiceManager();
    114     if (sm == NULL) {
    115         ETRACE("fail to get service manager!");
    116         return false;
    117     }
    118 
    119     sp<IBinder> service = sm->checkService(String16(INTEL_MDS_SERVICE_NAME));
    120     if (service == NULL) {
    121         VTRACE("fail to get MultiDisplay service!");
    122         return false;
    123     }
    124 
    125     return true;
    126 }
    127 
    128 bool MultiDisplayObserver::initMDSClient()
    129 {
    130     sp<IServiceManager> sm = defaultServiceManager();
    131     if (sm == NULL) {
    132         ETRACE("Fail to get service manager");
    133         return false;
    134     }
    135     sp<IMDService> mds = interface_cast<IMDService>(
    136             sm->getService(String16(INTEL_MDS_SERVICE_NAME)));
    137     if (mds == NULL) {
    138         ETRACE("Fail to get MDS service");
    139         return false;
    140     }
    141     mMDSCbRegistrar = mds->getCallbackRegistrar();
    142     if (mMDSCbRegistrar.get() == NULL) {
    143         ETRACE("failed to create mds base Client");
    144         return false;
    145     }
    146 
    147     mMDSCallback = new MultiDisplayCallback(this);
    148     if (mMDSCallback.get() == NULL) {
    149         ETRACE("failed to create MultiDisplayCallback");
    150         deinitMDSClient();
    151         return false;
    152     }
    153     mMDSInfoProvider = mds->getInfoProvider();
    154     if (mMDSInfoProvider.get() == NULL) {
    155         ETRACE("failed to create mds video Client");
    156         return false;
    157     }
    158 
    159     mMDSConnObserver = mds->getConnectionObserver();
    160     if (mMDSConnObserver.get() == NULL) {
    161         ETRACE("failed to create mds video Client");
    162         return false;
    163     }
    164     mMDSDecoderConfig = mds->getDecoderConfig();
    165     if (mMDSDecoderConfig.get() == NULL) {
    166         ETRACE("failed to create mds decoder Client");
    167         return false;
    168     }
    169 
    170     status_t ret = mMDSCbRegistrar->registerCallback(mMDSCallback);
    171     if (ret != NO_ERROR) {
    172         ETRACE("failed to register callback");
    173         deinitMDSClient();
    174         return false;
    175     }
    176 
    177     Drm *drm = Hwcomposer::getInstance().getDrm();
    178     mDeviceConnected = drm->isConnected(IDisplayDevice::DEVICE_EXTERNAL);
    179     ITRACE("MDS client is initialized");
    180     return true;
    181 }
    182 
    183 void MultiDisplayObserver::deinitMDSClient()
    184 {
    185     if (mMDSCallback.get() && mMDSCbRegistrar.get()) {
    186         mMDSCbRegistrar->unregisterCallback(mMDSCallback);
    187     }
    188 
    189     mDeviceConnected = false;
    190     mMDSCbRegistrar = NULL;
    191     mMDSInfoProvider = NULL;
    192     mMDSCallback = NULL;
    193     mMDSConnObserver = NULL;
    194     mMDSDecoderConfig = NULL;
    195 }
    196 
    197 bool MultiDisplayObserver::initMDSClientAsync()
    198 {
    199     if (mThread.get()) {
    200         WTRACE("working thread has been already created.");
    201         return true;
    202     }
    203 
    204     mThread = new MDSClientInitThread(this);
    205     if (mThread.get() == NULL) {
    206         ETRACE("failed to create MDS client init thread");
    207         return false;
    208     }
    209     mThreadLoopCount = 0;
    210     // TODO: check return value
    211     mThread->run("MDSClientInitThread", PRIORITY_URGENT_DISPLAY);
    212     return true;
    213 }
    214 
    215 bool MultiDisplayObserver::initialize()
    216 {
    217     bool ret = true;
    218     Mutex::Autolock _l(mLock);
    219 
    220     if (mInitialized) {
    221         WTRACE("display observer has been initialized");
    222         return true;
    223     }
    224 
    225     // initialize MDS client once. This should succeed if MDS service starts
    226     // before surfaceflinger service is started.
    227     // if surface flinger runs first, MDS client will be initialized asynchronously in
    228     // a working thread
    229     if (isMDSRunning()) {
    230         if (!initMDSClient()) {
    231             ETRACE("failed to initialize MDS client");
    232             // FIXME: NOT a common case for system server crash.
    233             // Start a working thread to initialize MDS client if exception happens
    234             ret = initMDSClientAsync();
    235         }
    236     } else {
    237         ret = initMDSClientAsync();
    238     }
    239 
    240     mInitialized = true;
    241     return ret;
    242 }
    243 
    244 void MultiDisplayObserver::deinitialize()
    245 {
    246     sp<MDSClientInitThread> detachedThread;
    247     do {
    248         Mutex::Autolock _l(mLock);
    249 
    250         if (mThread.get()) {
    251             mCondition.signal();
    252             detachedThread = mThread;
    253             mThread = NULL;
    254         }
    255         mThreadLoopCount = 0;
    256         deinitMDSClient();
    257         mInitialized = false;
    258     } while (0);
    259 
    260     if (detachedThread.get()) {
    261         detachedThread->requestExitAndWait();
    262         detachedThread = NULL;
    263     }
    264 }
    265 
    266 bool MultiDisplayObserver::threadLoop()
    267 {
    268     Mutex::Autolock _l(mLock);
    269 
    270     // try to create MDS client in the working thread
    271     // multiple delayed attempts are made until MDS service starts.
    272 
    273     // Return false if MDS service is running or loop limit is reached
    274     // such that thread becomes inactive.
    275     if (isMDSRunning()) {
    276         if (!initMDSClient()) {
    277             ETRACE("failed to initialize MDS client");
    278         }
    279         return false;
    280     }
    281 
    282     if (mThreadLoopCount++ > THREAD_LOOP_BOUND) {
    283         ETRACE("failed to initialize MDS client, loop limit reached");
    284         return false;
    285     }
    286 
    287     status_t err = mCondition.waitRelative(mLock, milliseconds(THREAD_LOOP_DELAY));
    288     if (err != -ETIMEDOUT) {
    289         ITRACE("thread is interrupted");
    290         return false;
    291     }
    292 
    293     return true; // keep trying
    294 }
    295 
    296 
    297 status_t MultiDisplayObserver::blankSecondaryDisplay(bool blank)
    298 {
    299     // blank secondary display
    300     Hwcomposer::getInstance().getDisplayAnalyzer()->postBlankEvent(blank);
    301     return 0;
    302 }
    303 
    304 status_t MultiDisplayObserver::updateVideoState(int sessionId, MDS_VIDEO_STATE state)
    305 {
    306     Hwcomposer::getInstance().getDisplayAnalyzer()->postVideoEvent(
    307         sessionId, (int)state);
    308     return 0;
    309 }
    310 
    311 status_t MultiDisplayObserver::setHdmiTiming(const MDSHdmiTiming& timing)
    312 {
    313     drmModeModeInfo mode;
    314     mode.hdisplay = timing.width;
    315     mode.vdisplay = timing.height;
    316     mode.vrefresh = timing.refresh;
    317     mode.flags = timing.flags;
    318     ITRACE("timing to set: %dx%d@%dHz", timing.width, timing.height, timing.refresh);
    319     ExternalDevice *dev =
    320         (ExternalDevice *)Hwcomposer::getInstance().getDisplayDevice(HWC_DISPLAY_EXTERNAL);
    321     if (dev) {
    322         dev->setDrmMode(mode);
    323     }
    324 
    325     mExternalHdmiTiming = true;
    326     return 0;
    327 }
    328 
    329 status_t MultiDisplayObserver::updateInputState(bool active)
    330 {
    331     Hwcomposer::getInstance().getDisplayAnalyzer()->postInputEvent(active);
    332     return 0;
    333 }
    334 
    335 
    336 /// Public interfaces
    337 
    338 status_t MultiDisplayObserver::notifyHotPlug( bool connected)
    339 {
    340     {
    341         // lock scope
    342         Mutex::Autolock _l(mLock);
    343         if (mMDSConnObserver.get() == NULL) {
    344             return NO_INIT;
    345         }
    346 
    347         if (connected == mDeviceConnected) {
    348             WTRACE("hotplug event ignored");
    349             return NO_ERROR;
    350         }
    351 
    352         // clear it after externel device is disconnected
    353         if (!connected) mExternalHdmiTiming = false;
    354 
    355         mDeviceConnected = connected;
    356     }
    357     return mMDSConnObserver->updateHdmiConnectionStatus(connected);
    358 }
    359 
    360 status_t MultiDisplayObserver::getVideoSourceInfo(int sessionID, VideoSourceInfo* info)
    361 {
    362     Mutex::Autolock _l(mLock);
    363     if (mMDSInfoProvider.get() == NULL) {
    364         return NO_INIT;
    365     }
    366 
    367     if (info == NULL) {
    368         ETRACE("invalid parameter");
    369         return UNKNOWN_ERROR;
    370     }
    371 
    372     MDSVideoSourceInfo videoInfo;
    373     memset(&videoInfo, 0, sizeof(MDSVideoSourceInfo));
    374     status_t ret = mMDSInfoProvider->getVideoSourceInfo(sessionID, &videoInfo);
    375     if (ret == NO_ERROR) {
    376         info->width     = videoInfo.displayW;
    377         info->height    = videoInfo.displayH;
    378         info->frameRate = videoInfo.frameRate;
    379         info->isProtected = videoInfo.isProtected;
    380         VTRACE("Video Session[%d] source info: %dx%d@%d", sessionID,
    381                 info->width, info->height, info->frameRate);
    382     }
    383     return ret;
    384 }
    385 
    386 int MultiDisplayObserver::getVideoSessionNumber()
    387 {
    388     Mutex::Autolock _l(mLock);
    389     if (mMDSInfoProvider.get() == NULL) {
    390         return 0;
    391     }
    392 
    393     return mMDSInfoProvider->getVideoSessionNumber();
    394 }
    395 
    396 bool MultiDisplayObserver::isExternalDeviceTimingFixed() const
    397 {
    398     Mutex::Autolock _l(mLock);
    399     return mExternalHdmiTiming;
    400 }
    401 
    402 status_t MultiDisplayObserver::notifyWidiConnectionStatus( bool connected)
    403 {
    404     Mutex::Autolock _l(mLock);
    405     if (mMDSConnObserver.get() == NULL) {
    406         return NO_INIT;
    407     }
    408     return mMDSConnObserver->updateWidiConnectionStatus(connected);
    409 }
    410 
    411 status_t MultiDisplayObserver::setDecoderOutputResolution(
    412         int sessionID,
    413         int32_t width, int32_t height,
    414         int32_t offX, int32_t offY,
    415         int32_t bufWidth, int32_t bufHeight)
    416 {
    417     Mutex::Autolock _l(mLock);
    418     if (mMDSDecoderConfig.get() == NULL) {
    419         return NO_INIT;
    420     }
    421     if (width <= 0 || height <= 0 ||
    422             offX < 0 || offY < 0 ||
    423             bufWidth <= 0 || bufHeight <= 0) {
    424         ETRACE(" Invalid parameter: %dx%d, %dx%d, %dx%d", width, height, offX, offY, bufWidth, bufHeight);
    425         return UNKNOWN_ERROR;
    426     }
    427 
    428     status_t ret = mMDSDecoderConfig->setDecoderOutputResolution(sessionID, width, height, offX, offY, bufWidth, bufHeight);
    429     if (ret == NO_ERROR) {
    430         ITRACE("Video Session[%d] output resolution %dx%d ", sessionID, width, height);
    431     }
    432     return ret;
    433 }
    434 
    435 
    436 #endif //TARGET_HAS_MULTIPLE_DISPLAY
    437 
    438 } // namespace intel
    439 } // namespace android
    440