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; } } }
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; }