static void handle_uevent(hwc_context_t* ctx, const char* udata, int len)
{
    int vsync = 0;
    int64_t timestamp = 0;
    const char *str = udata;
    bool usecopybit = false;
    int compositionType =
        qdutils::QCCompositionType::getInstance().getCompositionType();

    if (compositionType & (qdutils::COMPOSITION_TYPE_DYN |
                           qdutils::COMPOSITION_TYPE_MDP |
                           qdutils::COMPOSITION_TYPE_C2D)) {
        usecopybit = true;
    }
    if(!strcasestr("change@/devices/virtual/switch/hdmi", str) &&
       !strcasestr("change@/devices/virtual/switch/wfd", str)) {
        ALOGD_IF(UEVENT_DEBUG, "%s: Not Ext Disp Event ", __FUNCTION__);
        return;
    }
    int connected = -1; // initial value - will be set to  1/0 based on hotplug
    int extDpyNum = HWC_DISPLAY_EXTERNAL;
    char property[PROPERTY_VALUE_MAX];
    if((property_get("persist.sys.wfd.virtual", property, NULL) > 0) &&
            (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
             (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
        // This means we are using Google API to trigger WFD Display
        extDpyNum = HWC_DISPLAY_VIRTUAL;

    }

    int dpy = isHDMI(str) ? HWC_DISPLAY_EXTERNAL : extDpyNum;

    // parse HDMI/WFD switch state for connect/disconnect
    // for HDMI:
    // The event will be of the form:
    // change@/devices/virtual/switch/hdmi ACTION=change
    // SWITCH_STATE=1 or SWITCH_STATE=0
    while(*str) {
        if (!strncmp(str, "SWITCH_STATE=", strlen("SWITCH_STATE="))) {
            connected = atoi(str + strlen("SWITCH_STATE="));
            //Disabled until SF calls unblank
            ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive = false;
            //Ignored for Virtual Displays
            //ToDo: we can do this in a much better way
            ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = true;
            break;
        }
        str += strlen(str) + 1;
        if (str - udata >= len)
            break;
    }
    ALOGD_IF(UEVENT_DEBUG, "Received str:%s",udata);

    if(connected != EXTERNAL_ONLINE) {
        if(ctx->mExtDisplay->ignoreRequest(udata)) {
            ALOGD_IF(UEVENT_DEBUG,"No need to process this connection request"
                                  "str:%s",udata);
           ctx->dpyAttr[dpy].isActive = true;
           return;
        }
    }

    // update extDpyNum
    ctx->mExtDisplay->setExtDpyNum(dpy);
    switch(connected) {
        case EXTERNAL_OFFLINE:
            {   // disconnect event
                const char *s1 = udata + strlen(HWC_UEVENT_SWITCH_STR);
                if(!strncmp(s1,"hdmi",strlen(s1))) {
                    ctx->mExtDisplay->teardownHDMIDisplay();
                }else if(!strncmp(s1,"wfd",strlen(s1))) {
                    ctx->mExtDisplay->teardownWFDDisplay();
                }
                Locker::Autolock _l(ctx->mExtLock);
                clear(ctx, dpy);
                ALOGD("%s sending hotplug: connected = %d and dpy:%d",
                      __FUNCTION__, connected, dpy);
                ctx->dpyAttr[dpy].connected = false;

                //hwc comp could be on
                if(dpy != HWC_DISPLAY_VIRTUAL)
                    ctx->proc->hotplug(ctx->proc, dpy, connected);

                break;
            }
        case EXTERNAL_ONLINE:
            {   // connect case
                {
                    //Force composition to give up resources like pipes and
                    //close fb. For example if assertive display is going on,
                    //fb2 could be open, thus connecting Layer Mixer#0 to
                    //WriteBack module. If HDMI attempts to open fb1, the driver
                    //will try to attach Layer Mixer#0 to HDMI INT, which will
                    //fail, since Layer Mixer#0 is still connected to WriteBack.
                    //This block will force composition to close fb2 in above
                    //example.
                    Locker::Autolock _l(ctx->mExtLock);
                    ctx->mExtDispConfiguring = true;
                    ctx->dpyAttr[dpy].connected = false;
                    ctx->proc->invalidate(ctx->proc);
                }
                //2 cycles for slower content
                usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
                        * 2 / 1000);
                const char *s1 = udata + strlen(HWC_UEVENT_SWITCH_STR);
                if(!strncmp(s1,"hdmi",strlen(s1))) {
                    // hdmi online event..!
                    // check if WFD is configured
                    if(ctx->mExtDisplay->isWFDActive()) {
                        ALOGD_IF(UEVENT_DEBUG,"Received HDMI connection request"
                                "when WFD is active");
                        // teardown Active WFD Display
                        ctx->mExtDisplay->teardownWFDDisplay();
                        {
                            Locker::Autolock _l(ctx->mExtLock);
                            clear(ctx, dpy);
                            //send hotplug disconnect event
                            ALOGD_IF(UEVENT_DEBUG, "sending hotplug: disconnect"
                                    "for WFD");
                        }
                        //Invalidate
                        ctx->proc->invalidate(ctx->proc);
                        //wait for 1 second
                        ALOGE_IF(UEVENT_DEBUG, "wait for 1 second -- padding"
                                "round");
                        sleep(1);
                    }
                    ctx->mExtDisplay->configureHDMIDisplay();
                } else if(!strncmp(s1,"wfd",strlen(s1))) {
                    // wfd online event..!
                    ctx->mExtDisplay->configureWFDDisplay();
                }

                {
                    Locker::Autolock _l(ctx->mExtLock);
                    ctx->dpyAttr[dpy].isPause = false;
                    setup(ctx, dpy, usecopybit);
                    ALOGD("%s sending hotplug: connected = %d", __FUNCTION__,
                            connected);
                    ctx->dpyAttr[dpy].connected = true;
                    if(dpy != HWC_DISPLAY_VIRTUAL)
                        ctx->proc->hotplug(ctx->proc, dpy, connected);
                }

                break;
            }
        case EXTERNAL_PAUSE:
            {   // pause case
                ALOGD("%s Received Pause event",__FUNCTION__);
                Locker::Autolock _l(ctx->mExtLock);
                ctx->dpyAttr[dpy].isActive = true;
                ctx->dpyAttr[dpy].isPause = true;
                break;
            }
        case EXTERNAL_RESUME:
            {  // resume case
                ALOGD("%s Received resume event",__FUNCTION__);
                //Treat Resume as Online event
                //Since external didnt have any pipes, force primary to give up
                //its pipes; we don't allow inter-mixer pipe transfers.
                {
                    Locker::Autolock _l(ctx->mExtLock);
                    ctx->mExtDispConfiguring = true;
                    ctx->dpyAttr[dpy].isActive = true;
                    ctx->proc->invalidate(ctx->proc);
                }
                usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
                        * 2 / 1000);
                //At this point external has all the pipes it would need.
                {
                    Locker::Autolock _l(ctx->mExtLock);
                    ctx->dpyAttr[dpy].isPause = false;
                    ctx->proc->invalidate(ctx->proc);
                }
                break;
            }
        default:
            {
                ALOGE("ignore event and connected:%d",connected);
                break;
            }
    }
}
Пример #2
0
bool CAESinkIntelSMD::Initialize(AEAudioFormat &format, std::string &device)
{
  VERBOSE2();

  CLog::Log(LOGDEBUG, "%s: device: %s, data format: %s, sample rate: %d, channel count: %d, frame size: %d", __DEBUG_ID__, device.c_str(), CAEUtil::DataFormatToStr(format.m_dataFormat), format.m_sampleRate, format.m_channelLayout.Count(), format.m_frameSize);

  CSingleLock lock(m_SMDAudioLock);

  bool bIsHDMI = isHDMI(device);
  bool bIsSPDIF = isSPDIF(device);
  bool bIsAnalog = isAnalog(device);
  int deviceType = getDeviceType(device);

  ismd_result_t result;
  AEDataFormat inputDataFormat = format.m_dataFormat;

  bool bSPDIFPassthrough = false;
  bool bHDMIPassthrough = false;
  bool bIsRawCodec = AE_IS_RAW(inputDataFormat);

  format.m_sampleRate = getOutputSampleRate(deviceType, format.m_sampleRate);
  format.m_dataFormat = getAEDataFormat(deviceType, format.m_dataFormat, format.m_frameSize);

  int channels = format.m_channelLayout.Count();
  // can not support more than 2 channels on anything other than HDMI
  if (channels > 2 && (bIsSPDIF || bIsAnalog))
    channels = 2;
  // support for more than 8 channels not supported
  else if (channels > 8)
    channels = 8;


  ismd_audio_processor_t  audioProcessor = -1;
  ismd_audio_format_t     ismdAudioInputFormat = ISMD_AUDIO_MEDIA_FMT_INVALID;

  audioProcessor = g_IntelSMDGlobals.GetAudioProcessor();
  if(audioProcessor == -1)
  {
    CLog::Log(LOGERROR, "%s audioProcessor is not valid", __DEBUG_ID__);
    return false;
  }

  // disable all outputs
  g_IntelSMDGlobals.DisableAudioOutput(g_IntelSMDGlobals.GetHDMIOutput());
  g_IntelSMDGlobals.DisableAudioOutput(g_IntelSMDGlobals.GetSPDIFOutput());
  g_IntelSMDGlobals.DisableAudioOutput(g_IntelSMDGlobals.GetI2SOutput());

  m_audioDevice = g_IntelSMDGlobals.CreateAudioInput(false);
  if(m_audioDevice == -1)
  {
    CLog::Log(LOGERROR, "%s failed to create audio input", __DEBUG_ID__);
    return false;
  }

  g_IntelSMDGlobals.SetPrimaryAudioDevice(m_audioDevice);
  m_audioDeviceInput = g_IntelSMDGlobals.GetAudioDevicePort(m_audioDevice);
  if(m_audioDeviceInput == -1)
  {
    CLog::Log(LOGERROR, "%s failed to create audio input port", __DEBUG_ID__);
    return false;
  }

  ismdAudioInputFormat = GetISMDFormat(inputDataFormat);

  unsigned int uiBitsPerSample = CAEUtil::DataFormatToBits(format.m_dataFormat);
  unsigned int uiUsedBitsPerSample = CAEUtil::DataFormatToUsedBits(format.m_dataFormat);

  // Are we doing DD+ -> DD mode
  bool bAC3Encode = false;
  if (bIsHDMI)
  {
    unsigned int sampleRate = format.m_sampleRate;
    unsigned int bitsPerSample = uiUsedBitsPerSample;
    if (format.m_encodedRate != 0)
      sampleRate = format.m_encodedRate;

    unsigned int suggSampleRate = sampleRate;
    if (!CheckEDIDSupport(ismdAudioInputFormat, channels, suggSampleRate, bitsPerSample, bAC3Encode))
    {
      if (suggSampleRate != sampleRate)
        format.m_sampleRate = suggSampleRate;

      if (bitsPerSample != uiUsedBitsPerSample)
      {
        if (uiUsedBitsPerSample == 24)
        {
          format.m_dataFormat = AE_FMT_S24NE4;
          uiUsedBitsPerSample = bitsPerSample;
        }
        else if (uiUsedBitsPerSample == 32)
        {
          format.m_dataFormat = AE_FMT_S32LE;
          uiUsedBitsPerSample = bitsPerSample;
        }
        else
        {
          format.m_dataFormat = AE_FMT_S16LE;
          uiUsedBitsPerSample = 16;
        }
        
        uiBitsPerSample = CAEUtil::DataFormatToBits(format.m_dataFormat);
      }
      //format.m_frameSize = uiBitsPerSample/4;
    }  
  }
  else if (bIsSPDIF && ismdAudioInputFormat == ISMD_AUDIO_MEDIA_FMT_DD_PLUS && ISMD_SUCCESS == ismd_audio_codec_available((ismd_audio_format_t) ISMD_AUDIO_ENCODE_FMT_AC3))
  {
    bAC3Encode = true;
  }

  unsigned int outputSampleRate = format.m_sampleRate;
  
  // for raw codecs, send as PCM passthrough
  if (!bAC3Encode && bIsRawCodec && ismdAudioInputFormat != ISMD_AUDIO_MEDIA_FMT_DD && ismdAudioInputFormat != ISMD_AUDIO_MEDIA_FMT_TRUE_HD)
  {
    format.m_dataFormat = AE_FMT_S16NE;
    ismdAudioInputFormat = ISMD_AUDIO_MEDIA_FMT_PCM;
    bHDMIPassthrough = bSPDIFPassthrough = true;
  }

  format.m_channelLayout.Reset();
  if (bIsRawCodec)
  {
    for (int i = 0; i < channels; ++i)
      format.m_channelLayout += AE_CH_RAW;
  }
  // TODO: This currently handles Mono,Stereo, 5.1, 7.1 correctly
  // Handle the other cases (i.e. 6.1 DTS)
  else
  {
    for (int i = 0; i < channels; ++i)
      format.m_channelLayout += s_chMap[i];
  }

  //TODO: Handle non normal channel configs (3 channel, etc).
  int inputChannelConfig = AUDIO_CHAN_CONFIG_2_CH;
  if (format.m_channelLayout.Count() == 1)
    inputChannelConfig = AUDIO_CHAN_CONFIG_1_CH;
  else if (format.m_channelLayout.Count() == 6)
    inputChannelConfig = AUDIO_CHAN_CONFIG_6_CH;
  else if (format.m_channelLayout.Count() == 8)
    inputChannelConfig = AUDIO_CHAN_CONFIG_8_CH;

  format.m_frameSize = channels * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);

  // if standard audio keep buffer small so delay is short
  if (!bIsRawCodec)
  {
    // try to keep roughly 5ms buffer using multiples of a 1024 buffer size
    int numBuffers = ((0.005*((double)(format.m_sampleRate*format.m_frameSize))) / 1024.0) + 0.5;
    if (numBuffers == 0)
      numBuffers = 1;
    else if (numBuffers > 8)
      numBuffers = 8;
    m_dwChunkSize = numBuffers*1024;
  }
  else
  {
    m_dwChunkSize = 8*1024;
  }

  m_dwBufferLen = m_dwChunkSize;

  format.m_frames = m_dwChunkSize/format.m_frameSize;
  format.m_frameSamples = format.m_frames*channels;
  m_frameSize = format.m_frameSize;

  CLog::Log(LOGINFO, "%s ismdAudioInputFormat %d\n", __DEBUG_ID__,
      ismdAudioInputFormat);

  int counter = 0;
  while(counter < 5)
  {
    result = ismd_audio_input_set_data_format(audioProcessor, m_audioDevice, ismdAudioInputFormat);
    if (result != ISMD_SUCCESS)
    {
      CLog::Log(LOGERROR, "%s ismd_audio_input_set_data_format failed. retrying %d %d", __DEBUG_ID__, counter, result);
      counter++;
      usleep(1000);
    }
    else
      break;
  }
  
  switch( ismdAudioInputFormat )
  {
    case ISMD_AUDIO_MEDIA_FMT_DD:
      CLog::Log(LOGDEBUG, "%s: Initialize DD detected", __DEBUG_ID__);
      bHDMIPassthrough = bSPDIFPassthrough = true;
      break;
    case ISMD_AUDIO_MEDIA_FMT_DD_PLUS:
      CLog::Log(LOGDEBUG, "%s: Initialize DD Plus detected", __DEBUG_ID__);

      bHDMIPassthrough = true;
      // check special case for DD+->DD using DDCO 
      if(bAC3Encode)
      {
        CLog::Log(LOGDEBUG, "%s: Initialize EAC3->AC3 transcoding is on", __DEBUG_ID__);
        bHDMIPassthrough = false;
        bAC3Encode = true; 
        ConfigureDolbyPlusModes(audioProcessor, m_audioDevice, bAC3Encode);       
      }
      break;
    case ISMD_AUDIO_MEDIA_FMT_DTS:
    case ISMD_AUDIO_MEDIA_FMT_DTS_LBR:
      CLog::Log(LOGDEBUG, "%s: Initialize DTS detected", __DEBUG_ID__);
      bHDMIPassthrough = bSPDIFPassthrough = true;
      break;
    case ISMD_AUDIO_MEDIA_FMT_DTS_HD:
    case ISMD_AUDIO_MEDIA_FMT_DTS_HD_MA:
    case ISMD_AUDIO_MEDIA_FMT_DTS_HD_HRA:
      CLog::Log(LOGDEBUG, "%s: Initialize DTS-HD detected", __DEBUG_ID__);
      bHDMIPassthrough = true;
      outputSampleRate = format.m_encodedRate;
      channels = 2;
      break;
    case ISMD_AUDIO_MEDIA_FMT_TRUE_HD:
      CLog::Log(LOGDEBUG, "%s: Initialize TrueHD detected", __DEBUG_ID__);
      bHDMIPassthrough = true;
      outputSampleRate = format.m_encodedRate;
      channels = 2;
      break;
    case ISMD_AUDIO_MEDIA_FMT_PCM:
      result = ismd_audio_input_set_pcm_format(audioProcessor, m_audioDevice, uiBitsPerSample, format.m_sampleRate, inputChannelConfig);
      if (result != ISMD_SUCCESS)
      {
        CLog::Log(LOGERROR, "%s - ismd_audio_input_set_pcm_format: %d", __DEBUG_ID__, result);
    //    return false;
      }
      break;
    default:
      break;
  }
  
  
  // I2S. Nothing to touch here. we always use defaults

  // SPIDF
   if(bIsSPDIF)
   {
     ismd_audio_output_t OutputSPDIF = g_IntelSMDGlobals.GetSPDIFOutput();
     ismd_audio_output_config_t spdif_output_config;

     ConfigureAudioOutputParams(spdif_output_config, AE_DEVTYPE_IEC958, uiUsedBitsPerSample,
        outputSampleRate, channels, ismdAudioInputFormat, bSPDIFPassthrough, bAC3Encode);
     if(!g_IntelSMDGlobals.ConfigureAudioOutput(OutputSPDIF, spdif_output_config))
     {
       CLog::Log(LOGERROR, "%s ConfigureAudioOutput SPDIF failed %d", __DEBUG_ID__, result);
 //      return false;
     }
     
     //format.m_sampleRate = spdif_output_config.sample_rate;
   }

  // HDMI
  if(bIsHDMI)
  {
    ismd_audio_output_t OutputHDMI = g_IntelSMDGlobals.GetHDMIOutput();
    ismd_audio_output_config_t hdmi_output_config;
    ConfigureAudioOutputParams(hdmi_output_config, AE_DEVTYPE_HDMI, uiUsedBitsPerSample,
      outputSampleRate, channels, ismdAudioInputFormat, bHDMIPassthrough, bAC3Encode);
    if(!g_IntelSMDGlobals.ConfigureAudioOutput(OutputHDMI, hdmi_output_config))
    {
      CLog::Log(LOGERROR, "%s ConfigureAudioOutput HDMI failed %d", __DEBUG_ID__, result);
      return false;
    }
    //format.m_sampleRate = hdmi_output_config.sample_rate;
  }

  // Configure the master clock frequency

  CLog::Log(LOGINFO, "%s ConfigureMasterClock %d", __DEBUG_ID__, format.m_sampleRate);
  g_IntelSMDGlobals.ConfigureMasterClock(format.m_sampleRate);
  
  bSPDIFPassthrough = bIsSPDIF && bSPDIFPassthrough;
  bHDMIPassthrough = bIsHDMI && bHDMIPassthrough;
  ismd_audio_input_pass_through_config_t passthrough_config;
  memset(&passthrough_config, 0, sizeof(&passthrough_config));
  if (bSPDIFPassthrough || bHDMIPassthrough)
  {
    passthrough_config.is_pass_through = TRUE;
    passthrough_config.supported_format_count = 1;
    passthrough_config.supported_formats[0] = ismdAudioInputFormat;
  }

  result = ismd_audio_input_set_as_primary(audioProcessor, m_audioDevice, passthrough_config);
  if (result != ISMD_SUCCESS)
  {
    CLog::Log(LOGERROR, "%s  ismd_audio_input_set_as_primary failed %d", __DEBUG_ID__, result);
//      return false;
  }

  if(!g_IntelSMDGlobals.EnableAudioInput(m_audioDevice))
  {
    CLog::Log(LOGERROR, "%s  EnableAudioInput", __DEBUG_ID__);
//    return false;
  }

  // enable outputs
  if (bIsHDMI)
  {
    if(!g_IntelSMDGlobals.EnableAudioOutput(g_IntelSMDGlobals.GetHDMIOutput()))
    {
      CLog::Log(LOGERROR, "%s  EnableAudioOutput HDMI failed", __DEBUG_ID__);
     //   return false;
    }
  }
  
  if (bIsSPDIF)
  {
    if(!g_IntelSMDGlobals.EnableAudioOutput(g_IntelSMDGlobals.GetSPDIFOutput()))
    {
      CLog::Log(LOGERROR, "%s  EnableAudioOutput SPDIF failed", __DEBUG_ID__);
//     return false;
    }
  }
  
  if (bIsAnalog)
  {
    if(!g_IntelSMDGlobals.EnableAudioOutput(g_IntelSMDGlobals.GetI2SOutput()))
    {
      CLog::Log(LOGERROR, "%s  EnableAudioOutput I2S failed", __DEBUG_ID__);
 //      return false;
    }
  }
  
  g_IntelSMDGlobals.SetAudioDeviceState(ISMD_DEV_STATE_PLAY, m_audioDevice);

//  m_fCurrentVolume = g_settings.m_fVolumeLevel;
  //g_IntelSMDGlobals.SetMasterVolume(m_fCurrentVolume);

  m_bPause = false;
  m_dSampleRate = format.m_sampleRate;
  m_bIsAllocated = true;

  // set latency when using passthrough since we are not using a timed audio interface
  if (bAC3Encode || ismdAudioInputFormat == ISMD_AUDIO_MEDIA_FMT_DD)
    m_latency = 0.675;//0.45;

  CLog::Log(LOGINFO, "%s done", __DEBUG_ID__);

  return true;
}