2 * Copyright (C) 2010-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
22 #include "AESinkPULSE.h"
23 #include "utils/log.h"
25 #include "guilib/LocalizeStrings.h"
29 static const char *ContextStateToString(pa_context_state s)
33 case PA_CONTEXT_UNCONNECTED:
35 case PA_CONTEXT_CONNECTING:
37 case PA_CONTEXT_AUTHORIZING:
39 case PA_CONTEXT_SETTING_NAME:
40 return "setting name";
41 case PA_CONTEXT_READY:
43 case PA_CONTEXT_FAILED:
45 case PA_CONTEXT_TERMINATED:
52 static const char *StreamStateToString(pa_stream_state s)
56 case PA_STREAM_UNCONNECTED:
58 case PA_STREAM_CREATING:
62 case PA_STREAM_FAILED:
64 case PA_STREAM_TERMINATED:
71 static pa_sample_format AEFormatToPulseFormat(AEDataFormat format)
75 case AE_FMT_U8 : return PA_SAMPLE_U8;
76 case AE_FMT_S16LE : return PA_SAMPLE_S16LE;
77 case AE_FMT_S16BE : return PA_SAMPLE_S16BE;
78 case AE_FMT_S16NE : return PA_SAMPLE_S16NE;
79 case AE_FMT_S24LE3: return PA_SAMPLE_S24LE;
80 case AE_FMT_S24BE3: return PA_SAMPLE_S24BE;
81 case AE_FMT_S24NE3: return PA_SAMPLE_S24NE;
82 case AE_FMT_S24LE4: return PA_SAMPLE_S24_32LE;
83 case AE_FMT_S24BE4: return PA_SAMPLE_S24_32BE;
84 case AE_FMT_S24NE4: return PA_SAMPLE_S24_32NE;
85 case AE_FMT_S32BE : return PA_SAMPLE_S32BE;
86 case AE_FMT_S32LE : return PA_SAMPLE_S32LE;
87 case AE_FMT_S32NE : return PA_SAMPLE_S32NE;
88 case AE_FMT_FLOAT : return PA_SAMPLE_FLOAT32;
93 return PA_SAMPLE_S16NE;
96 return PA_SAMPLE_INVALID;
100 static pa_encoding AEFormatToPulseEncoding(AEDataFormat format)
104 case AE_FMT_AC3 : return PA_ENCODING_AC3_IEC61937;
105 case AE_FMT_DTS : return PA_ENCODING_DTS_IEC61937;
106 case AE_FMT_EAC3 : return PA_ENCODING_EAC3_IEC61937;
109 return PA_ENCODING_PCM;
113 static AEDataFormat defaultDataFormats[] = {
130 static unsigned int defaultSampleRates[] = {
147 /* Static callback functions */
149 static void ContextStateCallback(pa_context *c, void *userdata)
151 pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
152 switch (pa_context_get_state(c))
154 case PA_CONTEXT_READY:
155 case PA_CONTEXT_TERMINATED:
156 case PA_CONTEXT_UNCONNECTED:
157 case PA_CONTEXT_CONNECTING:
158 case PA_CONTEXT_AUTHORIZING:
159 case PA_CONTEXT_SETTING_NAME:
160 case PA_CONTEXT_FAILED:
161 pa_threaded_mainloop_signal(m, 0);
166 static void StreamStateCallback(pa_stream *s, void *userdata)
168 pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
169 switch (pa_stream_get_state(s))
171 case PA_STREAM_UNCONNECTED:
172 case PA_STREAM_CREATING:
173 case PA_STREAM_READY:
174 case PA_STREAM_FAILED:
175 case PA_STREAM_TERMINATED:
176 pa_threaded_mainloop_signal(m, 0);
181 static void StreamRequestCallback(pa_stream *s, size_t length, void *userdata)
183 pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
184 pa_threaded_mainloop_signal(m, 0);
187 static void StreamLatencyUpdateCallback(pa_stream *s, void *userdata)
189 pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
190 pa_threaded_mainloop_signal(m, 0);
192 struct SinkInfoStruct
194 AEDeviceInfoList *list;
197 pa_threaded_mainloop *mainloop;
207 static void SinkInfoCallback(pa_context *c, const pa_sink_info *i, int eol, void *userdata)
209 SinkInfoStruct *sinkStruct = (SinkInfoStruct *)userdata;
212 if (i->flags && (i->flags & PA_SINK_HARDWARE))
213 sinkStruct->isHWDevice = true;
215 sinkStruct->device_found = true;
217 pa_threaded_mainloop_signal(sinkStruct->mainloop, 0);
220 static AEChannel PAChannelToAEChannel(pa_channel_position_t channel)
222 AEChannel ae_channel;
225 case PA_CHANNEL_POSITION_FRONT_LEFT: ae_channel = AE_CH_FL; break;
226 case PA_CHANNEL_POSITION_FRONT_RIGHT: ae_channel = AE_CH_FR; break;
227 case PA_CHANNEL_POSITION_FRONT_CENTER: ae_channel = AE_CH_FC; break;
228 case PA_CHANNEL_POSITION_LFE: ae_channel = AE_CH_LFE; break;
229 case PA_CHANNEL_POSITION_REAR_LEFT: ae_channel = AE_CH_BL; break;
230 case PA_CHANNEL_POSITION_REAR_RIGHT: ae_channel = AE_CH_BR; break;
231 case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER: ae_channel = AE_CH_FLOC; break;
232 case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: ae_channel = AE_CH_FROC; break;
233 case PA_CHANNEL_POSITION_REAR_CENTER: ae_channel = AE_CH_BC; break;
234 case PA_CHANNEL_POSITION_SIDE_LEFT: ae_channel = AE_CH_SL; break;
235 case PA_CHANNEL_POSITION_SIDE_RIGHT: ae_channel = AE_CH_SR; break;
236 case PA_CHANNEL_POSITION_TOP_FRONT_LEFT: ae_channel = AE_CH_TFL; break;
237 case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT: ae_channel = AE_CH_TFR; break;
238 case PA_CHANNEL_POSITION_TOP_FRONT_CENTER: ae_channel = AE_CH_TFC; break;
239 case PA_CHANNEL_POSITION_TOP_CENTER: ae_channel = AE_CH_TC; break;
240 case PA_CHANNEL_POSITION_TOP_REAR_LEFT: ae_channel = AE_CH_TBL; break;
241 case PA_CHANNEL_POSITION_TOP_REAR_RIGHT: ae_channel = AE_CH_TBR; break;
242 case PA_CHANNEL_POSITION_TOP_REAR_CENTER: ae_channel = AE_CH_TBC; break;
243 default: ae_channel = AE_CH_NULL; break;
248 static pa_channel_position_t AEChannelToPAChannel(AEChannel ae_channel)
250 pa_channel_position_t pa_channel;
253 case AE_CH_FL: pa_channel = PA_CHANNEL_POSITION_FRONT_LEFT; break;
254 case AE_CH_FR: pa_channel = PA_CHANNEL_POSITION_FRONT_RIGHT; break;
255 case AE_CH_FC: pa_channel = PA_CHANNEL_POSITION_FRONT_CENTER; break;
256 case AE_CH_LFE: pa_channel = PA_CHANNEL_POSITION_LFE; break;
257 case AE_CH_BL: pa_channel = PA_CHANNEL_POSITION_REAR_LEFT; break;
258 case AE_CH_BR: pa_channel = PA_CHANNEL_POSITION_REAR_RIGHT; break;
259 case AE_CH_FLOC: pa_channel = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER; break;
260 case AE_CH_FROC: pa_channel = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; break;
261 case AE_CH_BC: pa_channel = PA_CHANNEL_POSITION_REAR_CENTER; break;
262 case AE_CH_SL: pa_channel = PA_CHANNEL_POSITION_SIDE_LEFT; break;
263 case AE_CH_SR: pa_channel = PA_CHANNEL_POSITION_SIDE_RIGHT; break;
264 case AE_CH_TFL: pa_channel = PA_CHANNEL_POSITION_TOP_FRONT_LEFT; break;
265 case AE_CH_TFR: pa_channel = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT; break;
266 case AE_CH_TFC: pa_channel = PA_CHANNEL_POSITION_TOP_FRONT_CENTER; break;
267 case AE_CH_TC: pa_channel = PA_CHANNEL_POSITION_TOP_CENTER; break;
268 case AE_CH_TBL: pa_channel = PA_CHANNEL_POSITION_TOP_REAR_LEFT; break;
269 case AE_CH_TBR: pa_channel = PA_CHANNEL_POSITION_TOP_REAR_RIGHT; break;
270 case AE_CH_TBC: pa_channel = PA_CHANNEL_POSITION_TOP_REAR_CENTER; break;
271 default: pa_channel = PA_CHANNEL_POSITION_INVALID; break;
276 static pa_channel_map AEChannelMapToPAChannel(CAEChannelInfo info)
279 pa_channel_map_init(&map);
280 pa_channel_position_t pos;
281 for (unsigned int i = 0; i < info.Count(); ++i)
283 pos = AEChannelToPAChannel(info[i]);
284 if(pos != PA_CHANNEL_POSITION_INVALID)
286 // remember channel name and increase channel count
287 map.map[map.channels++] = pos;
293 static CAEChannelInfo PAChannelToAEChannelMap(pa_channel_map channels)
298 for (unsigned int i=0; i<channels.channels; i++)
300 ch = PAChannelToAEChannel(channels.map[i]);
307 static void SinkInfoRequestCallback(pa_context *c, const pa_sink_info *i, int eol, void *userdata)
310 SinkInfoStruct *sinkStruct = (SinkInfoStruct *)userdata;
312 if(sinkStruct && sinkStruct->list->empty())
314 //add a default device first
315 CAEDeviceInfo defaultDevice;
316 defaultDevice.m_deviceName = std::string("Default");
317 defaultDevice.m_displayName = std::string("Default");
318 defaultDevice.m_displayNameExtra = std::string("Default Output Device (PULSEAUDIO)");
319 defaultDevice.m_dataFormats.insert(defaultDevice.m_dataFormats.end(), defaultDataFormats, defaultDataFormats + sizeof(defaultDataFormats) / sizeof(defaultDataFormats[0]));
320 defaultDevice.m_channels = CAEChannelInfo(AE_CH_LAYOUT_2_0);
321 defaultDevice.m_sampleRates.assign(defaultSampleRates, defaultSampleRates + sizeof(defaultSampleRates) / sizeof(defaultSampleRates[0]));
322 defaultDevice.m_deviceType = AE_DEVTYPE_PCM;
323 sinkStruct->list->push_back(defaultDevice);
328 CAEDeviceInfo device;
330 device.m_deviceName = string(i->name);
331 device.m_displayName = string(i->description);
332 if (i->active_port && i->active_port->description)
333 device.m_displayNameExtra = std::string((i->active_port->description)).append(" (PULSEAUDIO)");
335 device.m_displayNameExtra = std::string((i->description)).append(" (PULSEAUDIO)");
336 unsigned int device_type = AE_DEVTYPE_PCM; //0
338 device.m_channels = PAChannelToAEChannelMap(i->channel_map);
340 // Don't add devices that would not have a channel map
341 if(device.m_channels.Count() == 0)
344 device.m_sampleRates.assign(defaultSampleRates, defaultSampleRates + sizeof(defaultSampleRates) / sizeof(defaultSampleRates[0]));
346 for (unsigned int j = 0; j < i->n_formats; j++)
348 switch(i->formats[j]->encoding)
350 case PA_ENCODING_AC3_IEC61937:
351 device.m_dataFormats.push_back(AE_FMT_AC3);
352 device_type = AE_DEVTYPE_IEC958;
354 case PA_ENCODING_DTS_IEC61937:
355 device.m_dataFormats.push_back(AE_FMT_DTS);
356 device_type = AE_DEVTYPE_IEC958;
358 case PA_ENCODING_EAC3_IEC61937:
359 device.m_dataFormats.push_back(AE_FMT_EAC3);
360 device_type = AE_DEVTYPE_IEC958;
362 case PA_ENCODING_PCM:
363 device.m_dataFormats.insert(device.m_dataFormats.end(), defaultDataFormats, defaultDataFormats + sizeof(defaultDataFormats) / sizeof(defaultDataFormats[0]));
369 // passthrough is only working when device has Stereo channel config
370 if (device_type > AE_DEVTYPE_PCM && device.m_channels.Count() == 2)
371 device.m_deviceType = AE_DEVTYPE_IEC958;
373 device.m_deviceType = AE_DEVTYPE_PCM;
376 CLog::Log(LOGDEBUG, "PulseAudio: Found %s with devicestring %s", device.m_displayName.c_str(), device.m_deviceName.c_str());
377 sinkStruct->list->push_back(device);
381 CLog::Log(LOGDEBUG, "PulseAudio: Skipped %s with devicestring %s", device.m_displayName.c_str(), device.m_deviceName.c_str());
384 pa_threaded_mainloop_signal(sinkStruct->mainloop, 0);
387 /* PulseAudio class memberfunctions*/
390 CAESinkPULSE::CAESinkPULSE()
392 m_IsAllocated = false;
393 m_passthrough = false;
395 m_BytesPerSecond = 0;
402 CAESinkPULSE::~CAESinkPULSE()
407 bool CAESinkPULSE::Initialize(AEAudioFormat &format, std::string &device)
409 m_IsAllocated = false;
410 m_passthrough = false;
411 m_BytesPerSecond = 0;
417 if (!SetupContext(NULL, &m_Context, &m_MainLoop))
419 CLog::Log(LOGNOTICE, "PulseAudio might not be running. Context was not created.");
424 pa_threaded_mainloop_lock(m_MainLoop);
426 struct pa_channel_map map;
427 pa_channel_map_init(&map);
429 m_passthrough = AE_IS_RAW(format.m_dataFormat);
434 format.m_channelLayout = AE_CH_LAYOUT_2_0;
438 map = AEChannelMapToPAChannel(format.m_channelLayout);
439 // if count has changed we need to fit the AE Map
440 if(map.channels != format.m_channelLayout.Count())
441 format.m_channelLayout = PAChannelToAEChannelMap(map);
443 m_Channels = format.m_channelLayout.Count();
445 pa_cvolume_reset(&m_Volume, m_Channels);
447 pa_format_info *info[1];
448 info[0] = pa_format_info_new();
449 info[0]->encoding = AEFormatToPulseEncoding(format.m_dataFormat);
452 pa_format_info_set_sample_format(info[0], AEFormatToPulseFormat(format.m_dataFormat));
453 pa_format_info_set_channel_map(info[0], &map);
455 pa_format_info_set_channels(info[0], m_Channels);
457 // PA requires m_encodedRate in order to do EAC3
458 unsigned int samplerate;
461 if (format.m_encodedRate == 0)
463 CLog::Log(LOGNOTICE, "PulseAudio: Passthrough in use but m_encodedRate is not set - fallback to m_sampleRate");
464 samplerate = format.m_sampleRate;
467 samplerate = format.m_encodedRate;
470 samplerate = format.m_sampleRate;
472 pa_format_info_set_rate(info[0], samplerate);
474 if (!pa_format_info_valid(info[0]))
476 CLog::Log(LOGERROR, "PulseAudio: Invalid format info");
477 pa_format_info_free(info[0]);
478 pa_threaded_mainloop_unlock(m_MainLoop);
484 #if PA_CHECK_VERSION(2,0,0)
485 pa_format_info_to_sample_spec(info[0], &spec, NULL);
487 spec.rate = (AEFormatToPulseEncoding(format.m_dataFormat) == PA_ENCODING_EAC3_IEC61937) ? 4 * samplerate : samplerate;
488 spec.format = AEFormatToPulseFormat(format.m_dataFormat);
489 spec.channels = m_Channels;
491 if (!pa_sample_spec_valid(&spec))
493 CLog::Log(LOGERROR, "PulseAudio: Invalid sample spec");
494 pa_format_info_free(info[0]);
495 pa_threaded_mainloop_unlock(m_MainLoop);
500 m_BytesPerSecond = pa_bytes_per_second(&spec);
501 unsigned int frameSize = pa_frame_size(&spec);
503 m_Stream = pa_stream_new_extended(m_Context, "audio stream", info, 1, NULL);
504 pa_format_info_free(info[0]);
506 if (m_Stream == NULL)
508 CLog::Log(LOGERROR, "PulseAudio: Could not create a stream");
509 pa_threaded_mainloop_unlock(m_MainLoop);
514 pa_stream_set_state_callback(m_Stream, StreamStateCallback, m_MainLoop);
515 pa_stream_set_write_callback(m_Stream, StreamRequestCallback, m_MainLoop);
516 pa_stream_set_latency_update_callback(m_Stream, StreamLatencyUpdateCallback, m_MainLoop);
518 bool isDefaultDevice = (device == "Default");
520 pa_buffer_attr buffer_attr;
521 SinkInfoStruct sinkStruct;
522 sinkStruct.mainloop = m_MainLoop;
523 sinkStruct.isHWDevice = false;
524 sinkStruct.device_found = true; // needed to get default device opened
526 if (!isDefaultDevice)
528 // we need to check if the device we want to open really exists
529 // default device is handled in a special manner
530 sinkStruct.device_found = false; // if sink is valid it will be set true in pa_context_get_sink_info_by_name
531 WaitForOperation(pa_context_get_sink_info_by_name(m_Context, device.c_str(),SinkInfoCallback, &sinkStruct), m_MainLoop, "Get Sink Info");
534 if(!sinkStruct.device_found) // ActiveAE will open us again with a valid device name
536 CLog::Log(LOGERROR, "PulseAudio: Sink %s not found", device.c_str());
537 pa_threaded_mainloop_unlock(m_MainLoop);
543 // 50ms min packet size
544 if(sinkStruct.isHWDevice || isDefaultDevice)
546 unsigned int latency = m_BytesPerSecond / 5;
547 unsigned int process_time = latency / 4;
548 memset(&buffer_attr, 0, sizeof(buffer_attr));
549 buffer_attr.tlength = (uint32_t) latency;
550 buffer_attr.minreq = (uint32_t) process_time;
551 buffer_attr.maxlength = (uint32_t) -1;
552 buffer_attr.prebuf = (uint32_t) -1;
553 buffer_attr.fragsize = (uint32_t) latency;
556 if (pa_stream_connect_playback(m_Stream, isDefaultDevice ? NULL : device.c_str(), sinkStruct.isHWDevice ? &buffer_attr : NULL, ((pa_stream_flags)(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_ADJUST_LATENCY)), m_passthrough ? NULL : &m_Volume, NULL) < 0)
558 CLog::Log(LOGERROR, "PulseAudio: Failed to connect stream to output");
559 pa_threaded_mainloop_unlock(m_MainLoop);
564 /* Wait until the stream is ready */
567 pa_threaded_mainloop_wait(m_MainLoop);
568 CLog::Log(LOGDEBUG, "PulseAudio: Stream %s", StreamStateToString(pa_stream_get_state(m_Stream)));
570 while (pa_stream_get_state(m_Stream) != PA_STREAM_READY && pa_stream_get_state(m_Stream) != PA_STREAM_FAILED);
572 if (pa_stream_get_state(m_Stream) == PA_STREAM_FAILED)
574 CLog::Log(LOGERROR, "PulseAudio: Waited for the stream but it failed");
575 pa_threaded_mainloop_unlock(m_MainLoop);
580 const pa_buffer_attr *a;
582 if (!(a = pa_stream_get_buffer_attr(m_Stream)))
584 CLog::Log(LOGERROR, "PulseAudio: %s", pa_strerror(pa_context_errno(m_Context)));
585 pa_threaded_mainloop_unlock(m_MainLoop);
591 unsigned int packetSize = a->minreq;
592 m_BufferSize = a->tlength;
594 format.m_frames = packetSize / frameSize;
597 pa_threaded_mainloop_unlock(m_MainLoop);
599 m_IsAllocated = true;
600 format.m_frameSize = frameSize;
601 format.m_frameSamples = format.m_frames * format.m_channelLayout.Count();
603 format.m_dataFormat = m_passthrough ? AE_FMT_S16NE : format.m_dataFormat;
610 void CAESinkPULSE::Deinitialize()
612 m_IsAllocated = false;
613 m_passthrough = false;
619 pa_threaded_mainloop_stop(m_MainLoop);
623 pa_stream_disconnect(m_Stream);
624 pa_stream_unref(m_Stream);
630 pa_context_disconnect(m_Context);
631 pa_context_unref(m_Context);
637 pa_threaded_mainloop_free(m_MainLoop);
642 double CAESinkPULSE::GetDelay()
648 pa_usec_t latency = (pa_usec_t) -1;
649 pa_threaded_mainloop_lock(m_MainLoop);
650 if ((error = pa_stream_get_latency(m_Stream, &latency, NULL)) < 0)
652 if (error == -PA_ERR_NODATA)
654 WaitForOperation(pa_stream_update_timing_info(m_Stream, NULL,NULL), m_MainLoop, "Update Timing Information");
655 if ((error = pa_stream_get_latency(m_Stream, &latency, NULL)) < 0)
657 CLog::Log(LOGDEBUG, "GetDelay - Failed to get Latency %d", error);
662 latency = (pa_usec_t) 0;
664 pa_threaded_mainloop_unlock(m_MainLoop);
665 return latency / 1000000.0;
668 double CAESinkPULSE::GetCacheTotal()
670 return (float)m_BufferSize / (float)m_BytesPerSecond;
673 unsigned int CAESinkPULSE::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
678 pa_threaded_mainloop_lock(m_MainLoop);
680 unsigned int available = frames * m_format.m_frameSize;
681 unsigned int length = 0;
682 // revisit me after Gotham - should use a callback for the write function
683 while ((length = pa_stream_writable_size(m_Stream)) == 0)
684 pa_threaded_mainloop_wait(m_MainLoop);
686 length = std::min((unsigned int)length, available);
688 int error = pa_stream_write(m_Stream, data, length, NULL, 0, PA_SEEK_RELATIVE);
689 pa_threaded_mainloop_unlock(m_MainLoop);
693 CLog::Log(LOGERROR, "CPulseAudioDirectSound::AddPackets - pa_stream_write failed\n");
697 return (unsigned int)(length / m_format.m_frameSize);
700 void CAESinkPULSE::Drain()
705 pa_threaded_mainloop_lock(m_MainLoop);
706 WaitForOperation(pa_stream_drain(m_Stream, NULL, NULL), m_MainLoop, "Drain");
707 pa_threaded_mainloop_unlock(m_MainLoop);
710 void CAESinkPULSE::SetVolume(float volume)
712 if (m_IsAllocated && !m_passthrough)
714 pa_threaded_mainloop_lock(m_MainLoop);
715 pa_volume_t pavolume = pa_sw_volume_from_linear(volume);
717 pa_cvolume_mute(&m_Volume, m_Channels);
719 pa_cvolume_set(&m_Volume, m_Channels, pavolume);
720 pa_operation *op = pa_context_set_sink_input_volume(m_Context, pa_stream_get_index(m_Stream), &m_Volume, NULL, NULL);
722 CLog::Log(LOGERROR, "PulseAudio: Failed to set volume");
724 pa_operation_unref(op);
726 pa_threaded_mainloop_unlock(m_MainLoop);
730 void CAESinkPULSE::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
733 pa_threaded_mainloop *mainloop;
735 if (!SetupContext(NULL, &context, &mainloop))
737 CLog::Log(LOGNOTICE, "PulseAudio might not be running. Context was not created.");
741 pa_threaded_mainloop_lock(mainloop);
743 SinkInfoStruct sinkStruct;
744 sinkStruct.mainloop = mainloop;
745 sinkStruct.list = &list;
746 WaitForOperation(pa_context_get_sink_info_list(context, SinkInfoRequestCallback, &sinkStruct), mainloop, "EnumerateAudioSinks");
748 pa_threaded_mainloop_unlock(mainloop);
751 pa_threaded_mainloop_stop(mainloop);
755 pa_context_disconnect(context);
756 pa_context_unref(context);
762 pa_threaded_mainloop_free(mainloop);
767 bool CAESinkPULSE::Pause(bool pause)
769 pa_threaded_mainloop_lock(m_MainLoop);
771 if (!WaitForOperation(pa_stream_cork(m_Stream, pause ? 1 : 0, NULL, NULL), m_MainLoop, pause ? "Pause" : "Resume"))
774 pa_threaded_mainloop_unlock(m_MainLoop);
779 inline bool CAESinkPULSE::WaitForOperation(pa_operation *op, pa_threaded_mainloop *mainloop, const char *LogEntry = "")
786 while (pa_operation_get_state(op) == PA_OPERATION_RUNNING)
787 pa_threaded_mainloop_wait(mainloop);
789 if (pa_operation_get_state(op) != PA_OPERATION_DONE)
791 CLog::Log(LOGERROR, "PulseAudio: %s Operation failed", LogEntry);
795 pa_operation_unref(op);
799 bool CAESinkPULSE::SetupContext(const char *host, pa_context **context, pa_threaded_mainloop **mainloop)
801 if ((*mainloop = pa_threaded_mainloop_new()) == NULL)
803 CLog::Log(LOGERROR, "PulseAudio: Failed to allocate main loop");
807 if (((*context) = pa_context_new(pa_threaded_mainloop_get_api(*mainloop), "XBMC")) == NULL)
809 CLog::Log(LOGERROR, "PulseAudio: Failed to allocate context");
813 pa_context_set_state_callback(*context, ContextStateCallback, *mainloop);
815 if (pa_context_connect(*context, host, (pa_context_flags_t)0, NULL) < 0)
817 CLog::Log(LOGERROR, "PulseAudio: Failed to connect context");
820 pa_threaded_mainloop_lock(*mainloop);
822 if (pa_threaded_mainloop_start(*mainloop) < 0)
824 CLog::Log(LOGERROR, "PulseAudio: Failed to start MainLoop");
825 pa_threaded_mainloop_unlock(*mainloop);
829 /* Wait until the context is ready */
832 pa_threaded_mainloop_wait(*mainloop);
833 CLog::Log(LOGDEBUG, "PulseAudio: Context %s", ContextStateToString(pa_context_get_state(*context)));
835 while (pa_context_get_state(*context) != PA_CONTEXT_READY && pa_context_get_state(*context) != PA_CONTEXT_FAILED);
837 if (pa_context_get_state(*context) == PA_CONTEXT_FAILED)
839 CLog::Log(LOGERROR, "PulseAudio: Waited for the Context but it failed");
840 pa_threaded_mainloop_unlock(*mainloop);
844 pa_threaded_mainloop_unlock(*mainloop);