aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrent Nelson <trent.a.b.nelson@gmail.com>2014-02-21 12:09:34 -0700
committerTrent Nelson <trent.a.b.nelson@gmail.com>2014-02-21 12:09:34 -0700
commit4298c43dc3a6d80cc60a55172c68f10544b479cb (patch)
tree83a5e615e34b2c7d755df2be36f1db63940dc462
parentaf78970361fe4651198bc96994b8fe9b4fdc052e (diff)
parentdfb802828cd1d8defff8121d081ab56611cef7ca (diff)
Merge pull request #4133 from FernetMenta/aefixes
ActiveAE: add method for re-init after device/eld change
-rw-r--r--xbmc/cores/AudioEngine/AEFactory.cpp6
-rw-r--r--xbmc/cores/AudioEngine/AEFactory.h1
-rw-r--r--xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp35
-rw-r--r--xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h4
-rw-r--r--xbmc/cores/AudioEngine/Interfaces/AE.h5
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp57
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkPULSE.h4
-rw-r--r--xbmc/utils/ActorProtocol.cpp44
-rw-r--r--xbmc/utils/ActorProtocol.h2
9 files changed, 155 insertions, 3 deletions
diff --git a/xbmc/cores/AudioEngine/AEFactory.cpp b/xbmc/cores/AudioEngine/AEFactory.cpp
index 3094bdf7fd..fff42a6130 100644
--- a/xbmc/cores/AudioEngine/AEFactory.cpp
+++ b/xbmc/cores/AudioEngine/AEFactory.cpp
@@ -404,3 +404,9 @@ void CAEFactory::KeepConfiguration(unsigned int millis)
if (AE)
AE->KeepConfiguration(millis);
}
+
+void CAEFactory::DeviceChange()
+{
+ if (AE)
+ AE->DeviceChange();
+}
diff --git a/xbmc/cores/AudioEngine/AEFactory.h b/xbmc/cores/AudioEngine/AEFactory.h
index 9a340cc3c1..1d55513464 100644
--- a/xbmc/cores/AudioEngine/AEFactory.h
+++ b/xbmc/cores/AudioEngine/AEFactory.h
@@ -76,6 +76,7 @@ public:
static void SettingOptionsAudioStreamsilenceFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int &current);
static bool IsSettingVisible(const std::string &condition, const std::string &value, const std::string &settingId);
static void KeepConfiguration(unsigned int millis);
+ static void DeviceChange();
static void RegisterAudioCallback(IAudioCallback* pCallback);
static void UnregisterAudioCallback();
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
index 63a8983d04..c871ee893e 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
@@ -425,6 +425,36 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg)
}
msg->Reply(CActiveAEControlProtocol::ACC);
return;
+ case CActiveAEControlProtocol::DEVICECHANGE:
+ time_t now;
+ time(&now);
+ 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_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;
+ }
+ m_controlPort.PurgeOut(CActiveAEControlProtocol::DEVICECHANGE);
+ return;
case CActiveAEControlProtocol::PAUSESTREAM:
CActiveAEStream *stream;
stream = *(CActiveAEStream**)msg->data;
@@ -2292,6 +2322,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;
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h
index debc8e140f..225c694775 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h
@@ -28,6 +28,7 @@
#include "cores/AudioEngine/Interfaces/AESound.h"
#include "cores/AudioEngine/AEFactory.h"
#include "guilib/DispResource.h"
+#include <queue>
// ffmpeg
#include "DllAvFormat.h"
@@ -73,6 +74,7 @@ public:
INIT = 0,
RECONFIGURE,
SUSPEND,
+ DEVICECHANGE,
MUTE,
VOLUME,
PAUSESTREAM,
@@ -224,6 +226,7 @@ public:
virtual bool SupportsQualityLevel(enum AEQuality level);
virtual bool IsSettingVisible(const std::string &settingId);
virtual void KeepConfiguration(unsigned int millis);
+ virtual void DeviceChange();
virtual void RegisterAudioCallback(IAudioCallback* pCallback);
virtual void UnregisterAudioCallback();
@@ -292,6 +295,7 @@ protected:
XbmcThreads::EndTime m_extDrainTimer;
unsigned int m_extKeepConfig;
bool m_extDeferData;
+ std::queue<time_t> m_extLastDeviceChange;
enum
{
diff --git a/xbmc/cores/AudioEngine/Interfaces/AE.h b/xbmc/cores/AudioEngine/Interfaces/AE.h
index f91dc4c369..dd3289746f 100644
--- a/xbmc/cores/AudioEngine/Interfaces/AE.h
+++ b/xbmc/cores/AudioEngine/Interfaces/AE.h
@@ -232,5 +232,10 @@ public:
* @param millis time for which old configuration should be kept
*/
virtual void KeepConfiguration(unsigned int millis) {return; }
+
+ /**
+ * Instruct AE to re-initialize, e.g. after ELD change event
+ */
+ virtual void DeviceChange() {return; }
};
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp
index a04a2a8d24..127fc62ea5 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp
@@ -189,6 +189,34 @@ static void StreamLatencyUpdateCallback(pa_stream *s, void *userdata)
pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
pa_threaded_mainloop_signal(m, 0);
}
+
+static void SinkChangedCallback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata)
+{
+ CAESinkPULSE* p = (CAESinkPULSE*) userdata;
+ if(!p)
+ return;
+
+ CSingleLock lock(p->m_sec);
+ if (p->IsInitialized())
+ {
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW)
+ {
+ CLog::Log(LOGDEBUG, "Sink appeared");
+ CAEFactory::DeviceChange();
+ }
+ else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
+ {
+ CLog::Log(LOGDEBUG, "Sink removed");
+ CAEFactory::DeviceChange();
+ }
+ else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_CHANGE)
+ {
+ CLog::Log(LOGDEBUG, "Sink changed");
+ //CAEFactory::DeviceChange();
+ }
+ }
+}
+
struct SinkInfoStruct
{
AEDeviceInfoList *list;
@@ -406,7 +434,10 @@ CAESinkPULSE::~CAESinkPULSE()
bool CAESinkPULSE::Initialize(AEAudioFormat &format, std::string &device)
{
- m_IsAllocated = false;
+ {
+ CSingleLock lock(m_sec);
+ m_IsAllocated = false;
+ }
m_passthrough = false;
m_BytesPerSecond = 0;
m_BufferSize = 0;
@@ -423,6 +454,16 @@ bool CAESinkPULSE::Initialize(AEAudioFormat &format, std::string &device)
pa_threaded_mainloop_lock(m_MainLoop);
+ {
+ // Register Callback for Sink changes
+ CSingleLock lock(m_sec);
+ pa_context_set_subscribe_callback(m_Context, SinkChangedCallback, this);
+ const pa_subscription_mask_t mask = PA_SUBSCRIPTION_MASK_SINK;
+ pa_operation *op = pa_context_subscribe(m_Context, mask, NULL, this);
+ if (op != NULL)
+ pa_operation_unref(op);
+ }
+
struct pa_channel_map map;
pa_channel_map_init(&map);
@@ -595,20 +636,24 @@ bool CAESinkPULSE::Initialize(AEAudioFormat &format, std::string &device)
}
pa_threaded_mainloop_unlock(m_MainLoop);
-
- m_IsAllocated = true;
+
format.m_frameSize = frameSize;
format.m_frameSamples = format.m_frames * format.m_channelLayout.Count();
m_format = format;
format.m_dataFormat = m_passthrough ? AE_FMT_S16NE : format.m_dataFormat;
Pause(false);
+ {
+ CSingleLock lock(m_sec);
+ m_IsAllocated = true;
+ }
return true;
}
void CAESinkPULSE::Deinitialize()
{
+ CSingleLock lock(m_sec);
m_IsAllocated = false;
m_passthrough = false;
@@ -764,6 +809,12 @@ void CAESinkPULSE::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
}
}
+bool CAESinkPULSE::IsInitialized()
+{
+ CSingleLock lock(m_sec);
+ return m_IsAllocated;
+}
+
bool CAESinkPULSE::Pause(bool pause)
{
pa_threaded_mainloop_lock(m_MainLoop);
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.h b/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.h
index 9fa301f00f..39fda73a86 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.h
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.h
@@ -22,9 +22,11 @@
#include "system.h"
#include "cores/AudioEngine/Interfaces/AESink.h"
+#include "cores/AudioEngine/AEFactory.h"
#include "Utils/AEDeviceInfo.h"
#include "Utils/AEUtil.h"
#include <pulse/pulseaudio.h>
+#include "threads/CriticalSection.h"
class CAESinkPULSE : public IAESink
{
@@ -46,6 +48,8 @@ public:
virtual void SetVolume(float volume);
static void EnumerateDevicesEx(AEDeviceInfoList &list, bool force = false);
+ bool IsInitialized();
+ CCriticalSection m_sec;
private:
bool Pause(bool pause);
static inline bool WaitForOperation(pa_operation *op, pa_threaded_mainloop *mainloop, const char *LogEntry);
diff --git a/xbmc/utils/ActorProtocol.cpp b/xbmc/utils/ActorProtocol.cpp
index ac5b5ebe17..9ea07bd5d6 100644
--- a/xbmc/utils/ActorProtocol.cpp
+++ b/xbmc/utils/ActorProtocol.cpp
@@ -251,3 +251,47 @@ void Protocol::Purge()
while (ReceiveOutMessage(&msg))
msg->Release();
}
+
+void Protocol::PurgeIn(int signal)
+{
+ Message *msg;
+ std::queue<Message*> msgs;
+
+ CSingleLock lock(criticalSection);
+
+ while (!inMessages.empty())
+ {
+ msg = inMessages.front();
+ inMessages.pop();
+ if (msg->signal != signal)
+ msgs.push(msg);
+ }
+ while (!msgs.empty())
+ {
+ msg = msgs.front();
+ msgs.pop();
+ inMessages.push(msg);
+ }
+}
+
+void Protocol::PurgeOut(int signal)
+{
+ Message *msg;
+ std::queue<Message*> msgs;
+
+ CSingleLock lock(criticalSection);
+
+ while (!outMessages.empty())
+ {
+ msg = outMessages.front();
+ outMessages.pop();
+ if (msg->signal != signal)
+ msgs.push(msg);
+ }
+ while (!msgs.empty())
+ {
+ msg = msgs.front();
+ msgs.pop();
+ outMessages.push(msg);
+ }
+}
diff --git a/xbmc/utils/ActorProtocol.h b/xbmc/utils/ActorProtocol.h
index 336da06492..100b1acd0b 100644
--- a/xbmc/utils/ActorProtocol.h
+++ b/xbmc/utils/ActorProtocol.h
@@ -69,6 +69,8 @@ public:
bool ReceiveOutMessage(Message **msg);
bool ReceiveInMessage(Message **msg);
void Purge();
+ void PurgeIn(int signal);
+ void PurgeOut(int signal);
void DeferIn(bool value) {inDefered = value;};
void DeferOut(bool value) {outDefered = value;};
void Lock() {criticalSection.lock();};