X-Git-Url: http://code.vuplus.com/gitweb/?a=blobdiff_plain;f=xbmc%2Fcores%2FAudioEngine%2FEngines%2FActiveAE%2FActiveAE.cpp;h=eae62530dd815d94ead2345ad0f80ca6d8cfa2df;hb=35b5f279740b89321e8be3a6d80ef10eeed5748e;hp=fc6a964c1d12f06272e592d4aa081bd7ffe95b66;hpb=e22fa22e57279b2378a70a1f2dc29fa57b98dce0;p=vuplus_xbmc diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp index fc6a964..eae6253 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp @@ -32,6 +32,7 @@ using namespace ActiveAE; #define MAX_CACHE_LEVEL 0.5 // total cache time of stream in seconds #define MAX_WATER_LEVEL 0.25 // buffered time after stream stages in seconds +#define MAX_BUFFER_TIME 0.1 // max time of a buffer in seconds void CEngineStats::Reset(unsigned int sampleRate) { @@ -101,7 +102,7 @@ float CEngineStats::GetDelay(CActiveAEStream *stream) if (delay < 0) delay = 0.0; - delay += stream->m_bufferedTime; + delay += stream->m_bufferedTime / stream->m_streamResampleRatio; return delay; } @@ -121,6 +122,7 @@ float CEngineStats::GetCacheTotal(CActiveAEStream *stream) float CEngineStats::GetWaterLevel() { + CSingleLock lock(m_lock); return (float)m_bufferedSamples / m_sinkSampleRate; } @@ -148,6 +150,7 @@ CActiveAE::CActiveAE() : m_vizBuffers = NULL; m_vizBuffersInput = NULL; m_volume = 1.0; + m_volumeScaled = 1.0; m_aeVolume = 1.0; m_muted = false; m_aeMuted = false; @@ -165,7 +168,7 @@ CActiveAE::~CActiveAE() void CActiveAE::Dispose() { -#if defined(HAS_GLX) || defined(TARGET_DARWIN_OSX) +#if defined(HAS_GLX) || defined(TARGET_DARWIN) g_Windowing.Unregister(this); #endif @@ -224,6 +227,7 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg) return; case CActiveAEControlProtocol::VOLUME: m_volume = *(float*)msg->data; + m_volumeScaled = CAEUtil::GainToScale(CAEUtil::PercentToGain(m_volume)); if (m_sinkHasVolume) m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::VOLUME, &m_volume, sizeof(float)); return; @@ -235,6 +239,9 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg) return; case CActiveAEControlProtocol::DISPLAYRESET: return; + case CActiveAEControlProtocol::APPFOCUSED: + m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::APPFOCUSED, msg->data, sizeof(bool)); + return; default: break; } @@ -392,13 +399,14 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg) case AE_TOP_CONFIGURED: if (port == &m_controlPort) { + bool streaming; switch (signal) { case CActiveAEControlProtocol::RECONFIGURE: if (m_streams.empty()) { - bool silence = false; - m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::SILENCEMODE, &silence, sizeof(bool)); + streaming = false; + m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::STREAMING, &streaming, sizeof(bool)); } LoadSettings(); ChangeResamplers(); @@ -425,16 +433,53 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg) } msg->Reply(CActiveAEControlProtocol::ACC); return; + case CActiveAEControlProtocol::DEVICECHANGE: + time_t now; + time(&now); + CLog::Log(LOGDEBUG,"CActiveAE - device change event"); + while (!m_extLastDeviceChange.empty() && (now - m_extLastDeviceChange.front() > 0)) + { + m_extLastDeviceChange.pop(); + } + if (m_extLastDeviceChange.size() > 2) + { + CLog::Log(LOGWARNING,"CActiveAE - received %ld device change events within one second", m_extLastDeviceChange.size()); + return; + } + m_extLastDeviceChange.push(now); + UnconfigureSink(); + m_controlPort.PurgeOut(CActiveAEControlProtocol::DEVICECHANGE); + m_sink.EnumerateSinkList(true); + LoadSettings(); + m_extError = false; + Configure(); + if (!m_extError) + { + m_state = AE_TOP_CONFIGURED_PLAY; + m_extTimeout = 0; + } + else + { + m_state = AE_TOP_ERROR; + m_extTimeout = 500; + } + return; case CActiveAEControlProtocol::PAUSESTREAM: CActiveAEStream *stream; stream = *(CActiveAEStream**)msg->data; if (stream->m_paused != true && m_streams.size() == 1) + { FlushEngine(); + streaming = false; + m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::STREAMING, &streaming, sizeof(bool)); + } stream->m_paused = true; return; case CActiveAEControlProtocol::RESUMESTREAM: stream = *(CActiveAEStream**)msg->data; stream->m_paused = false; + streaming = true; + m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::STREAMING, &streaming, sizeof(bool)); m_extTimeout = 0; return; case CActiveAEControlProtocol::FLUSHSTREAM: @@ -591,11 +636,13 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg) switch (signal) { case CActiveAEControlProtocol::DISPLAYRESET: + CLog::Log(LOGDEBUG,"CActiveAE - display reset event"); displayReset = true; case CActiveAEControlProtocol::INIT: m_extError = false; if (!displayReset) { + m_controlPort.PurgeOut(CActiveAEControlProtocol::DEVICECHANGE); m_sink.EnumerateSinkList(true); LoadSettings(); } @@ -615,6 +662,8 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg) m_stats.SetSuspended(false); m_extDeferData = false; return; + case CActiveAEControlProtocol::DEVICECHANGE: + return; default: break; } @@ -649,7 +698,7 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg) break; case AE_TOP_CONFIGURED_IDLE: - if (port == NULL) // timeout + if (port == &m_controlPort) { switch (signal) { @@ -667,6 +716,14 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg) m_state = AE_TOP_CONFIGURED_PLAY; m_extTimeout = 0; return; + default: + break; + } + } + else if (port == NULL) // timeout + { + switch (signal) + { case CActiveAEControlProtocol::TIMEOUT: ResampleSounds(); ClearDiscardedBuffers(); @@ -904,11 +961,11 @@ void CActiveAE::Configure(AEAudioFormat *desiredFmt) m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::VOLUME, &m_volume, sizeof(float)); // limit buffer size in case of sink returns large buffer - unsigned int buffertime = (m_sinkFormat.m_frames*1000) / m_sinkFormat.m_sampleRate; - if (buffertime > 80) + unsigned int buffertime = m_sinkFormat.m_frames / m_sinkFormat.m_sampleRate; + if (buffertime > MAX_BUFFER_TIME) { - CLog::Log(LOGWARNING, "ActiveAE::%s - sink returned large buffer of %d ms, reducing to 80 ms", __FUNCTION__, buffertime); - m_sinkFormat.m_frames = 80 * m_sinkFormat.m_sampleRate / 1000; + CLog::Log(LOGWARNING, "ActiveAE::%s - sink returned large buffer of %d ms, reducing to %d ms", __FUNCTION__, buffertime, (int)(MAX_BUFFER_TIME*1000)); + m_sinkFormat.m_frames = MAX_BUFFER_TIME * m_sinkFormat.m_sampleRate; } } @@ -922,6 +979,11 @@ void CActiveAE::Configure(AEAudioFormat *desiredFmt) if (m_streams.empty()) { inputFormat = m_sinkFormat; + if (m_sinkFormat.m_channelLayout.Count() > m_sinkRequestFormat.m_channelLayout.Count()) + { + inputFormat.m_channelLayout = m_sinkRequestFormat.m_channelLayout; + inputFormat.m_channelLayout.ResolveChannels(m_sinkFormat.m_channelLayout); + } inputFormat.m_dataFormat = AE_FMT_FLOAT; inputFormat.m_frameSize = inputFormat.m_channelLayout.Count() * (CAEUtil::DataFormatToBits(inputFormat.m_dataFormat) >> 3); @@ -930,8 +992,8 @@ void CActiveAE::Configure(AEAudioFormat *desiredFmt) sinkInputFormat = inputFormat; m_internalFormat = inputFormat; - bool silence = false; - m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::SILENCEMODE, &silence, sizeof(bool)); + bool streaming = false; + m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::STREAMING, &streaming, sizeof(bool)); delete m_encoder; m_encoder = NULL; @@ -955,8 +1017,8 @@ void CActiveAE::Configure(AEAudioFormat *desiredFmt) // resample buffers for streams else { - bool silence = true; - m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::SILENCEMODE, &silence, sizeof(bool)); + bool streaming = true; + m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::STREAMING, &streaming, sizeof(bool)); AEAudioFormat outputFormat; if (m_mode == MODE_RAW) @@ -971,6 +1033,7 @@ void CActiveAE::Configure(AEAudioFormat *desiredFmt) outputFormat = inputFormat; outputFormat.m_dataFormat = AE_FMT_FLOATP; outputFormat.m_sampleRate = 48000; + outputFormat.m_encodedRate = 48000; // setup encoder if (!m_encoder) @@ -1015,6 +1078,16 @@ void CActiveAE::Configure(AEAudioFormat *desiredFmt) outputFormat.m_dataFormat = AE_FMT_FLOAT; outputFormat.m_frameSize = outputFormat.m_channelLayout.Count() * (CAEUtil::DataFormatToBits(outputFormat.m_dataFormat) >> 3); + + // due to channel ordering of the driver, a sink may return more channels than + // requested, i.e. 2.1 request returns FL,FR,BL,BR,FC,LFE for ALSA + // in this case we need to downmix to requested format + if (m_sinkFormat.m_channelLayout.Count() > m_sinkRequestFormat.m_channelLayout.Count()) + { + outputFormat.m_channelLayout = m_sinkRequestFormat.m_channelLayout; + outputFormat.m_channelLayout.ResolveChannels(m_sinkFormat.m_channelLayout); + } + // TODO: adjust to decoder sinkInputFormat = outputFormat; } @@ -1097,7 +1170,9 @@ void CActiveAE::Configure(AEAudioFormat *desiredFmt) // resample buffers for sink if (m_sinkBuffers && - (!CompareFormat(m_sinkBuffers->m_format,m_sinkFormat) || !CompareFormat(m_sinkBuffers->m_inputFormat, sinkInputFormat))) + (!CompareFormat(m_sinkBuffers->m_format,m_sinkFormat) || + !CompareFormat(m_sinkBuffers->m_inputFormat, sinkInputFormat) || + m_sinkBuffers->m_format.m_frames != m_sinkFormat.m_frames)) { m_discardBufferPools.push_back(m_sinkBuffers); m_sinkBuffers = NULL; @@ -1346,6 +1421,7 @@ void CActiveAE::ApplySettingsToFormat(AEAudioFormat &format, AudioSettings &sett { format.m_dataFormat = AE_FMT_AC3; format.m_sampleRate = 48000; + format.m_encodedRate = 48000; format.m_channelLayout = AE_CH_LAYOUT_2_0; if (mode) *mode = MODE_TRANSCODE; @@ -1570,13 +1646,15 @@ bool CActiveAE::RunStages() CSampleBuffer *buffer; if (!(*it)->m_drain) { - while (time < MAX_CACHE_LEVEL && !(*it)->m_inputBuffers->m_freeSamples.empty()) + float buftime = (float)(*it)->m_inputBuffers->m_format.m_frames / (*it)->m_inputBuffers->m_format.m_sampleRate; + time += buftime * (*it)->m_processingSamples.size(); + while ((time < MAX_CACHE_LEVEL || (*it)->m_streamIsBuffering) && !(*it)->m_inputBuffers->m_freeSamples.empty()) { buffer = (*it)->m_inputBuffers->GetFreeBuffer(); (*it)->m_processingSamples.push_back(buffer); (*it)->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMBUFFER, &buffer, sizeof(CSampleBuffer*)); (*it)->IncFreeBuffers(); - time += (float)buffer->pkt->max_nb_samples / buffer->pkt->config.sample_rate; + time += buftime; } } else @@ -1669,7 +1747,14 @@ bool CActiveAE::RunStages() if ((*it)->m_fadingSamples == -1) { (*it)->m_fadingSamples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f; - (*it)->m_volume = (*it)->m_fadingBase; + if ((*it)->m_fadingSamples > 0) + (*it)->m_volume = (*it)->m_fadingBase; + else + { + (*it)->m_volume = (*it)->m_fadingTarget; + CSingleLock lock((*it)->m_streamLock); + (*it)->m_streamFading = false; + } } if ((*it)->m_fadingSamples > 0) { @@ -1899,7 +1984,7 @@ bool CActiveAE::RunStages() CSampleBuffer *buffer; for (it = m_streams.begin(); it != m_streams.end(); ++it) { - if (!(*it)->m_resampleBuffers->m_outputSamples.empty()) + if (!(*it)->m_resampleBuffers->m_outputSamples.empty() && !(*it)->m_paused) { buffer = (*it)->m_resampleBuffers->m_outputSamples.front(); (*it)->m_resampleBuffers->m_outputSamples.pop_front(); @@ -1908,18 +1993,18 @@ bool CActiveAE::RunStages() } } } + } - // serve sink buffers - busy = m_sinkBuffers->ResampleBuffers(); - while(!m_sinkBuffers->m_outputSamples.empty()) - { - CSampleBuffer *out = NULL; - out = m_sinkBuffers->m_outputSamples.front(); - m_sinkBuffers->m_outputSamples.pop_front(); - m_sink.m_dataPort.SendOutMessage(CSinkDataProtocol::SAMPLE, - &out, sizeof(CSampleBuffer*)); - busy = true; - } + // serve sink buffers + busy |= m_sinkBuffers->ResampleBuffers(); + while(!m_sinkBuffers->m_outputSamples.empty()) + { + CSampleBuffer *out = NULL; + out = m_sinkBuffers->m_outputSamples.front(); + m_sinkBuffers->m_outputSamples.pop_front(); + m_sink.m_dataPort.SendOutMessage(CSinkDataProtocol::SAMPLE, + &out, sizeof(CSampleBuffer*)); + busy = true; } return busy; @@ -1998,20 +2083,21 @@ void CActiveAE::MixSounds(CSoundPacket &dstSample) void CActiveAE::Deamplify(CSoundPacket &dstSample) { - if (m_volume < 1.0 || m_muted) + if (m_volumeScaled < 1.0 || m_muted) { float *buffer; int nb_floats = dstSample.nb_samples * dstSample.config.channels / dstSample.planes; + float volume = m_muted ? 0.0f : m_volumeScaled; for(int j=0; jsignal == CActiveAEControlProtocol::ACC; reply->Release(); @@ -2079,7 +2165,7 @@ bool CActiveAE::Initialize() } // hook into windowing for receiving display reset events -#if defined(HAS_GLX) || defined(TARGET_DARWIN_OSX) +#if defined(HAS_GLX) || defined(TARGET_DARWIN) g_Windowing.Register(this); #endif @@ -2121,19 +2207,11 @@ void CActiveAE::OnSettingsChange(const std::string& setting) } } -bool CActiveAE::SupportsRaw(AEDataFormat format) +bool CActiveAE::SupportsRaw(AEDataFormat format, int samplerate) { - if (!m_sink.HasPassthroughDevice()) + if (!m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), format, samplerate)) return false; - // those formats require HDMI - if (format == AE_FMT_DTSHD || format == AE_FMT_TRUEHD) - { - if(m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) != AE_DEVTYPE_HDMI) - return false; - } - - // TODO: check ELD? return true; } @@ -2171,16 +2249,20 @@ bool CActiveAE::IsSettingVisible(const std::string &settingId) } else if (settingId == "audiooutput.truehdpassthrough") { - if (m_sink.HasPassthroughDevice() && - CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED && - m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) == AE_DEVTYPE_HDMI) + if (m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), AE_FMT_TRUEHD, 192000) && + CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED) return true; } else if (settingId == "audiooutput.dtshdpassthrough") { - if (m_sink.HasPassthroughDevice() && - CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED && - m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) == AE_DEVTYPE_HDMI) + if (m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), AE_FMT_DTSHD, 192000) && + CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED) + return true; + } + else if (settingId == "audiooutput.eac3passthrough") + { + if (m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), AE_FMT_EAC3, 192000) && + CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED) return true; } else if (settingId == "audiooutput.stereoupmix") @@ -2273,6 +2355,11 @@ void CActiveAE::KeepConfiguration(unsigned int millis) m_controlPort.SendOutMessage(CActiveAEControlProtocol::KEEPCONFIG, &timeMs, sizeof(unsigned int)); } +void CActiveAE::DeviceChange() +{ + m_controlPort.SendOutMessage(CActiveAEControlProtocol::DEVICECHANGE); +} + void CActiveAE::OnLostDevice() { Message *reply; @@ -2298,6 +2385,11 @@ void CActiveAE::OnResetDevice() m_controlPort.SendOutMessage(CActiveAEControlProtocol::DISPLAYRESET); } +void CActiveAE::OnAppFocusChange(bool focus) +{ + m_controlPort.SendOutMessage(CActiveAEControlProtocol::APPFOCUSED, &focus, sizeof(focus)); +} + //----------------------------------------------------------------------------- // Utils //----------------------------------------------------------------------------- @@ -2564,6 +2656,9 @@ bool CActiveAE::ResampleSound(CActiveAESound *sound) IAEStream *CActiveAE::MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options) { + if (IsSuspended()) + return NULL; + //TODO: pass number of samples in audio packet AEAudioFormat format;