bool CAESinkPi::Initialize(AEAudioFormat &format, std::string &device) { // This may be called before Application calls g_RBP.Initialise, so call it here too g_RBP.Initialize(); /* if we are raw need to let gpu know */ m_passthrough = format.m_dataFormat == AE_FMT_RAW; m_initDevice = device; m_initFormat = format; m_latency = CServiceBroker::GetSettings().GetInt("audiooutput.latency") * 1e-3; m_latency = std::max(m_latency, 50e-3); if (m_passthrough || CServiceBroker::GetSettings().GetString(CSettings::SETTING_AUDIOOUTPUT_AUDIODEVICE) == "PI:HDMI") m_output = AESINKPI_HDMI; else if (CServiceBroker::GetSettings().GetString(CSettings::SETTING_AUDIOOUTPUT_AUDIODEVICE) == "PI:Analogue") m_output = AESINKPI_ANALOGUE; else if (CServiceBroker::GetSettings().GetString(CSettings::SETTING_AUDIOOUTPUT_AUDIODEVICE) == "PI:Both") m_output = AESINKPI_BOTH; else assert(0); // analogue only supports stereo if (m_output == AESINKPI_ANALOGUE || m_output == AESINKPI_BOTH) format.m_channelLayout = AE_CH_LAYOUT_2_0; // setup for a 50ms sink feed from SoftAE if (format.m_dataFormat != AE_FMT_FLOATP && format.m_dataFormat != AE_FMT_FLOAT && format.m_dataFormat != AE_FMT_S32NE && format.m_dataFormat != AE_FMT_S32NEP && format.m_dataFormat != AE_FMT_S32LE && format.m_dataFormat != AE_FMT_S16NE && format.m_dataFormat != AE_FMT_S16NEP && format.m_dataFormat != AE_FMT_S16LE) format.m_dataFormat = AE_FMT_S16LE; unsigned int channels = format.m_channelLayout.Count(); unsigned int sample_size = CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3; format.m_frameSize = sample_size * channels; format.m_sampleRate = std::max(8000U, std::min(192000U, format.m_sampleRate)); format.m_frames = format.m_sampleRate * m_latency / NUM_OMX_BUFFERS; m_format = format; m_sinkbuffer_sec_per_byte = 1.0 / (double)(m_format.m_frameSize * m_format.m_sampleRate); CLog::Log(LOGDEBUG, "%s:%s Format:%d Channels:%d Samplerate:%d framesize:%d bufsize:%d bytes/s=%.2f dest=%s", CLASSNAME, __func__, m_format.m_dataFormat, channels, m_format.m_sampleRate, m_format.m_frameSize, m_format.m_frameSize * m_format.m_frames, 1.0/m_sinkbuffer_sec_per_byte, CServiceBroker::GetSettings().GetString(CSettings::SETTING_AUDIOOUTPUT_AUDIODEVICE).c_str()); // magic value used when omxplayer is playing - want sink to be disabled if (m_passthrough && m_format.m_streamInfo.m_sampleRate == 16000) return true; SetAudioProps(m_passthrough, GetChannelMap(m_format.m_channelLayout, m_passthrough)); OMX_ERRORTYPE omx_err = OMX_ErrorNone; if (!m_omx_render.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit)) CLog::Log(LOGERROR, "%s::%s - m_omx_render.Initialize omx_err(0x%08x)", CLASSNAME, __func__, omx_err); if (m_output == AESINKPI_BOTH) { if (!m_omx_splitter.Initialize("OMX.broadcom.audio_splitter", OMX_IndexParamAudioInit)) CLog::Log(LOGERROR, "%s::%s - m_omx_splitter.Initialize omx_err(0x%08x)", CLASSNAME, __func__, omx_err); if (!m_omx_render_slave.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit)) CLog::Log(LOGERROR, "%s::%s - m_omx_render.Initialize omx_err(0x%08x)", CLASSNAME, __func__, omx_err); m_omx_output = &m_omx_splitter; } else m_omx_output = &m_omx_render; SetAudioDest(); OMX_INIT_STRUCTURE(m_pcm_input); m_pcm_input.eNumData = OMX_NumericalDataSigned; m_pcm_input.eEndian = OMX_EndianLittle; m_pcm_input.bInterleaved = OMX_TRUE; m_pcm_input.nBitPerSample = sample_size * 8; // 0x8000 = float, 0x10000 = planar uint32_t flags = 0; if (m_format.m_dataFormat == AE_FMT_FLOAT || m_format.m_dataFormat == AE_FMT_FLOATP) flags |= 0x8000; if (AE_IS_PLANAR(m_format.m_dataFormat)) flags |= 0x10000; m_pcm_input.ePCMMode = flags == 0 ? OMX_AUDIO_PCMModeLinear : (OMX_AUDIO_PCMMODETYPE)flags; m_pcm_input.nChannels = channels; m_pcm_input.nSamplingRate = m_format.m_sampleRate; if ( m_omx_splitter.IsInitialized() ) { m_pcm_input.nPortIndex = m_omx_splitter.GetInputPort(); omx_err = m_omx_splitter.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input); if (omx_err != OMX_ErrorNone) CLog::Log(LOGERROR, "%s::%s - error m_omx_splitter SetParameter in omx_err(0x%08x)", CLASSNAME, __func__, omx_err); m_pcm_input.nPortIndex = m_omx_splitter.GetOutputPort(); omx_err = m_omx_splitter.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input); if(omx_err != OMX_ErrorNone) CLog::Log(LOGERROR, "%s::%s - error m_omx_splitter SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err); m_pcm_input.nPortIndex = m_omx_splitter.GetOutputPort() + 1; omx_err = m_omx_splitter.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input); if(omx_err != OMX_ErrorNone) CLog::Log(LOGERROR, "%s::%s - error m_omx_splitter SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err); } if ( m_omx_render_slave.IsInitialized() ) { m_pcm_input.nPortIndex = m_omx_render_slave.GetInputPort(); omx_err = m_omx_render_slave.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input); if (omx_err != OMX_ErrorNone) CLog::Log(LOGERROR, "%s::%s - error m_omx_render_slave SetParameter in omx_err(0x%08x)", CLASSNAME, __func__, omx_err); } if ( m_omx_render.IsInitialized() ) { m_pcm_input.nPortIndex = m_omx_render.GetInputPort(); omx_err = m_omx_render.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input); if (omx_err != OMX_ErrorNone) CLog::Log(LOGERROR, "%s::%s - error m_omx_render SetParameter in omx_err(0x%08x)", CLASSNAME, __func__, omx_err); } if ( m_omx_output->IsInitialized() ) { // set up the number/size of buffers for decoder input OMX_PARAM_PORTDEFINITIONTYPE port_param; OMX_INIT_STRUCTURE(port_param); port_param.nPortIndex = m_omx_output->GetInputPort(); omx_err = m_omx_output->GetParameter(OMX_IndexParamPortDefinition, &port_param); if (omx_err != OMX_ErrorNone) CLog::Log(LOGERROR, "%s:%s - error get OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err); port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, (unsigned int)NUM_OMX_BUFFERS); port_param.nBufferSize = ALIGN_UP(m_format.m_frameSize * m_format.m_frames, port_param.nBufferAlignment); omx_err = m_omx_output->SetParameter(OMX_IndexParamPortDefinition, &port_param); if (omx_err != OMX_ErrorNone) CLog::Log(LOGERROR, "%s:%s - error set OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err); omx_err = m_omx_output->AllocInputBuffers(); if (omx_err != OMX_ErrorNone) CLog::Log(LOGERROR, "%s:%s - Error alloc buffers 0x%08x", CLASSNAME, __func__, omx_err); } if ( m_omx_splitter.IsInitialized() ) { m_omx_tunnel_splitter.Initialize(&m_omx_splitter, m_omx_splitter.GetOutputPort(), &m_omx_render, m_omx_render.GetInputPort()); omx_err = m_omx_tunnel_splitter.Establish(); if (omx_err != OMX_ErrorNone) { CLog::Log(LOGERROR, "COMXAudio::Initialize - Error m_omx_tunnel_splitter.Establish 0x%08x", omx_err); return false; } m_omx_tunnel_splitter_slave.Initialize(&m_omx_splitter, m_omx_splitter.GetOutputPort() + 1, &m_omx_render_slave, m_omx_render_slave.GetInputPort()); omx_err = m_omx_tunnel_splitter_slave.Establish(); if (omx_err != OMX_ErrorNone) { CLog::Log(LOGERROR, "COMXAudio::Initialize - Error m_omx_tunnel_splitter_slave.Establish 0x%08x", omx_err); return false; } } if ( m_omx_splitter.IsInitialized() ) { omx_err = m_omx_splitter.SetStateForComponent(OMX_StateExecuting); if (omx_err != OMX_ErrorNone) CLog::Log(LOGERROR, "%s:%s - m_omx_splitter OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err); } if ( m_omx_render.IsInitialized() ) { omx_err = m_omx_render.SetStateForComponent(OMX_StateExecuting); if (omx_err != OMX_ErrorNone) CLog::Log(LOGERROR, "%s:%s - m_omx_render OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err); } if ( m_omx_render_slave.IsInitialized() ) { omx_err = m_omx_render_slave.SetStateForComponent(OMX_StateExecuting); if (omx_err != OMX_ErrorNone) CLog::Log(LOGERROR, "%s:%s - m_omx_render_slave OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err); } m_Initialized = true; return true; }
bool CAESinkPi::Initialize(AEAudioFormat &format, std::string &device) { m_initDevice = device; m_initFormat = format; // setup for a 50ms sink feed from SoftAE format.m_dataFormat = AE_FMT_S16NE; format.m_frames = format.m_sampleRate * AUDIO_PLAYBUFFER; format.m_frameSamples = format.m_channelLayout.Count(); format.m_frameSize = format.m_frameSamples * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3); format.m_sampleRate = std::max(8000U, std::min(96000U, format.m_sampleRate)); m_format = format; m_sinkbuffer_size = format.m_frameSize * format.m_frames * NUM_OMX_BUFFERS; m_sinkbuffer_sec_per_byte = 1.0 / (double)(format.m_frameSize * format.m_sampleRate); CLog::Log(LOGDEBUG, "%s:%s Format:%d Channels:%d Samplerate:%d framesize:%d bufsize:%d bytes/s=%.2f", CLASSNAME, __func__, format.m_dataFormat, format.m_channelLayout.Count(), format.m_sampleRate, format.m_frameSize, m_sinkbuffer_size, 1.0/m_sinkbuffer_sec_per_byte); // This may be called before Application calls g_RBP.Initialise, so call it here too g_RBP.Initialize(); CLog::Log(LOGDEBUG, "%s:%s", CLASSNAME, __func__); OMX_ERRORTYPE omx_err = OMX_ErrorNone; if (!m_omx_render.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit)) CLog::Log(LOGERROR, "%s::%s - m_omx_render.Initialize omx_err(0x%08x)", CLASSNAME, __func__, omx_err); OMX_INIT_STRUCTURE(m_pcm_input); m_pcm_input.nPortIndex = m_omx_render.GetInputPort(); m_pcm_input.eNumData = OMX_NumericalDataSigned; m_pcm_input.eEndian = OMX_EndianLittle; m_pcm_input.bInterleaved = OMX_TRUE; m_pcm_input.nBitPerSample = 16; m_pcm_input.ePCMMode = OMX_AUDIO_PCMModeLinear; m_pcm_input.nChannels = m_format.m_frameSamples; m_pcm_input.nSamplingRate = m_format.m_sampleRate; m_pcm_input.eChannelMapping[0] = OMX_AUDIO_ChannelLF; m_pcm_input.eChannelMapping[1] = OMX_AUDIO_ChannelRF; m_pcm_input.eChannelMapping[2] = OMX_AUDIO_ChannelMax; omx_err = m_omx_render.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input); if (omx_err != OMX_ErrorNone) CLog::Log(LOGERROR, "%s::%s - error m_omx_render SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err); m_omx_render.ResetEos(); SetAudioDest(); // set up the number/size of buffers for decoder input OMX_PARAM_PORTDEFINITIONTYPE port_param; OMX_INIT_STRUCTURE(port_param); port_param.nPortIndex = m_omx_render.GetInputPort(); omx_err = m_omx_render.GetParameter(OMX_IndexParamPortDefinition, &port_param); if (omx_err != OMX_ErrorNone) CLog::Log(LOGERROR, "%s:%s - error get OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err); port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, (unsigned int)NUM_OMX_BUFFERS); port_param.nBufferSize = m_sinkbuffer_size / port_param.nBufferCountActual; omx_err = m_omx_render.SetParameter(OMX_IndexParamPortDefinition, &port_param); if (omx_err != OMX_ErrorNone) CLog::Log(LOGERROR, "%s:%s - error set OMX_IndexParamPortDefinition (intput) omx_err(0x%08x)", CLASSNAME, __func__, omx_err); omx_err = m_omx_render.AllocInputBuffers(); if (omx_err != OMX_ErrorNone) CLog::Log(LOGERROR, "%s:%s - Error alloc buffers 0x%08x", CLASSNAME, __func__, omx_err); omx_err = m_omx_render.SetStateForComponent(OMX_StateExecuting); if (omx_err != OMX_ErrorNone) CLog::Log(LOGERROR, "%s:%s - m_omx_render OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err); m_Initialized = true; return true; }