<left>30</left>
<top>60</top>
<width>550</width>
- <height>80</height>
+ <height>100</height>
<align>left</align>
<label>-</label>
<font>font13</font>
- <autoscroll time="3000" delay="4000" repeat="5000">Skin.HasSetting(AutoScroll)</autoscroll>
+ <autoscroll time="3000" delay="4000" repeat="5000">true</autoscroll>
</control>
<control type="button" id="10">
<description>OK button</description>
<align>left</align>
<label>-</label>
<font>font13</font>
- <autoscroll time="3000" delay="4000" repeat="5000">Skin.HasSetting(AutoScroll)</autoscroll>
+ <autoscroll time="3000" delay="4000" repeat="5000">true</autoscroll>
</control>
<control type="progress">
<description>Progressbar</description>
<left>30</left>
<top>60</top>
<width>550</width>
- <height>80</height>
+ <height>100</height>
<align>left</align>
<label>-</label>
<font>font13</font>
- <autoscroll time="3000" delay="4000" repeat="5000">Skin.HasSetting(AutoScroll)</autoscroll>
+ <autoscroll time="3000" delay="4000" repeat="5000">true</autoscroll>
</control>
<control type="button" id="11">
<description>Yes button</description>
<texture border="3">epg-genres/$INFO[ListItem.Property(GenreType)].png</texture>
</control>
<control type="label" id="1">
- <left>6</left>
+ <left>10</left>
<top>3</top>
- <width>30</width>
+ <width>20</width>
<height>25</height>
<font>font12</font>
<aligny>center</aligny>
<texture border="3">epg-genres/$INFO[ListItem.Property(GenreType)].png</texture>
</control>
<control type="label" id="1">
- <left>6</left>
+ <left>10</left>
<top>3</top>
- <width>30</width>
+ <width>20</width>
<height>25</height>
<font>font12</font>
<aligny>center</aligny>
<?xml version="1.0" encoding="UTF-8"?>
-<addon id="xbmc.json" version="6.14.0" provider-name="Team XBMC">
+<addon id="xbmc.json" version="6.14.1" provider-name="Team XBMC">
<backwards-compatibility abi="6.0.0"/>
<requires>
<import addon="xbmc.core" version="0.1.0"/>
if (avio_seek(s->pb, pos, SEEK_SET) < 0)
return AV_NOPTS_VALUE;
+ ff_read_frame_flush(s);
asf_reset_header(s);
for (;;) {
if (av_read_frame(s, pkt) < 0) {
--- /dev/null
+From 4b101ab02ea762f70903e894a4b002b229526a4a Mon Sep 17 00:00:00 2001
+From: Michael Niedermayer <michaelni@gmx.at>
+Date: Mon, 12 Aug 2013 22:52:23 +0200
+Subject: [PATCH] avformat/asfdec: call ff_read_frame_flush() in asf_read_pts()
+
+flushing just the asf demuxer but not the cores buffers leads to inconsistencies
+and a "random" packet position which later causes an assertion failure
+
+Fixes Ticket2853
+
+Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
+---
+ libavformat/asfdec.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/libavformat/asfdec.c b/libavformat/asfdec.c
+index cffbcc4..0d6370d 100644
+--- a/libavformat/asfdec.c
++++ b/libavformat/asfdec.c
+@@ -1414,6 +1414,7 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index,
+ if (avio_seek(s->pb, pos, SEEK_SET) < 0)
+ return AV_NOPTS_VALUE;
+
++ ff_read_frame_flush(s);
+ asf_reset_header(s);
+ for (;;) {
+ if (av_read_frame(s, pkt) < 0) {
+--
+1.8.5.5
+
<constraints>
<options>languages</options>
<delimiter>,</delimiter>
- <minimum>1</minimum>
- <maximum>3</maximum>
+ <minimumItems>1</minimumItems>
+ <maximumItems>3</maximumItems>
</constraints>
<control type="list" format="string">
<multiselect>true</multiselect>
//We don't know if there is unsecure information in this yet, so we
//postpone any logging
const std::string in_actionStr(actionStr);
- CLog::Log(LOGDEBUG,"%s : Translating action string", __FUNCTION__);
CGUIInfoLabel info(actionStr, "");
actionStr = info.GetLabel(0);
return thumbFile;
}
+bool CFileItem::SkipLocalArt() const
+{
+ return (m_strPath.empty()
+ || StringUtils::StartsWithNoCase(m_strPath, "newsmartplaylist://")
+ || StringUtils::StartsWithNoCase(m_strPath, "newplaylist://")
+ || m_bIsShareOrDrive
+ || IsInternetStream()
+ || URIUtils::IsUPnP(m_strPath)
+ || (URIUtils::IsFTP(m_strPath) && !g_advancedSettings.m_bFTPThumbs)
+ || IsPlugin()
+ || IsAddonsPath()
+ || IsParentFolder()
+ || IsLiveTV()
+ || IsDVD());
+}
+
CStdString CFileItem::FindLocalArt(const std::string &artFile, bool useFolder) const
{
- // ignore a bunch that are meaningless
- if (m_strPath.empty()
- || StringUtils::StartsWithNoCase(m_strPath, "newsmartplaylist://")
- || StringUtils::StartsWithNoCase(m_strPath, "newplaylist://")
- || m_bIsShareOrDrive
- || IsInternetStream()
- || URIUtils::IsUPnP(m_strPath)
- || (URIUtils::IsFTP(m_strPath) && !g_advancedSettings.m_bFTPThumbs)
- || IsPlugin()
- || IsAddonsPath()
- || IsParentFolder()
- || IsLiveTV()
- || IsDVD())
+ if (SkipLocalArt())
return "";
CStdString thumb;
*/
CStdString FindLocalArt(const std::string &artFile, bool useFolder) const;
+ /*! \brief Whether or not to skip searching for local art.
+ \return true if local art should be skipped for this item, false otherwise.
+ \sa GetLocalArt, FindLocalArt
+ */
+ bool SkipLocalArt() const;
+
// Gets the .tbn file associated with this item
CStdString GetTBNFile() const;
// Gets the folder image associated with this item (defaults to folder.jpg)
using namespace XFILE;
using namespace ADDON;
-CNfoFile::NFOResult CNfoFile::Create(const CStdString& strPath, const ScraperPtr& info, int episode, const CStdString& strPath2)
+CNfoFile::NFOResult CNfoFile::Create(const CStdString& strPath, const ScraperPtr& info, int episode)
{
m_info = info; // assume we can use these settings
m_type = ScraperTypeFromContent(info->Content());
ERROR_NFO = 4
};
- NFOResult Create(const CStdString&, const ADDON::ScraperPtr&, int episode=-1,
- const CStdString& strPath2="");
+ NFOResult Create(const CStdString&, const ADDON::ScraperPtr&, int episode=-1);
template<class T>
bool GetDetails(T& details,const char* document=NULL, bool prioritise=false)
{
Context::~Context()
{
// cleanup
+ XbmcCommons::Exception::SetLogger(NULL);
+ CThread::SetLogger(NULL);
delete impl->loggerImpl;
delete impl;
return "default";
}
-bool CAEFactory::SupportsRaw(AEDataFormat format)
+bool CAEFactory::SupportsRaw(AEDataFormat format, int samplerate)
{
// check if passthrough is enabled
if (!CSettings::Get().GetBool("audiooutput.passthrough"))
return false;
if(AE)
- return AE->SupportsRaw(format);
+ return AE->SupportsRaw(format, samplerate);
return false;
}
static void EnumerateOutputDevices(AEDeviceList &devices, bool passthrough);
static void VerifyOutputDevice(std::string &device, bool passthrough);
static std::string GetDefaultDevice(bool passthrough);
- static bool SupportsRaw(AEDataFormat format);
+ static bool SupportsRaw(AEDataFormat format, int samplerate);
static bool SupportsSilenceTimeout();
/**
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();
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:
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 %d ms", __FUNCTION__, buffertime, MAX_BUFFER_TIME*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;
}
}
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)
}
}
-bool CActiveAE::SupportsRaw(AEDataFormat format)
+bool CActiveAE::SupportsRaw(AEDataFormat format, int samplerate)
{
- if (!m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), format))
+ if (!m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), format, samplerate))
return false;
return true;
}
else if (settingId == "audiooutput.truehdpassthrough")
{
- if (m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), AE_FMT_TRUEHD) &&
+ 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.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), AE_FMT_DTSHD) &&
+ 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) &&
+ if (m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), AE_FMT_EAC3, 192000) &&
CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED)
return true;
}
m_controlPort.SendOutMessage(CActiveAEControlProtocol::DISPLAYRESET);
}
+void CActiveAE::OnAppFocusChange(bool focus)
+{
+ m_controlPort.SendOutMessage(CActiveAEControlProtocol::APPFOCUSED, &focus, sizeof(focus));
+}
+
//-----------------------------------------------------------------------------
// Utils
//-----------------------------------------------------------------------------
GETSTATE,
DISPLAYLOST,
DISPLAYRESET,
+ APPFOCUSED,
KEEPCONFIG,
TIMEOUT,
};
virtual void EnumerateOutputDevices(AEDeviceList &devices, bool passthrough);
virtual std::string GetDefaultDevice(bool passthrough);
- virtual bool SupportsRaw(AEDataFormat format);
+ virtual bool SupportsRaw(AEDataFormat format, int samplerate);
virtual bool SupportsSilenceTimeout();
virtual bool SupportsQualityLevel(enum AEQuality level);
virtual bool IsSettingVisible(const std::string &settingId);
virtual void OnLostDevice();
virtual void OnResetDevice();
+ virtual void OnAppFocusChange(bool focus);
protected:
void PlaySound(CActiveAESound *sound);
return false;
}
-bool CActiveAESink::SupportsFormat(const std::string &device, AEDataFormat format)
+bool CActiveAESink::SupportsFormat(const std::string &device, AEDataFormat format, int samplerate)
{
std::string dev = device;
std::string dri;
AEDataFormatList::iterator itt3;
itt3 = find(info.m_dataFormats.begin(), info.m_dataFormats.end(), format);
if (itt3 != info.m_dataFormats.end())
- return true;
+ {
+ AESampleRateList::iterator itt4;
+ itt4 = find(info.m_sampleRates.begin(), info.m_sampleRates.end(), samplerate);
+ if (itt4 != info.m_sampleRates.end())
+ return true;
+ else
+ return false;
+ }
else
return false;
}
}
m_extError = false;
m_extSilenceTimer = 0;
+ m_extStreaming = false;
ReturnBuffers();
OpenSink();
msg->Reply(CSinkControlProtocol::ACC);
return;
+ case CSinkControlProtocol::APPFOCUSED:
+ m_extAppFocused = *(bool*)msg->data;
+ SetSilenceTimer();
+ m_extTimeout = 0;
+ return;
+
default:
break;
}
{
switch (signal)
{
- case CSinkControlProtocol::SILENCEMODE:
- bool silencemode;
- silencemode = *(bool*)msg->data;
- if (silencemode)
- m_extSilenceTimeout = XbmcThreads::EndTime::InfiniteValue;
- else
- m_extSilenceTimeout = CSettings::Get().GetInt("audiooutput.streamsilence") * 60000;
- m_extSilenceTimer.Set(m_extSilenceTimeout);
+ case CSinkControlProtocol::STREAMING:
+ m_extStreaming = *(bool*)msg->data;
+ SetSilenceTimer();
if (!m_extSilenceTimer.IsTimePast())
{
m_state = S_TOP_CONFIGURED_SILENCE;
- m_extTimeout = 0;
}
+ m_extTimeout = 0;
return;
case CSinkControlProtocol::VOLUME:
m_volume = *(float*)msg->data;
{
switch (signal)
{
- case CSinkControlProtocol::SILENCEMODE:
+ case CSinkControlProtocol::STREAMING:
+ m_extStreaming = *(bool*)msg->data;
+ SetSilenceTimer();
+ m_extTimeout = 0;
return;
case CSinkControlProtocol::VOLUME:
m_volume = *(float*)msg->data;
{
m_sink->Drain();
m_state = S_TOP_CONFIGURED_IDLE;
- m_extTimeout = 10000;
+ if (m_extAppFocused)
+ m_extTimeout = 10000;
+ else
+ m_extTimeout = 0;
}
return;
default:
m_state = S_TOP_UNCONFIGURED;
m_extTimeout = 1000;
m_bStateMachineSelfTrigger = false;
+ m_extAppFocused = true;
while (!m_bStop)
{
convertFn(noise, nb_floats, m_sampleOfSilence.pkt->data[0]);
_aligned_free(noise);
}
+
+void CActiveAESink::SetSilenceTimer()
+{
+ if (m_extStreaming)
+ m_extSilenceTimeout = XbmcThreads::EndTime::InfiniteValue;
+ else if (m_extAppFocused)
+ m_extSilenceTimeout = CSettings::Get().GetInt("audiooutput.streamsilence") * 60000;
+ else
+ m_extSilenceTimeout = 0;
+ m_extSilenceTimer.Set(m_extSilenceTimeout);
+}
{
CONFIGURE,
UNCONFIGURE,
- SILENCEMODE,
+ STREAMING,
+ APPFOCUSED,
VOLUME,
FLUSH,
TIMEOUT,
void Dispose();
AEDeviceType GetDeviceType(const std::string &device);
bool HasPassthroughDevice();
- bool SupportsFormat(const std::string &device, AEDataFormat format);
+ bool SupportsFormat(const std::string &device, AEDataFormat format, int samplerate);
CSinkControlProtocol m_controlPort;
CSinkDataProtocol m_dataPort;
void GetDeviceFriendlyName(std::string &device);
void OpenSink();
void ReturnBuffers();
+ void SetSilenceTimer();
unsigned int OutputSamples(CSampleBuffer* samples);
void ConvertInit(CSampleBuffer* samples);
int m_extTimeout;
bool m_extError;
unsigned int m_extSilenceTimeout;
+ bool m_extAppFocused;
+ bool m_extStreaming;
XbmcThreads::EndTime m_extSilenceTimer;
CSampleBuffer m_sampleOfSilence;
* @see CAEPackIEC61937::CAEPackIEC61937()
* @returns true if the AudioEngine is capable of RAW output
*/
- virtual bool SupportsRaw(AEDataFormat format) { return false; }
+ virtual bool SupportsRaw(AEDataFormat format, int samplerate) { return false; }
/**
* Returns true if the AudioEngine supports drain mode which is not streaming silence when idle
if (m_buffer->GetWriteSize() < frames * m_frameSize)
{ // no space to write - wait for a bit
CSingleLock lock(mutex);
+ unsigned int timeout = 900 * frames / m_sampleRate;
if (!m_started)
- condVar.wait(lock);
- else
- condVar.wait(lock, 900 * frames / m_sampleRate);
+ timeout = 500;
+
+ // we are using a timer here for beeing sure for timeouts
+ // condvar can be woken spuriously as signaled
+ XbmcThreads::EndTime timer(timeout);
+ condVar.wait(mutex, timeout);
+ if (!m_started && timer.IsTimePast())
+ return INT_MAX;
}
unsigned int write_frames = std::min(frames, m_buffer->GetWriteSize() / m_frameSize);
void CAAudioUnitSink::drain()
{
unsigned int bytes = m_buffer->GetReadSize();
- while (bytes)
+ unsigned int totalBytes = bytes;
+ int maxNumTimeouts = 3;
+ unsigned int timeout = 900 * bytes / (m_sampleRate * m_frameSize);
+ while (bytes && maxNumTimeouts > 0)
{
CSingleLock lock(mutex);
- condVar.wait(mutex, 900 * bytes / (m_sampleRate * m_frameSize));
+ XbmcThreads::EndTime timer(timeout);
+ condVar.wait(mutex, timeout);
+
bytes = m_buffer->GetReadSize();
+ // if we timeout and don't
+ // consum bytes - decrease maxNumTimeouts
+ if (timer.IsTimePast() && bytes == totalBytes)
+ maxNumTimeouts--;
+ totalBytes = bytes;
}
}
device.m_displayName = device.m_deviceName;
device.m_displayNameExtra = "";
- if (device.m_deviceName.find("HDMI") != std::string::npos)
- device.m_deviceType = AE_DEVTYPE_HDMI;
+ // flag indicating that passthroughformats where added throughout the stream enumeration
+ bool hasPassthroughFormats = false;
+ // the maximum number of channels found in the streams
+ UInt32 numMaxChannels = 0;
+ // the terminal type as reported by ca
+ UInt32 caTerminalType = 0;
+
+ bool isDigital = caDevice.IsDigital(caTerminalType);
+
CLog::Log(LOGDEBUG, "EnumerateDevices:Device(%s)" , device.m_deviceName.c_str());
AudioStreamIdList streams;
std::string formatString;
CLog::Log(LOGDEBUG, "EnumerateDevices:Format(%s)" ,
StreamDescriptionToString(desc, formatString));
+
// add stream format info
switch (desc.mFormatID)
{
device.m_dataFormats.push_back(AE_FMT_AC3);
if (!HasDataFormat(device.m_dataFormats, AE_FMT_DTS))
device.m_dataFormats.push_back(AE_FMT_DTS);
- // if we are not hdmi, this is an S/PDIF device
- if (device.m_deviceType != AE_DEVTYPE_HDMI)
- device.m_deviceType = AE_DEVTYPE_IEC958;
+ hasPassthroughFormats = true;
+ isDigital = true;// sanity - those are always digital devices!
break;
default:
AEDataFormat format = AE_FMT_INVALID;
format = AE_FMT_S16BE;
else
{
+ // if it is no digital stream per definition
+ // check if the device name suggests that it is digital
+ // (some hackintonshs are not so smart in announcing correct
+ // ca devices ...
+ if (!isDigital)
+ {
+ std::string devNameLower = device.m_deviceName;
+ StringUtils::ToLower(devNameLower);
+ isDigital = devNameLower.find("digital") != std::string::npos;
+ }
+
/* Passthrough is possible with a 2ch digital output */
- if (desc.mChannelsPerFrame == 2 && CCoreAudioStream::IsDigitalOuptut(*j))
+ if (desc.mChannelsPerFrame == 2 && isDigital)
{
if (desc.mSampleRate == 48000)
{
device.m_dataFormats.push_back(AE_FMT_AC3);
if (!HasDataFormat(device.m_dataFormats, AE_FMT_DTS))
device.m_dataFormats.push_back(AE_FMT_DTS);
+ hasPassthroughFormats = true;
}
else if (desc.mSampleRate == 192000)
{
if (!HasDataFormat(device.m_dataFormats, AE_FMT_EAC3))
device.m_dataFormats.push_back(AE_FMT_EAC3);
+ hasPassthroughFormats = true;
}
}
format = AE_FMT_S16LE;
}
break;
}
+
+ if (numMaxChannels < desc.mChannelsPerFrame)
+ numMaxChannels = desc.mChannelsPerFrame;
+
if (format != AE_FMT_INVALID && !HasDataFormat(device.m_dataFormats, format))
device.m_dataFormats.push_back(format);
break;
}
}
+
+ // flag indicating that the device name "sounds" like HDMI
+ bool hasHdmiName = device.m_deviceName.find("HDMI") != std::string::npos;
+ // flag indicating that the device name "sounds" like DisplayPort
+ bool hasDisplayPortName = device.m_deviceName.find("DisplayPort") != std::string::npos;
+
+ // decide the type of the device based on the discovered information
+ // in the streams
+ // device defaults to PCM (see start of the while loop)
+ // it can be HDMI, DisplayPort or Optical
+ // for all of those types it needs to support
+ // passthroughformats and needs to be a digital port
+ if (hasPassthroughFormats && isDigital)
+ {
+ // if the max number of channels was more then 2
+ // this can be HDMI or DisplayPort or Thunderbolt
+ if (numMaxChannels > 2)
+ {
+ // either the devicename suggests its HDMI
+ // or CA reported the terminalType as HDMI
+ if (hasHdmiName || caTerminalType == kIOAudioDeviceTransportTypeHdmi)
+ device.m_deviceType = AE_DEVTYPE_HDMI;
+
+ // either the devicename suggests its DisplayPort
+ // or CA reported the terminalType as DisplayPort or Thunderbolt
+ if (hasDisplayPortName || caTerminalType == kIOAudioDeviceTransportTypeDisplayPort || caTerminalType == kIOAudioDeviceTransportTypeThunderbolt)
+ device.m_deviceType = AE_DEVTYPE_DP;
+ }
+ else// treat all other digital passthrough devices as optical
+ device.m_deviceType = AE_DEVTYPE_IEC958;
+ }
+
+ // devicename based overwrites from former code - maybe FIXME at some point when we
+ // are sure that the upper detection does its job in all[tm] use cases
+ if (hasHdmiName)
+ device.m_deviceType = AE_DEVTYPE_HDMI;
+ if (hasDisplayPortName)
+ device.m_deviceType = AE_DEVTYPE_DP;
+
+
list.push_back(std::make_pair(deviceID, device));
//in the first place of the list add the default device
//with name "default" - if this is selected
if (m_buffer->GetWriteSize() < frames * m_format.m_frameSize)
{ // no space to write - wait for a bit
CSingleLock lock(mutex);
+ unsigned int timeout = 900 * frames / m_format.m_sampleRate;
if (!m_started)
- condVar.wait(lock);
- else
- condVar.wait(lock, 900 * frames / m_format.m_sampleRate);
+ timeout = 500;
+
+ // we are using a timer here for beeing sure for timeouts
+ // condvar can be woken spuriously as signaled
+ XbmcThreads::EndTime timer(timeout);
+ condVar.wait(mutex, timeout);
+ if (!m_started && timer.IsTimePast())
+ return INT_MAX;
}
unsigned int write_frames = std::min(frames, m_buffer->GetWriteSize() / m_format.m_frameSize);
void CAESinkDARWINOSX::Drain()
{
int bytes = m_buffer->GetReadSize();
- while (bytes)
+ int totalBytes = bytes;
+ int maxNumTimeouts = 3;
+ unsigned int timeout = 900 * bytes / (m_format.m_sampleRate * m_format.m_frameSize);
+ while (bytes && maxNumTimeouts > 0)
{
CSingleLock lock(mutex);
- condVar.wait(mutex, 900 * bytes / (m_format.m_sampleRate * m_format.m_frameSize));
+ XbmcThreads::EndTime timer(timeout);
+ condVar.wait(mutex, timeout);
+
bytes = m_buffer->GetReadSize();
+ // if we timeout and don't
+ // consum bytes - decrease maxNumTimeouts
+ if (timer.IsTimePast() && bytes == totalBytes)
+ maxNumTimeouts--;
+ totalBytes = bytes;
}
}
#define NUM_OMX_BUFFERS 2
#define AUDIO_PLAYBUFFER (1.0/20.0)
+static const unsigned int PassthroughSampleRates[] = { 8000, 11025, 16000, 22050, 24000, 32000, 41400, 48000, 88200, 96000, 176400, 192000 };
+
CAEDeviceInfo CAESinkPi::m_info;
CAESinkPi::CAESinkPi() :
m_info.m_displayNameExtra = "";
m_info.m_channels += AE_CH_FL;
m_info.m_channels += AE_CH_FR;
- m_info.m_sampleRates.push_back(48000);
+ for (unsigned int i=0; i<sizeof PassthroughSampleRates/sizeof *PassthroughSampleRates; i++)
+ m_info.m_sampleRates.push_back(PassthroughSampleRates[i]);
m_info.m_dataFormats.push_back(AE_FMT_S16LE);
m_info.m_dataFormats.push_back(AE_FMT_AC3);
m_info.m_dataFormats.push_back(AE_FMT_DTS);
return name;
}
+bool CCoreAudioDevice::IsDigital(UInt32 &transportType)
+{
+ bool isDigital = false;
+ if (!m_DeviceId)
+ return false;
+
+ AudioObjectPropertyAddress propertyAddress;
+ propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
+ propertyAddress.mElement = 0;
+ propertyAddress.mSelector = kAudioDevicePropertyTransportType;
+
+ UInt32 propertySize = sizeof(transportType);
+ OSStatus ret = AudioObjectGetPropertyData(m_DeviceId, &propertyAddress, 0, NULL, &propertySize, &transportType);
+ if (ret != noErr)
+ return false;
+
+ if (transportType == kIOAudioDeviceTransportTypeFireWire)
+ isDigital = true;
+ if (transportType == kIOAudioDeviceTransportTypeUSB)
+ isDigital = true;
+ if (transportType == kIOAudioDeviceTransportTypeHdmi)
+ isDigital = true;
+ if (transportType == kIOAudioDeviceTransportTypeDisplayPort)
+ isDigital = true;
+ if (transportType == kIOAudioDeviceTransportTypeThunderbolt)
+ isDigital = true;
+ if (transportType == kAudioStreamTerminalTypeDigitalAudioInterface)
+ isDigital = true;
+
+ return isDigital;
+}
+
UInt32 CCoreAudioDevice::GetTotalOutputChannels()
{
UInt32 channels = 0;
AudioDeviceID GetId() {return m_DeviceId;}
std::string GetName();
+ bool IsDigital(UInt32 &transportType);
UInt32 GetTotalOutputChannels();
bool GetStreams(AudioStreamIdList *pList);
bool IsRunning();
#include "utils/log.h"
#include "utils/StdString.h"
-// defines taken from CoreAudio/AudioHardware.h from SDK 10.8
-#if !defined kAudioStreamTerminalTypeHDMI
-#define kAudioStreamTerminalTypeHDMI 'hdmi'
-#endif
-
-#if !defined kAudioStreamTerminalTypeDisplayPort
-#define kAudioStreamTerminalTypeDisplayPort 'dprt'
-#endif
-
CCoreAudioStream::CCoreAudioStream() :
m_StreamId (0 )
{
return val;
}
+// WARNING - don't rely on this method - the return value of
+// GetTerminalType is driver specific - the checked return
+// values are only recommendations from apple
bool CCoreAudioStream::IsDigitalOuptut(AudioStreamID id)
{
UInt32 type = GetTerminalType(id);
+ // yes apple is mixing types here...
return (type == kAudioStreamTerminalTypeDigitalAudioInterface ||
- type == kAudioStreamTerminalTypeDisplayPort ||
- type == kAudioStreamTerminalTypeHDMI);
+ type == kIOAudioDeviceTransportTypeDisplayPort ||
+ type == kIOAudioDeviceTransportTypeHdmi ||
+ type == kIOAudioDeviceTransportTypeFireWire ||
+ type == kIOAudioDeviceTransportTypeThunderbolt ||
+ type == kIOAudioDeviceTransportTypeUSB);
}
UInt32 CCoreAudioStream::GetTerminalType(AudioStreamID id)
#include "threads/Event.h"
#include <CoreAudio/CoreAudio.h>
+#include <IOKit/audio/IOAudioTypes.h>
#include <list>
+// not defined in 10.6 sdk
+#ifndef kIOAudioDeviceTransportTypeThunderbolt
+#define kIOAudioDeviceTransportTypeThunderbolt 'thun'
+#endif
+
+
typedef std::list<AudioStreamID> AudioStreamIdList;
typedef std::list<AudioStreamRangedDescription> StreamFormatList;
bool CDVDAudioCodecPassthrough::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
{
- bool bSupportsAC3Out = CAEFactory::SupportsRaw(AE_FMT_AC3);
- bool bSupportsEAC3Out = CAEFactory::SupportsRaw(AE_FMT_EAC3);
- bool bSupportsDTSOut = CAEFactory::SupportsRaw(AE_FMT_DTS);
- bool bSupportsTrueHDOut = CAEFactory::SupportsRaw(AE_FMT_TRUEHD);
- bool bSupportsDTSHDOut = CAEFactory::SupportsRaw(AE_FMT_DTSHD);
+ bool bSupportsAC3Out = CAEFactory::SupportsRaw(AE_FMT_AC3, hints.samplerate);
+ bool bSupportsEAC3Out = CAEFactory::SupportsRaw(AE_FMT_EAC3, 192000);
+ bool bSupportsDTSOut = CAEFactory::SupportsRaw(AE_FMT_DTS, hints.samplerate);
+ bool bSupportsTrueHDOut = CAEFactory::SupportsRaw(AE_FMT_TRUEHD, 192000);
+ bool bSupportsDTSHDOut = CAEFactory::SupportsRaw(AE_FMT_DTSHD, 192000);
/* only get the dts core from the parser if we don't support dtsHD */
m_info.SetCoreOnly(!bSupportsDTSHDOut);
/* check our audio capabilties */
/* pathrought is overriding hw decode*/
- if(hints.codec == AV_CODEC_ID_AC3 && CAEFactory::SupportsRaw(AE_FMT_AC3) && !CSettings::Get().GetBool("audiooutput.dualaudio"))
+ if(hints.codec == AV_CODEC_ID_AC3 && CAEFactory::SupportsRaw(AE_FMT_AC3, hints.samplerate) && !CSettings::Get().GetBool("audiooutput.dualaudio"))
{
dataFormat = AE_FMT_AC3;
m_passthrough = true;
}
- if(hints.codec == AV_CODEC_ID_DTS && CAEFactory::SupportsRaw(AE_FMT_DTS) && !CSettings::Get().GetBool("audiooutput.dualaudio"))
+ if(hints.codec == AV_CODEC_ID_DTS && CAEFactory::SupportsRaw(AE_FMT_DTS, hints.samplerate) && !CSettings::Get().GetBool("audiooutput.dualaudio"))
{
dataFormat = AE_FMT_DTS;
m_passthrough = true;
double tpfbs[] = { 0, 384.0f, 1152.0f, 1152.0f };
frequency = freqtab[version][freqindex];
- tpf = tpfbs[layer] / (double) frequency;
- if (version == MPEG_VERSION2_5 || version == MPEG_VERSION2)
- tpf /= 2;
if (frequency == 0)
return 0;
+ tpf = tpfbs[layer] / (double) frequency;
+ if (version == MPEG_VERSION2_5 || version == MPEG_VERSION2)
+ tpf /= 2;
+
/* Channel mode (stereo/mono) */
int chmode = (mpegheader & 0xc0) >> 6;
/* calculate position of Xing VBR header */
m_isPaused = false; // Make sure to reset the pause state
}
- if (!QueueNextFileEx(file, false))
- return false;
+ // if audio engine is suspended i.e. by a DisplayLost event (HDMI), MakeStream
+ // waits until the engine is resumed. if we block the main thread here, it can't
+ // resume the engine after a DisplayReset event
+ if (CAEFactory::IsSuspended())
+ {
+ if (!QueueNextFile(file))
+ return false;
+ }
+ else
+ {
+ if (!QueueNextFileEx(file, false))
+ return false;
+ }
CSharedLock lock(m_streamsLock);
if (m_streams.size() == 2)
if (bAdd)
{
- if ((url.GetFileType().Equals("ac3") && !CAEFactory::SupportsRaw(AE_FMT_AC3))
- || (url.GetFileType().Equals("dts") && !CAEFactory::SupportsRaw(AE_FMT_DTS)))
+ if ((url.GetFileType().Equals("ac3"))
+ || (url.GetFileType().Equals("dts")))
{
CLog::Log(LOGDEBUG, "CPlayerCoreFactory::GetPlayers: adding DVDPlayer (%d)", EPC_DVDPLAYER);
vecCores.push_back(EPC_DVDPLAYER);
size_t loc;
// mysql doesn't understand CAST(foo as integer) => change to CAST(foo as signed integer)
- if ((loc = ci_find(qry, "as integer)")) != string::npos)
+ while ((loc = ci_find(qry, "as integer)")) != string::npos)
qry = qry.insert(loc + 3, "signed ");
MYSQL_RES *stmt = NULL;
bool focused = (channel == m_channelOffset + m_channelCursor) && (item == m_gridIndex[m_channelOffset + m_channelCursor][m_blockOffset + m_blockCursor].item);
- if (m_orientation == VERTICAL)
- ProcessItem(posA2, posB, item.get(), m_lastChannel, focused, m_programmeLayout, m_focusedProgrammeLayout, currentTime, dirtyregions, m_gridIndex[channel][block].width);
- else
- ProcessItem(posB, posA2, item.get(), m_lastChannel, focused, m_programmeLayout, m_focusedProgrammeLayout, currentTime, dirtyregions, m_gridIndex[channel][block].height);
+ // calculate the size to truncate if item is out of grid view
+ float truncateSize = 0;
+ if (posA2 < posA)
+ {
+ truncateSize = posA - posA2;
+ posA2 = posA; // reset to grid start position
+ }
- // increment our X position
if (m_orientation == VERTICAL)
{
+ // truncate item's width
+ m_gridIndex[channel][block].width = m_gridIndex[channel][block].originWidth - truncateSize;
+
+ ProcessItem(posA2, posB, item.get(), m_lastChannel, focused, m_programmeLayout, m_focusedProgrammeLayout, currentTime, dirtyregions, m_gridIndex[channel][block].width);
+
+ // increment our X position
posA2 += m_gridIndex[channel][block].width; // assumes focused & unfocused layouts have equal length
- block += (int)(m_gridIndex[channel][block].width / m_blockSize);
+ block += (int)(m_gridIndex[channel][block].originWidth / m_blockSize);
}
else
{
+ // truncate item's height
+ m_gridIndex[channel][block].height = m_gridIndex[channel][block].originHeight - truncateSize;
+
+ ProcessItem(posB, posA2, item.get(), m_lastChannel, focused, m_programmeLayout, m_focusedProgrammeLayout, currentTime, dirtyregions, m_gridIndex[channel][block].height);
+
+ // increment our X position
posA2 += m_gridIndex[channel][block].height; // assumes focused & unfocused layouts have equal length
- block += (int)(m_gridIndex[channel][block].height / m_blockSize);
+ block += (int)(m_gridIndex[channel][block].originHeight / m_blockSize);
}
}
bool focused = (channel == m_channelOffset + m_channelCursor) && (item == m_gridIndex[m_channelOffset + m_channelCursor][m_blockOffset + m_blockCursor].item);
+ // reset to grid start position if first item is out of grid view
+ if (posA2 < posA)
+ posA2 = posA;
+
// render our item
if (focused)
{
if (m_orientation == VERTICAL)
{
posA2 += m_gridIndex[channel][block].width; // assumes focused & unfocused layouts have equal length
- block += (int)(m_gridIndex[channel][block].width / m_blockSize);
+ block += (int)(m_gridIndex[channel][block].originWidth / m_blockSize);
}
else
{
posA2 += m_gridIndex[channel][block].height; // assumes focused & unfocused layouts have equal length
- block += (int)(m_gridIndex[channel][block].height / m_blockSize);
+ block += (int)(m_gridIndex[channel][block].originHeight / m_blockSize);
}
}
if (!item->GetFocusedLayout())
{
CGUIListItemLayout *layout = new CGUIListItemLayout(*focusedlayout);
- if (resize != -1.0f)
- {
- if (m_orientation == VERTICAL)
- layout->SetWidth(resize);
- else
- layout->SetHeight(resize);
- }
item->SetFocusedLayout(layout);
}
- if (item->GetFocusedLayout())
+
+ if (resize != -1.0f)
{
- if (item != lastitem || !HasFocus())
- {
- item->GetFocusedLayout()->SetFocusedItem(0);
- }
- if (item != lastitem && HasFocus())
- {
- item->GetFocusedLayout()->ResetAnimation(ANIM_TYPE_UNFOCUS);
- unsigned int subItem = 1;
- if (lastitem && lastitem->GetFocusedLayout())
- subItem = lastitem->GetFocusedLayout()->GetFocusedItem();
- item->GetFocusedLayout()->SetFocusedItem(subItem ? subItem : 1);
- }
- item->GetFocusedLayout()->Process(item,m_parentID,currentTime,dirtyregions);
+ if (m_orientation == VERTICAL)
+ item->GetFocusedLayout()->SetWidth(resize);
+ else
+ item->GetFocusedLayout()->SetHeight(resize);
+ }
+
+ if (item != lastitem || !HasFocus())
+ item->GetFocusedLayout()->SetFocusedItem(0);
+
+ if (item != lastitem && HasFocus())
+ {
+ item->GetFocusedLayout()->ResetAnimation(ANIM_TYPE_UNFOCUS);
+ unsigned int subItem = 1;
+ if (lastitem && lastitem->GetFocusedLayout())
+ subItem = lastitem->GetFocusedLayout()->GetFocusedItem();
+ item->GetFocusedLayout()->SetFocusedItem(subItem ? subItem : 1);
}
+
+ item->GetFocusedLayout()->Process(item, m_parentID, currentTime, dirtyregions);
lastitem = item;
}
else
{
- if (item->GetFocusedLayout())
- item->GetFocusedLayout()->SetFocusedItem(0); // focus is not set
if (!item->GetLayout())
{
CGUIListItemLayout *layout = new CGUIListItemLayout(*normallayout);
- if (resize != -1.0f)
- {
- if (m_orientation == VERTICAL)
- layout->SetWidth(resize);
- else
- layout->SetHeight(resize);
- }
item->SetLayout(layout);
}
+
+ if (resize != -1.0f)
+ {
+ if (m_orientation == VERTICAL)
+ item->GetLayout()->SetWidth(resize);
+ else
+ item->GetLayout()->SetHeight(resize);
+ }
+
+ if (item->GetFocusedLayout())
+ item->GetFocusedLayout()->SetFocusedItem(0);
+
if (item->GetFocusedLayout() && item->GetFocusedLayout()->IsAnimating(ANIM_TYPE_UNFOCUS))
- item->GetFocusedLayout()->Process(item,m_parentID,currentTime,dirtyregions);
- else if (item->GetLayout())
- item->GetLayout()->Process(item,m_parentID,currentTime,dirtyregions);
+ item->GetFocusedLayout()->Process(item, m_parentID, currentTime, dirtyregions);
+ else
+ item->GetLayout()->Process(item, m_parentID, currentTime, dirtyregions);
}
g_graphicsContext.RestoreOrigin();
}
if (m_orientation == VERTICAL)
{
- m_gridIndex[row][savedBlock].width = itemSize*m_blockSize;
- m_gridIndex[row][savedBlock].height = m_channelHeight;
+ m_gridIndex[row][savedBlock].originWidth = itemSize*m_blockSize;
+ m_gridIndex[row][savedBlock].originHeight = m_channelHeight;
}
else
{
- m_gridIndex[row][savedBlock].width = m_channelWidth;
- m_gridIndex[row][savedBlock].height = itemSize*m_blockSize;
+ m_gridIndex[row][savedBlock].originWidth = m_channelWidth;
+ m_gridIndex[row][savedBlock].originHeight = itemSize*m_blockSize;
}
+ m_gridIndex[row][savedBlock].width = m_gridIndex[row][savedBlock].originWidth;
+ m_gridIndex[row][savedBlock].height = m_gridIndex[row][savedBlock].originHeight;
+
itemSize = 1;
savedBlock = block+1;
}
struct GridItemsPtr
{
CGUIListItemPtr item;
+ float originWidth;
+ float originHeight;
float width;
float height;
};
virtual ~IDispResource() {};
virtual void OnLostDevice() {};
virtual void OnResetDevice() {};
+ virtual void OnAppFocusChange(bool focus) {};
};
#endif
void CGUIListGroup::EnlargeWidth(float difference)
{
- // Alters the width of the controls that have an ID of 1
+ // Alters the width of the controls that have an ID of 1 to 14
for (iControls it = m_children.begin(); it != m_children.end(); it++)
{
CGUIControl *child = *it;
if (child->GetID() >= 1 && child->GetID() <= 14)
{
- if (child->GetID() == 1) // label
+ if (child->GetID() == 1)
{
- child->SetWidth(child->GetWidth() + difference - 10);
- child->SetVisible(child->GetWidth() > 10); ///
+ child->SetWidth(child->GetWidth() + difference);
+ child->SetVisible(child->GetWidth() > 10);
}
else
{
void CGUIListGroup::EnlargeHeight(float difference)
{
- // Alters the width of the controls that have an ID of 1
+ // Alters the height of the controls that have an ID of 1 to 14
for (iControls it = m_children.begin(); it != m_children.end(); it++)
{
CGUIControl *child = *it;
if (child->GetID() >= 1 && child->GetID() <= 14)
{
- if (child->GetID() == 1) // label
+ if (child->GetID() == 1)
{
child->SetHeight(child->GetHeight() + difference);
- child->SetVisible(child->GetHeight() > 10); ///
+ child->SetVisible(child->GetHeight() > 10);
}
else
{
else if (m_label.GetLabelInfo().align & XBFONT_CENTER_X)
m_label.SetMaxRect(m_posX - m_width*0.5f, m_posY, m_width, m_height);
else
- m_label.SetMaxRect(m_posX, m_posY, m_posX + m_width, m_posY + m_height);
+ m_label.SetMaxRect(m_posX, m_posY, m_width, m_height);
CGUIControl::SetWidth(m_width);
}
if (ParameterNotNull(parameterObject, "year"))
album.iYear = (int)parameterObject["year"].asInteger();
- if (musicdatabase.UpdateAlbum(album) <= 0)
+ if (!musicdatabase.UpdateAlbum(album))
return InternalError;
CJSONRPCUtils::NotifyItemUpdated();
namespace JSONRPC
{
const char* const JSONRPC_SERVICE_ID = "http://xbmc.org/jsonrpc/ServiceDescription.json";
- const char* const JSONRPC_SERVICE_VERSION = "6.14.0";
+ const char* const JSONRPC_SERVICE_VERSION = "6.14.1";
const char* const JSONRPC_SERVICE_DESCRIPTION = "JSON-RPC API of XBMC";
const char* const JSONRPC_SERVICE_TYPES[] = {
"\"elementtype\": { \"$ref\": \"Setting.Type\", \"required\": true },"
"\"definition\": { \"$ref\": \"Setting.Details.Setting\", \"required\": true },"
"\"delimiter\": { \"type\": \"string\", \"required\": true },"
- "\"minimum\": { \"type\": \"integer\" },"
- "\"maximum\": { \"type\": \"integer\" }"
+ "\"minimumItems\": { \"type\": \"integer\" },"
+ "\"maximumItems\": { \"type\": \"integer\" }"
"},"
"\"additionalProperties\": false"
"}",
obj["elementtype"] = obj["definition"]["type"];
obj["delimiter"] = setting->GetDelimiter();
- obj["minimum"] = setting->GetMinimum();
- obj["maximum"] = setting->GetMaximum();
+ obj["minimumItems"] = setting->GetMinimumItems();
+ obj["maximumItems"] = setting->GetMaximumItems();
return true;
}
"elementtype": { "$ref": "Setting.Type", "required": true },
"definition": { "$ref": "Setting.Details.Setting", "required": true },
"delimiter": { "type": "string", "required": true },
- "minimum": { "type": "integer" },
- "maximum": { "type": "integer" }
+ "minimumItems": { "type": "integer" },
+ "maximumItems": { "type": "integer" }
},
"additionalProperties": false
},
{
XBMC_TRACE;
- if (dlg)
+ if (dlg && open)
{
DelayedCallGuard dg;
dlg->Close();
dlg = pDialog;
handle = pHandle;
+ open = true;
pHandle->SetTitle(heading);
if (!message.empty())
{
DelayedCallGuard dcguard(languageHook);
handle->MarkFinished();
+ open = false;
}
bool DialogProgressBG::isFinished()
{
CGUIDialogExtendedProgressBar* dlg;
CGUIDialogProgressBarHandle* handle;
+ bool open;
protected:
virtual void deallocating();
public:
- DialogProgressBG() : dlg(NULL), handle(NULL) {}
+ DialogProgressBG() : dlg(NULL), handle(NULL), open(false) {}
virtual ~DialogProgressBG();
void WindowXML::clearList()
{
XBMC_TRACE;
+ LOCKGUI;
A(ClearFileItems());
A(m_viewControl).SetItems(*(A(m_vecItems)));
String PythonLanguageHook::GetAddonId()
{
XBMC_TRACE;
- const char* id = NULL;
// Get a reference to the main module
// and global dictionary
// Extract a reference to the function "func_name"
// from the global dictionary
PyObject* pyid = PyDict_GetItemString(global_dict, "__xbmcaddonid__");
- id = PyString_AsString(pyid);
- return id;
+ if (pyid)
+ return PyString_AsString(pyid);
+ return "";
}
String PythonLanguageHook::GetAddonVersion()
// Extract a reference to the function "func_name"
// from the global dictionary
PyObject* pyversion = PyDict_GetItemString(global_dict, "__xbmcapiversion__");
- String version(PyString_AsString(pyversion));
- return version;
+ if (pyversion)
+ return PyString_AsString(pyversion);
+ return "";
}
void PythonLanguageHook::RegisterPlayerCallback(IPlayerCallback* player) { XBMC_TRACE; g_pythonParser.RegisterPythonPlayerCallBack(player); }
}
// handle nfo files
- CStdString strNfo = URIUtils::AddFileToFolder(album.strPath, "album.nfo");
+ CStdString path = album.strPath;
+ if (path.empty())
+ m_musicDatabase.GetAlbumPath(album.idAlbum, path);
+
+ CStdString strNfo = URIUtils::AddFileToFolder(path, "album.nfo");
CNfoFile::NFOResult result = CNfoFile::NO_NFO;
CNfoFile nfoReader;
if (XFILE::CFile::Exists(strNfo))
{
CLog::Log(LOGDEBUG,"Found matching nfo file: %s", strNfo.c_str());
- result = nfoReader.Create(strNfo, info, -1, album.strPath);
+ result = nfoReader.Create(strNfo, info);
if (result == CNfoFile::FULL_NFO)
{
CLog::Log(LOGDEBUG, "%s Got details from nfo", __FUNCTION__);
}
// handle nfo files
- CStdString strNfo = URIUtils::AddFileToFolder(artist.strPath, "artist.nfo");
+ CStdString path = artist.strPath;
+ if (path.empty())
+ m_musicDatabase.GetArtistPath(artist.idArtist, path);
+
+ CStdString strNfo = URIUtils::AddFileToFolder(path, "artist.nfo");
CNfoFile::NFOResult result=CNfoFile::NO_NFO;
CNfoFile nfoReader;
if (XFILE::CFile::Exists(strNfo))
mime == right.mime);
}
+void EmbeddedArtInfo::Archive(CArchive &ar)
+{
+ if (ar.IsStoring())
+ {
+ ar << size;
+ ar << mime;
+ }
+ else
+ {
+ ar >> size;
+ ar >> mime;
+ }
+}
+
EmbeddedArt::EmbeddedArt(const uint8_t *dat, size_t siz, const std::string &mim)
{
set(dat, siz, mim);
SetComment(song.strComment);
SetPlayCount(song.iTimesPlayed);
SetLastPlayed(song.lastPlayed);
+ SetCoverArtInfo(song.embeddedArt.size, song.embeddedArt.mime);
m_rating = song.rating;
m_strURL = song.strFileName;
SYSTEMTIME stTime;
ar << m_strLyrics;
ar << m_bCompilation;
ar << m_listeners;
+ ar << m_coverArt;
}
else
{
ar >> m_strLyrics;
ar >> m_bCompilation;
ar >> m_listeners;
+ ar >> m_coverArt;
}
}
namespace MUSIC_INFO
{
- class EmbeddedArtInfo
+ class EmbeddedArtInfo : public IArchivable
{
public:
EmbeddedArtInfo() {};
void clear();
bool empty() const;
bool matches(const EmbeddedArtInfo &right) const;
+ virtual void Archive(CArchive& ar);
size_t size;
std::string mime;
};
if (!m_musicdatabase.GetArtist(params.GetArtistId(), artist))
return;
+ m_musicdatabase.GetArtistPath(params.GetArtistId(), artist.strPath);
while (1)
{
// Check if we have the information in the database first
CGUIDialogMusicInfo *pDlgArtistInfo = (CGUIDialogMusicInfo*)g_windowManager.GetWindow(WINDOW_DIALOG_MUSIC_INFO);
if (pDlgArtistInfo)
{
- CStdString strPath;
- m_musicdatabase.GetArtistPath(params.GetArtistId(), strPath);
- pDlgArtistInfo->SetArtist(artist, strPath);
+ pDlgArtistInfo->SetArtist(artist, artist.strPath);
pDlgArtistInfo->DoModal();
if (pDlgArtistInfo->NeedRefresh())
if (!m_musicdatabase.GetAlbum(params.GetAlbumId(), album))
return false;
+ m_musicdatabase.GetAlbumPath(params.GetAlbumId(), album.strPath);
while (1)
{
if (!m_musicdatabase.HasAlbumBeenScraped(params.GetAlbumId()))
CGUIDialogMusicInfo *pDlgAlbumInfo = (CGUIDialogMusicInfo*)g_windowManager.GetWindow(WINDOW_DIALOG_MUSIC_INFO);
if (pDlgAlbumInfo)
{
- CStdString strPath;
- m_musicdatabase.GetAlbumPath(params.GetAlbumId(), strPath);
- pDlgAlbumInfo->SetAlbum(album, strPath);
+ pDlgAlbumInfo->SetAlbum(album, album.strPath);
pDlgAlbumInfo->DoModal();
if (pDlgAlbumInfo->NeedRefresh())
}
else if (pDlgAlbumInfo->HasUpdatedThumb())
{
- UpdateThumb(album, strPath);
+ UpdateThumb(album, album.strPath);
}
}
break;
// Archived data is already converted (EXIF_COMMENT_CHARSET_CONVERTED)
// Unknown data can't be converted as it could be any codec (EXIF_COMMENT_CHARSET_UNKNOWN)
// JIS data can't be converted as CharsetConverter and iconv lacks support (EXIF_COMMENT_CHARSET_JIS)
- value = m_exifInfo.Comments;
+ g_charsetConverter.unknownToUTF8(m_exifInfo.Comments, value);
}
break;
case SLIDE_EXIF_LONG_DATE_TIME:
}
results->AddFront(pItem, 0);
}
-
- // Add parent directory item
- if (!strUseBase.empty() && (subDirectories > 0 || files.Size() > 0) && CSettings::Get().GetBool("filelists.showparentdiritems"))
- {
- CStdString strLabel("..");
- CFileItemPtr pItem(new CFileItem(strLabel));
- pItem->SetPath("pvr://recordings");
- pItem->m_bIsShareOrDrive = false;
- results->AddFront(pItem, 0);
- }
}
bool CPVRRecordings::HasAllRecordingsPathExtension(const CStdString &strDirectory)
PVRWindow ActiveView = GetActiveView();
SaveViewToDb(m_items.GetPath(), ActiveView == PVR_WINDOW_UNKNOWN ? WINDOW_PVR : WINDOW_PVR + 100 - ActiveView, NULL);
}
+
+bool CGUIViewStatePVR::HideParentDirItems(void)
+{
+ return (CGUIViewState::HideParentDirItems() || PVR_WINDOW_RECORDINGS != GetActiveView() || m_items.GetPath() == "pvr://recordings/");
+}
PVRWindow GetActiveView(void);
protected:
bool AutoPlayNextItem(void) { return false; };
- bool HideParentDirItems(void) { return true; }
+ bool HideParentDirItems(void);
void SaveViewState(void);
};
}
void CGUIWindowPVRRecordings::BeforeUpdate(const CStdString &strDirectory)
{
+ // set items path to current directory
+ m_parent->m_vecItems->SetPath(strDirectory);
+
if (m_thumbLoader.IsLoading())
m_thumbLoader.StopThread();
}
: CSetting(id, settingsManager),
m_definition(settingDefinition),
m_delimiter("|"),
- m_minimum(0), m_maximum(-1)
+ m_minimumItems(0), m_maximumItems(-1)
{ }
CSettingList::CSettingList(const std::string &id, const CSettingList &setting)
: CSetting(id, setting),
m_definition(NULL),
m_delimiter("|"),
- m_minimum(0), m_maximum(-1)
+ m_minimumItems(0), m_maximumItems(-1)
{
copy(setting);
}
if (XMLUtils::GetString(constraints, SETTING_XML_ELM_DELIMITER, delimiter) && !delimiter.empty())
m_delimiter = delimiter;
- XMLUtils::GetInt(constraints, SETTING_XML_ELM_MINIMUM, m_minimum);
- if (m_minimum < 0)
- m_minimum = 0;
- XMLUtils::GetInt(constraints, SETTING_XML_ELM_MAXIMUM, m_maximum);
- if (m_maximum <= 0)
- m_maximum = -1;
- else if (m_maximum < m_minimum)
+ XMLUtils::GetInt(constraints, SETTING_XML_ELM_MINIMUM_ITEMS, m_minimumItems);
+ if (m_minimumItems < 0)
+ m_minimumItems = 0;
+ XMLUtils::GetInt(constraints, SETTING_XML_ELM_MAXIMUM_ITEMS, m_maximumItems);
+ if (m_maximumItems <= 0)
+ m_maximumItems = -1;
+ else if (m_maximumItems < m_minimumItems)
{
- CLog::Log(LOGWARNING, "CSettingList: invalid <minimum> (%d) and/or <maximum> (%d) of %s", m_minimum, m_maximum, m_id.c_str());
+ CLog::Log(LOGWARNING, "CSettingList: invalid <minimum> (%d) and/or <maximum> (%d) of %s", m_minimumItems, m_maximumItems, m_id.c_str());
return false;
}
}
{
CExclusiveLock lock(m_critical);
- if ((int)values.size() < m_minimum ||
- (m_maximum > 0 && (int)values.size() > m_maximum))
+ if ((int)values.size() < m_minimumItems ||
+ (m_maximumItems > 0 && (int)values.size() > m_maximumItems))
return false;
bool equal = values.size() == m_values.size();
}
m_delimiter = setting.m_delimiter;
- m_minimum = setting.m_minimum;
- m_maximum = setting.m_maximum;
+ m_minimumItems = setting.m_minimumItems;
+ m_maximumItems = setting.m_maximumItems;
}
void CSettingList::copy(const SettingPtrList &srcValues, SettingPtrList &dstValues)
bool CSettingList::fromValues(const std::vector<std::string> &strValues, SettingPtrList &values) const
{
- if ((int)strValues.size() < m_minimum ||
- (m_maximum > 0 && (int)strValues.size() > m_maximum))
+ if ((int)strValues.size() < m_minimumItems ||
+ (m_maximumItems > 0 && (int)strValues.size() > m_maximumItems))
return false;
bool ret = true;
const CSetting* GetDefinition() const { return m_definition; }
const std::string& GetDelimiter() const { return m_delimiter; }
- int GetMinimum() const { return m_minimum; }
- int GetMaximum() const { return m_maximum; }
+ int GetMinimumItems() const { return m_minimumItems; }
+ int GetMaximumItems() const { return m_maximumItems; }
bool FromString(const std::vector<std::string> &value);
SettingPtrList m_defaults;
CSetting *m_definition;
std::string m_delimiter;
- int m_minimum;
- int m_maximum;
+ int m_minimumItems;
+ int m_maximumItems;
};
/*!
#define SETTING_XML_ELM_UPDATE "update"
#define SETTING_XML_ELM_ACCESS "access"
#define SETTING_XML_ELM_DELIMITER "delimiter"
+#define SETTING_XML_ELM_MINIMUM_ITEMS "minimumitems"
+#define SETTING_XML_ELM_MAXIMUM_ITEMS "maximumitems"
#define SETTING_XML_ATTR_ID "id"
#define SETTING_XML_ATTR_LABEL "label"
}
CStdString realPath;
- int i = 0;
// re-add any / or \ at the beginning
- while (path.at(i) == delim.at(0))
+ for (std::string::const_iterator itPath = path.begin(); itPath != path.end(); ++itPath)
{
+ if (*itPath != delim.at(0))
+ break;
+
realPath += delim;
- i++;
}
// put together the path
realPath += StringUtils::Join(realParts, delim);
std::string CVideoThumbLoader::GetLocalArt(const CFileItem &item, const std::string &type, bool checkFolder)
{
+ if (item.SkipLocalArt())
+ return "";
+
/* Cache directory for (sub) folders on streamed filesystems. We need to do this
else entering (new) directories from the app thread becomes much slower. This
is caused by the fact that Curl Stat/Exist() is really slow and that the
const MONITOR_DETAILS &details = GetMonitor(screen);
DEVMODEW sDevMode;
- ZeroMemory(&sDevMode, sizeof(DEVMODE));
- sDevMode.dmSize = sizeof(DEVMODE);
+ ZeroMemory(&sDevMode, sizeof(sDevMode));
+ sDevMode.dmSize = sizeof(sDevMode);
if(!EnumDisplaySettingsW(details.DeviceNameW.c_str(), ENUM_CURRENT_SETTINGS, &sDevMode))
CLog::Log(LOGERROR, "%s : EnumDisplaySettings failed with %d", __FUNCTION__, GetLastError());
const MONITOR_DETAILS &details = GetMonitor(res.iScreen);
DEVMODEW sDevMode;
- ZeroMemory(&sDevMode, sizeof(DEVMODE));
- sDevMode.dmSize = sizeof(DEVMODE);
+ ZeroMemory(&sDevMode, sizeof(sDevMode));
+ sDevMode.dmSize = sizeof(sDevMode);
// If we can't read the current resolution or any detail of the resolution is different than res
if (!EnumDisplaySettingsW(details.DeviceNameW.c_str(), ENUM_CURRENT_SETTINGS, &sDevMode) ||
((sDevMode.dmDisplayFlags & DM_INTERLACED) && !(res.dwFlags & D3DPRESENTFLAG_INTERLACED)) ||
(!(sDevMode.dmDisplayFlags & DM_INTERLACED) && (res.dwFlags & D3DPRESENTFLAG_INTERLACED)) )
{
- ZeroMemory(&sDevMode, sizeof(DEVMODE));
- sDevMode.dmSize = sizeof(DEVMODE);
+ ZeroMemory(&sDevMode, sizeof(sDevMode));
+ sDevMode.dmSize = sizeof(sDevMode);
sDevMode.dmDriverExtra = 0;
sDevMode.dmPelsWidth = res.iWidth;
sDevMode.dmPelsHeight = res.iHeight;