1 #include <QMutexLocker>
12 #define LOC QString("Pulse: ")
14 #define IS_READY(arg) ((PA_CONTEXT_READY == arg) || \
15 (PA_CONTEXT_FAILED == arg) || \
16 (PA_CONTEXT_TERMINATED == arg))
20 QString ret =
"Unknown";
23 case PA_CONTEXT_UNCONNECTED: ret =
"Unconnected";
break;
24 case PA_CONTEXT_CONNECTING: ret =
"Connecting";
break;
25 case PA_CONTEXT_AUTHORIZING: ret =
"Authorizing";
break;
26 case PA_CONTEXT_SETTING_NAME: ret =
"Setting Name";
break;
27 case PA_CONTEXT_READY: ret =
"Ready!";
break;
28 case PA_CONTEXT_FAILED: ret =
"Failed";
break;
29 case PA_CONTEXT_TERMINATED: ret =
"Terminated";
break;
40 static QMutex global_lock;
41 QMutexLocker locker(&global_lock);
48 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Cleaning up PulseHandler");
58 LOG(VB_AUDIO, LOG_INFO,
LOC +
"PulseAudio not running");
65 LOG(VB_AUDIO, LOG_INFO,
LOC +
"PulseHandler invalidated. Deleting.");
76 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Created PulseHandler object");
81 LOG(VB_GENERAL, LOG_ERR,
LOC +
82 "Failed to create PulseHandler object");
108 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Callback: no handler.");
112 if (handler->
m_ctx != ctx)
114 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Callback: handler/context mismatch.");
118 if (handler != PulseHandler::g_pulseHandler)
120 LOG(VB_GENERAL, LOG_ERR,
121 "Callback: returned handler is not the global handler.");
126 pa_context_state state = pa_context_get_state(ctx);
127 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"Callback: State changed %1->%2")
141 LOG(VB_GENERAL, LOG_WARNING,
LOC +
142 "Received a late/unexpected operation callback. Ignoring.");
150 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Operation: no handler.");
154 if (handler->
m_ctx != ctx)
156 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Operation: handler/context mismatch.");
160 if (handler != PulseHandler::g_pulseHandler)
162 LOG(VB_GENERAL, LOG_ERR,
LOC +
163 "Operation: returned handler is not the global handler.");
169 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"Operation: success %1 remaining %2")
174 : m_ctx_state(PA_CONTEXT_UNCONNECTED), m_ctx(NULL), m_pending_operations(0),
175 m_loop(NULL), m_initialised(
false), m_valid(
false),
184 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Destroying PulseAudio handler");
189 pa_context_disconnect(
m_ctx);
190 pa_context_unref(
m_ctx);
217 m_loop = pa_mainloop_new();
220 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to get PulseAudio mainloop");
224 pa_mainloop_api *api = pa_mainloop_get_api(
m_loop);
227 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to get PulseAudio api");
231 if (pa_signal_init(api) != 0)
233 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to initialise signaling");
237 const char *client =
"mythtv";
238 m_ctx = pa_context_new(api, client);
241 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to create context");
246 m_thread = QThread::currentThread();
251 pa_context_connect(
m_ctx, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL);
256 pa_mainloop_iterate(
m_loop, 0, &ret);
262 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Context not ready after 1000ms");
266 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Initialised handler");
279 LOG(VB_AUDIO, LOG_WARNING,
LOC +
280 "PulseHandler called from a different thread");
282 QString
action = suspend ?
"suspend" :
"resume";
284 if (!pa_context_is_local(
m_ctx))
286 LOG(VB_GENERAL, LOG_ERR,
LOC +
287 "PulseAudio server is remote. No need to " + action);
294 pa_operation *operation_sink =
295 pa_context_suspend_sink_by_index(
297 pa_operation_unref(operation_sink);
299 pa_operation *operation_source =
300 pa_context_suspend_source_by_index(
302 pa_operation_unref(operation_source);
309 pa_mainloop_iterate(
m_loop, 0, &ret);
317 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to " + action);
322 LOG(VB_GENERAL, LOG_INFO,
LOC +
"PulseAudio " + action +
" OK");