/**
  * 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);
        }
    }
}
Ejemplo n.º 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;
}