using namespace ActiveAE;
#include "ActiveAESound.h"
#include "ActiveAEStream.h"
-#include "Utils/AEUtil.h"
-#include "Encoders/AEEncoderFFmpeg.h"
+#include "cores/AudioEngine/Utils/AEUtil.h"
+#include "cores/AudioEngine/Encoders/AEEncoderFFmpeg.h"
#include "settings/Settings.h"
#include "settings/AdvancedSettings.h"
#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)
{
return delay;
}
+// this is used to sync a/v so we need to add sink latency here
float CEngineStats::GetDelay(CActiveAEStream *stream)
{
CSingleLock lock(m_lock);
unsigned int now = XbmcThreads::SystemClockMillis();
float delay = m_sinkDelay - (double)(now-m_sinkUpdate) / 1000;
+ delay += m_sinkLatency;
delay += (float)m_bufferedSamples / m_sinkSampleRate;
if (delay < 0)
delay = 0.0;
- delay += stream->m_bufferedTime;
+ delay += stream->m_bufferedTime / stream->m_streamResampleRatio;
return delay;
}
float CEngineStats::GetWaterLevel()
{
+ CSingleLock lock(m_lock);
return (float)m_bufferedSamples / m_sinkSampleRate;
}
m_vizBuffers = NULL;
m_vizBuffersInput = NULL;
m_volume = 1.0;
+ m_volumeScaled = 1.0;
m_aeVolume = 1.0;
m_muted = false;
m_aeMuted = false;
void CActiveAE::Dispose()
{
-#if defined(HAS_GLX) || defined(TARGET_DARWIN_OSX)
+#if defined(HAS_GLX) || defined(TARGET_DARWIN)
g_Windowing.Unregister(this);
#endif
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;
case CActiveAEControlProtocol::KEEPCONFIG:
m_extKeepConfig = *(unsigned int*)msg->data;
return;
+ case CActiveAEControlProtocol::DISPLAYRESET:
+ return;
+ case CActiveAEControlProtocol::APPFOCUSED:
+ m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::APPFOCUSED, msg->data, sizeof(bool));
+ return;
default:
break;
}
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();
m_state = AE_TOP_CONFIGURED_SUSPEND;
m_extDeferData = true;
}
+ 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;
- m_state = AE_TOP_CONFIGURED_PLAY;
+ streaming = true;
+ m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::STREAMING, &streaming, sizeof(bool));
m_extTimeout = 0;
return;
case CActiveAEControlProtocol::FLUSHSTREAM:
stream = *(CActiveAEStream**)msg->data;
SFlushStream(stream);
msg->Reply(CActiveAEControlProtocol::ACC);
- m_state = AE_TOP_CONFIGURED_PLAY;
m_extTimeout = 0;
return;
case CActiveAEControlProtocol::STREAMAMP:
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();
}
m_stats.SetSuspended(false);
m_extDeferData = false;
return;
+ case CActiveAEControlProtocol::DEVICECHANGE:
+ return;
default:
break;
}
break;
}
}
+ else if (port == NULL) // timeout
+ {
+ switch (signal)
+ {
+ case CActiveAEControlProtocol::TIMEOUT:
+ m_extTimeout = 1000;
+ return;
+ default:
+ break;
+ }
+ }
break;
case AE_TOP_CONFIGURED_IDLE:
- if (port == NULL) // timeout
+ if (port == &m_controlPort)
+ {
+ switch (signal)
+ {
+ case CActiveAEControlProtocol::RESUMESTREAM:
+ CActiveAEStream *stream;
+ stream = *(CActiveAEStream**)msg->data;
+ stream->m_paused = false;
+ m_state = AE_TOP_CONFIGURED_PLAY;
+ m_extTimeout = 0;
+ return;
+ case CActiveAEControlProtocol::FLUSHSTREAM:
+ stream = *(CActiveAEStream**)msg->data;
+ SFlushStream(stream);
+ msg->Reply(CActiveAEControlProtocol::ACC);
+ m_state = AE_TOP_CONFIGURED_PLAY;
+ m_extTimeout = 0;
+ return;
+ default:
+ break;
+ }
+ }
+ else if (port == NULL) // timeout
{
switch (signal)
{
AEAudioFormat sinkInputFormat, inputFormat;
AEAudioFormat oldInternalFormat = m_internalFormat;
+ AEAudioFormat oldSinkRequestFormat = m_sinkRequestFormat;
inputFormat = GetInputFormat(desiredFmt);
std::string device = AE_IS_RAW(m_sinkRequestFormat.m_dataFormat) ? m_settings.passthoughdevice : m_settings.device;
std::string driver;
CAESinkFactory::ParseDevice(device, driver);
- if (!IsSinkCompatible(m_sinkRequestFormat, device) || m_settings.driver.compare(driver) != 0)
+ if ((!CompareFormat(m_sinkRequestFormat, m_sinkFormat) && !CompareFormat(m_sinkRequestFormat, oldSinkRequestFormat)) ||
+ m_currDevice.compare(device) != 0 ||
+ m_settings.driver.compare(driver) != 0)
{
if (!InitSink())
return;
m_settings.driver = driver;
+ m_currDevice = device;
initSink = true;
m_stats.Reset(m_sinkFormat.m_sampleRate);
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;
}
}
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);
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;
// 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)
{
+ inputFormat.m_frames = m_sinkFormat.m_frames;
outputFormat = inputFormat;
sinkInputFormat = m_sinkFormat;
}
outputFormat = inputFormat;
outputFormat.m_dataFormat = AE_FMT_FLOATP;
outputFormat.m_sampleRate = 48000;
+ outputFormat.m_encodedRate = 48000;
// setup encoder
if (!m_encoder)
format.m_frameSize = 2* (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
format.m_frames = AC3_FRAME_SIZE;
format.m_sampleRate = 48000;
+ format.m_encodedRate = m_encoderFormat.m_sampleRate;
if (m_encoderBuffers && initSink)
{
m_discardBufferPools.push_back(m_encoderBuffers);
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;
}
(*it)->m_limiter.SetSamplerate(outputFormat.m_sampleRate);
}
+ // update buffered time of streams
+ m_stats.AddSamples(0, m_streams);
+
// buffers for viz
if (!AE_IS_RAW(inputFormat.m_dataFormat))
{
// 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;
if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::FLUSH,
&reply, 2000))
{
- bool success = reply->signal == CSinkControlProtocol::ACC ? true : false;
+ bool success = reply->signal == CSinkControlProtocol::ACC;
if (!success)
{
CLog::Log(LOGERROR, "ActiveAE::%s - returned error on flush", __FUNCTION__);
else if (settings.channels <= AE_CH_LAYOUT_2_0 && // no multichannel pcm
settings.passthrough &&
settings.ac3passthrough &&
+ settings.ac3transcode &&
!m_streams.empty() &&
(format.m_channelLayout.Count() > 2 || settings.stereoupmix))
{
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;
std::string device = AE_IS_RAW(newFormat.m_dataFormat) ? m_settings.passthoughdevice : m_settings.device;
std::string driver;
CAESinkFactory::ParseDevice(device, driver);
- if (m_settings.driver.compare(driver) != 0)
- return true;
- if (!IsSinkCompatible(newFormat, device))
+ if (!CompareFormat(newFormat, m_sinkFormat) ||
+ m_currDevice.compare(device) != 0 ||
+ m_settings.driver.compare(driver) != 0)
return true;
return false;
5000,
&config, sizeof(config)))
{
- bool success = reply->signal == CSinkControlProtocol::ACC ? true : false;
+ bool success = reply->signal == CSinkControlProtocol::ACC;
if (!success)
{
reply->Release();
m_extError = true;
return false;
}
- AEAudioFormat *data;
- data = (AEAudioFormat*)reply->data;
+ SinkReply *data;
+ data = (SinkReply*)reply->data;
if (data)
{
- m_sinkFormat = *data;
+ m_sinkFormat = data->format;
+ m_sinkHasVolume = data->hasVolume;
+ m_stats.SetSinkCacheTotal(data->cacheTotal);
+ m_stats.SetSinkLatency(data->latency);
}
- m_sinkHasVolume = m_sink.HasVolume();
reply->Release();
}
else
{
CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
+ m_stats.SetSinkCacheTotal(0);
+ m_stats.SetSinkLatency(0);
m_extError = true;
return false;
}
&reply,
2000))
{
- bool success = reply->signal == CSinkDataProtocol::ACC ? true : false;
+ bool success = reply->signal == CSinkDataProtocol::ACC;
if (!success)
{
reply->Release();
}
}
-bool CActiveAE::IsSinkCompatible(const AEAudioFormat &format, const std::string &device)
-{
- bool compatible = false;
- SinkConfig config;
- config.format = format;
- config.device = &device;
-
- // send message to sink
- Message *reply;
- if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::ISCOMPATIBLE,
- &reply,
- 1000,
- &config, sizeof(config)))
- {
- bool success = reply->signal == CSinkControlProtocol::ACC ? true : false;
- if (!success)
- {
- reply->Release();
- CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
- m_extError = true;
- return false;
- }
- compatible = *(bool*)reply->data;
- reply->Release();
- }
- else
- {
- CLog::Log(LOGERROR, "ActiveAE::%s - failed to query compatibility", __FUNCTION__);
- m_extError = true;
- return false;
- }
- return compatible;
-}
-
void CActiveAE::UnconfigureSink()
{
// send message to sink
&reply,
2000))
{
- bool success = reply->signal == CSinkControlProtocol::ACC ? true : false;
+ bool success = reply->signal == CSinkControlProtocol::ACC;
if (!success)
{
CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
m_extError = true;
}
+ // make sure we open sink on next configure
+ m_currDevice = "";
+
m_inMsgEvent.Reset();
}
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
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)
{
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();
}
}
}
+ }
- // 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;
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; j<dstSample.planes; j++)
{
buffer = (float*)dstSample.data[j];
#ifdef __SSE__
- CAEUtil::SSEMulArray(buffer, m_muted ? 0.0 : m_volume, nb_floats);
+ CAEUtil::SSEMulArray(buffer, volume, nb_floats);
#else
float *fbuffer = buffer;
for (int i = 0; i < nb_floats; i++)
- *fbuffer++ *= m_volume;
+ *fbuffer++ *= volume;
#endif
}
}
m_settings.guisoundmode = CSettings::Get().GetInt("audiooutput.guisoundmode");
m_settings.passthrough = m_settings.config == AE_CONFIG_FIXED ? false : CSettings::Get().GetBool("audiooutput.passthrough");
+ if (!m_sink.HasPassthroughDevice())
+ m_settings.passthrough = false;
m_settings.ac3passthrough = CSettings::Get().GetBool("audiooutput.ac3passthrough");
+ m_settings.ac3transcode = CSettings::Get().GetBool("audiooutput.ac3transcode");
m_settings.eac3passthrough = CSettings::Get().GetBool("audiooutput.eac3passthrough");
m_settings.truehdpassthrough = CSettings::Get().GetBool("audiooutput.truehdpassthrough");
m_settings.dtspassthrough = CSettings::Get().GetBool("audiooutput.dtspassthrough");
Message *reply;
if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT,
&reply,
- 5000))
+ 10000))
{
- bool success = reply->signal == CActiveAEControlProtocol::ACC ? true : false;
+ bool success = reply->signal == CActiveAEControlProtocol::ACC;
reply->Release();
if (!success)
{
}
// 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
setting == "audiooutput.audiodevice" ||
setting == "audiooutput.config" ||
setting == "audiooutput.ac3passthrough" ||
+ setting == "audiooutput.ac3transcode" ||
setting == "audiooutput.eac3passthrough" ||
setting == "audiooutput.dtspassthrough" ||
setting == "audiooutput.truehdpassthrough" ||
}
}
-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;
}
}
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")
{
- if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) != AE_DEVTYPE_IEC958)
- {
- if (CSettings::Get().GetInt("audiooutput.channels") > AE_CH_LAYOUT_2_0)
- return true;
- }
- else
- {
- if (m_sink.HasPassthroughDevice() &&
- CSettings::Get().GetBool("audiooutput.passthrough") &&
- CSettings::Get().GetBool("audiooutput.ac3passthrough"))
- return true;
- }
+ if (m_sink.HasPassthroughDevice() ||
+ CSettings::Get().GetInt("audiooutput.channels") > AE_CH_LAYOUT_2_0)
+ return true;
+ }
+ else if (settingId == "audiooutput.ac3transcode")
+ {
+ if (m_sink.HasPassthroughDevice() &&
+ CSettings::Get().GetBool("audiooutput.ac3passthrough") &&
+ CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED &&
+ (CSettings::Get().GetInt("audiooutput.channels") <= AE_CH_LAYOUT_2_0 || m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) == AE_DEVTYPE_IEC958))
+ return true;
}
return false;
}
&reply,
5000))
{
- bool success = reply->signal == CActiveAEControlProtocol::ACC ? true : false;
+ bool success = reply->signal == CActiveAEControlProtocol::ACC;
reply->Release();
if (!success)
{
m_controlPort.SendOutMessage(CActiveAEControlProtocol::KEEPCONFIG, &timeMs, sizeof(unsigned int));
}
+void CActiveAE::DeviceChange()
+{
+ m_controlPort.SendOutMessage(CActiveAEControlProtocol::DEVICECHANGE);
+}
+
void CActiveAE::OnLostDevice()
{
-// m_controlPort.SendOutMessage(CActiveAEControlProtocol::DISPLAYLOST);
+ Message *reply;
+ if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::DISPLAYLOST,
+ &reply,
+ 5000))
+ {
+ bool success = reply->signal == CActiveAEControlProtocol::ACC;
+ reply->Release();
+ if (!success)
+ {
+ CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
+ }
+ }
+ else
+ {
+ CLog::Log(LOGERROR, "ActiveAE::%s - timed out", __FUNCTION__);
+ }
}
void CActiveAE::OnResetDevice()
{
-// m_controlPort.SendOutMessage(CActiveAEControlProtocol::DISPLAYRESET);
+ m_controlPort.SendOutMessage(CActiveAEControlProtocol::DISPLAYRESET);
+}
+
+void CActiveAE::OnAppFocusChange(bool focus)
+{
+ m_controlPort.SendOutMessage(CActiveAEControlProtocol::APPFOCUSED, &focus, sizeof(focus));
}
//-----------------------------------------------------------------------------
{
if (lhs.m_channelLayout != rhs.m_channelLayout ||
lhs.m_dataFormat != rhs.m_dataFormat ||
- lhs.m_sampleRate != rhs.m_sampleRate ||
- lhs.m_frames != rhs.m_frames)
+ lhs.m_sampleRate != rhs.m_sampleRate)
return false;
else
return true;
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;
&reply,10000,
&msg, sizeof(MsgStreamNew)))
{
- bool success = reply->signal == CActiveAEControlProtocol::ACC ? true : false;
+ bool success = reply->signal == CActiveAEControlProtocol::ACC;
if (success)
{
CActiveAEStream *stream = *(CActiveAEStream**)reply->data;
&reply,1000,
&stream, sizeof(CActiveAEStream*)))
{
- bool success = reply->signal == CActiveAEControlProtocol::ACC ? true : false;
+ bool success = reply->signal == CActiveAEControlProtocol::ACC;
reply->Release();
if (!success)
{