/** * Callback. Invoked when any of our attributes are written via BLE. */ void MicroBitIOPinService::onDataWritten(const GattWriteCallbackParams *params) { // Check for writes to the IO configuration characteristic if (params->handle == ioPinServiceIOCharacteristicHandle && params->len >= sizeof(ioPinServiceIOCharacteristicBuffer)) { uint32_t *value = (uint32_t *)params->data; // Our IO configuration may be changing... read the new value, and push it back into the BLE stack. ioPinServiceIOCharacteristicBuffer = *value; ble.gattServer().write(ioPinServiceIOCharacteristicHandle, (const uint8_t *)&ioPinServiceIOCharacteristicBuffer, sizeof(ioPinServiceIOCharacteristicBuffer)); // Also, drop any selected pins into input mode, so we can pick up changes later for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++) { if(isDigital(i) && isInput(i)) io.pin[i].getDigitalValue(); //MicroBitIOPins[i]->getDigitalValue(); if(isAnalog(i) && isInput(i)) io.pin[i].getAnalogValue(); //MicroBitIOPins[i]->getAnalogValue(); } } // Check for writes to the IO configuration characteristic if (params->handle == ioPinServiceADCharacteristicHandle && params->len >= sizeof(ioPinServiceADCharacteristicBuffer)) { uint32_t *value = (uint32_t *)params->data; // Our IO configuration may be changing... read the new value, and push it back into the BLE stack. ioPinServiceADCharacteristicBuffer = *value; ble.gattServer().write(ioPinServiceADCharacteristicHandle, (const uint8_t *)&ioPinServiceADCharacteristicBuffer, sizeof(ioPinServiceADCharacteristicBuffer)); // Also, drop any selected pins into input mode, so we can pick up changes later for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++) { if(isDigital(i) && isInput(i)) io.pin[i].getDigitalValue(); //MicroBitIOPins[i]->getDigitalValue(); if(isAnalog(i) && isInput(i)) io.pin[i].getAnalogValue(); //MicroBitIOPins[i]->getAnalogValue(); } } if (params->handle == ioPinServiceDataCharacteristic->getValueHandle()) { // We have some pin data to change... uint16_t len = params->len; IOData *data = (IOData *)params->data; // There may be multiple write operaitons... take each in turn and update the pin values while (len >= sizeof(IOData)) { if (isOutput(data->pin)) { if (isDigital(data->pin)) io.pin[data->pin].setDigitalValue(data->value); //MicroBitIOPins[data->pin]->setDigitalValue(data->value); else io.pin[data->pin].setAnalogValue(data->value*4); //MicroBitIOPins[data->pin]->setAnalogValue(data->value*4); } data++; len -= sizeof(IOData); } } }
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; }