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"
26 #include "Application.h"
30 static const char *ContextStateToString(pa_context_state s)
34 case PA_CONTEXT_UNCONNECTED:
36 case PA_CONTEXT_CONNECTING:
38 case PA_CONTEXT_AUTHORIZING:
40 case PA_CONTEXT_SETTING_NAME:
41 return "setting name";
42 case PA_CONTEXT_READY:
44 case PA_CONTEXT_FAILED:
46 case PA_CONTEXT_TERMINATED:
53 static const char *StreamStateToString(pa_stream_state s)
57 case PA_STREAM_UNCONNECTED:
59 case PA_STREAM_CREATING:
63 case PA_STREAM_FAILED:
65 case PA_STREAM_TERMINATED:
72 static pa_sample_format AEFormatToPulseFormat(AEDataFormat format)
76 case AE_FMT_U8 : return PA_SAMPLE_U8;
77 case AE_FMT_S16LE : return PA_SAMPLE_S16LE;
78 case AE_FMT_S16BE : return PA_SAMPLE_S16BE;
79 case AE_FMT_S16NE : return PA_SAMPLE_S16NE;
80 case AE_FMT_S24LE3: return PA_SAMPLE_S24LE;
81 case AE_FMT_S24BE3: return PA_SAMPLE_S24BE;
82 case AE_FMT_S24NE3: return PA_SAMPLE_S24NE;
83 case AE_FMT_S24LE4: return PA_SAMPLE_S24_32LE;
84 case AE_FMT_S24BE4: return PA_SAMPLE_S24_32BE;
85 case AE_FMT_S24NE4: return PA_SAMPLE_S24_32NE;
86 case AE_FMT_S32BE : return PA_SAMPLE_S32BE;
87 case AE_FMT_S32LE : return PA_SAMPLE_S32LE;
88 case AE_FMT_S32NE : return PA_SAMPLE_S32NE;
89 case AE_FMT_FLOAT : return PA_SAMPLE_FLOAT32;
94 return PA_SAMPLE_S16NE;
97 return PA_SAMPLE_INVALID;
101 static pa_encoding AEFormatToPulseEncoding(AEDataFormat format)
105 case AE_FMT_AC3 : return PA_ENCODING_AC3_IEC61937;
106 case AE_FMT_DTS : return PA_ENCODING_DTS_IEC61937;
107 case AE_FMT_EAC3 : return PA_ENCODING_EAC3_IEC61937;
110 return PA_ENCODING_PCM;
114 static AEDataFormat defaultDataFormats[] = {
131 static unsigned int defaultSampleRates[] = {
148 /* Static callback functions */
150 static void ContextStateCallback(pa_context *c, void *userdata)
152 pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
153 switch (pa_context_get_state(c))
155 case PA_CONTEXT_READY:
156 case PA_CONTEXT_TERMINATED:
157 case PA_CONTEXT_UNCONNECTED:
158 case PA_CONTEXT_CONNECTING:
159 case PA_CONTEXT_AUTHORIZING:
160 case PA_CONTEXT_SETTING_NAME:
161 case PA_CONTEXT_FAILED:
162 pa_threaded_mainloop_signal(m, 0);
167 static void StreamStateCallback(pa_stream *s, void *userdata)
169 pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
170 switch (pa_stream_get_state(s))
172 case PA_STREAM_UNCONNECTED:
173 case PA_STREAM_CREATING:
174 case PA_STREAM_READY:
175 case PA_STREAM_FAILED:
176 case PA_STREAM_TERMINATED:
177 pa_threaded_mainloop_signal(m, 0);
182 static void StreamRequestCallback(pa_stream *s, size_t length, void *userdata)
184 pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
185 pa_threaded_mainloop_signal(m, 0);
188 static void StreamLatencyUpdateCallback(pa_stream *s, void *userdata)
190 pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
191 pa_threaded_mainloop_signal(m, 0);
194 static void SinkChangedCallback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata)
196 CAESinkPULSE* p = (CAESinkPULSE*) userdata;
200 CSingleLock lock(p->m_sec);
201 if (p->IsInitialized())
203 if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW)
205 CLog::Log(LOGDEBUG, "Sink appeared");
206 CAEFactory::DeviceChange();
208 else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
210 CLog::Log(LOGDEBUG, "Sink removed");
211 CAEFactory::DeviceChange();
213 else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_CHANGE)
215 CLog::Log(LOGDEBUG, "Sink changed");
216 //CAEFactory::DeviceChange();
221 struct SinkInfoStruct
223 AEDeviceInfoList *list;
226 pa_threaded_mainloop *mainloop;
238 struct SinkInputInfoStruct
244 pa_threaded_mainloop *mainloop;
245 SinkInputInfoStruct()
253 static void SinkInfoCallback(pa_context *c, const pa_sink_info *i, int eol, void *userdata)
255 SinkInfoStruct *sinkStruct = (SinkInfoStruct *)userdata;
258 if (i->flags && (i->flags & PA_SINK_HARDWARE))
259 sinkStruct->isHWDevice = true;
261 sinkStruct->samplerate = i->sample_spec.rate;
262 sinkStruct->device_found = true;
264 pa_threaded_mainloop_signal(sinkStruct->mainloop, 0);
267 static void SinkInputInfoCallback(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata)
269 SinkInputInfoStruct *siiStruct = (SinkInputInfoStruct *)userdata;
270 if(i && i->has_volume)
272 siiStruct->is_valid = true;
273 siiStruct->volume = i->volume;
274 siiStruct->mute = i->mute;
275 siiStruct->index = i->index;
277 pa_threaded_mainloop_signal(siiStruct->mainloop, 0);
280 static AEChannel PAChannelToAEChannel(pa_channel_position_t channel)
282 AEChannel ae_channel;
285 case PA_CHANNEL_POSITION_FRONT_LEFT: ae_channel = AE_CH_FL; break;
286 case PA_CHANNEL_POSITION_FRONT_RIGHT: ae_channel = AE_CH_FR; break;
287 case PA_CHANNEL_POSITION_FRONT_CENTER: ae_channel = AE_CH_FC; break;
288 case PA_CHANNEL_POSITION_LFE: ae_channel = AE_CH_LFE; break;
289 case PA_CHANNEL_POSITION_REAR_LEFT: ae_channel = AE_CH_BL; break;
290 case PA_CHANNEL_POSITION_REAR_RIGHT: ae_channel = AE_CH_BR; break;
291 case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER: ae_channel = AE_CH_FLOC; break;
292 case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: ae_channel = AE_CH_FROC; break;
293 case PA_CHANNEL_POSITION_REAR_CENTER: ae_channel = AE_CH_BC; break;
294 case PA_CHANNEL_POSITION_SIDE_LEFT: ae_channel = AE_CH_SL; break;
295 case PA_CHANNEL_POSITION_SIDE_RIGHT: ae_channel = AE_CH_SR; break;
296 case PA_CHANNEL_POSITION_TOP_FRONT_LEFT: ae_channel = AE_CH_TFL; break;
297 case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT: ae_channel = AE_CH_TFR; break;
298 case PA_CHANNEL_POSITION_TOP_FRONT_CENTER: ae_channel = AE_CH_TFC; break;
299 case PA_CHANNEL_POSITION_TOP_CENTER: ae_channel = AE_CH_TC; break;
300 case PA_CHANNEL_POSITION_TOP_REAR_LEFT: ae_channel = AE_CH_TBL; break;
301 case PA_CHANNEL_POSITION_TOP_REAR_RIGHT: ae_channel = AE_CH_TBR; break;
302 case PA_CHANNEL_POSITION_TOP_REAR_CENTER: ae_channel = AE_CH_TBC; break;
303 default: ae_channel = AE_CH_NULL; break;
308 static pa_channel_position_t AEChannelToPAChannel(AEChannel ae_channel)
310 pa_channel_position_t pa_channel;
313 case AE_CH_FL: pa_channel = PA_CHANNEL_POSITION_FRONT_LEFT; break;
314 case AE_CH_FR: pa_channel = PA_CHANNEL_POSITION_FRONT_RIGHT; break;
315 case AE_CH_FC: pa_channel = PA_CHANNEL_POSITION_FRONT_CENTER; break;
316 case AE_CH_LFE: pa_channel = PA_CHANNEL_POSITION_LFE; break;
317 case AE_CH_BL: pa_channel = PA_CHANNEL_POSITION_REAR_LEFT; break;
318 case AE_CH_BR: pa_channel = PA_CHANNEL_POSITION_REAR_RIGHT; break;
319 case AE_CH_FLOC: pa_channel = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER; break;
320 case AE_CH_FROC: pa_channel = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; break;
321 case AE_CH_BC: pa_channel = PA_CHANNEL_POSITION_REAR_CENTER; break;
322 case AE_CH_SL: pa_channel = PA_CHANNEL_POSITION_SIDE_LEFT; break;
323 case AE_CH_SR: pa_channel = PA_CHANNEL_POSITION_SIDE_RIGHT; break;
324 case AE_CH_TFL: pa_channel = PA_CHANNEL_POSITION_TOP_FRONT_LEFT; break;
325 case AE_CH_TFR: pa_channel = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT; break;
326 case AE_CH_TFC: pa_channel = PA_CHANNEL_POSITION_TOP_FRONT_CENTER; break;
327 case AE_CH_TC: pa_channel = PA_CHANNEL_POSITION_TOP_CENTER; break;
328 case AE_CH_TBL: pa_channel = PA_CHANNEL_POSITION_TOP_REAR_LEFT; break;
329 case AE_CH_TBR: pa_channel = PA_CHANNEL_POSITION_TOP_REAR_RIGHT; break;
330 case AE_CH_TBC: pa_channel = PA_CHANNEL_POSITION_TOP_REAR_CENTER; break;
331 default: pa_channel = PA_CHANNEL_POSITION_INVALID; break;
336 static pa_channel_map AEChannelMapToPAChannel(CAEChannelInfo info)
339 pa_channel_map_init(&map);
340 pa_channel_position_t pos;
341 for (unsigned int i = 0; i < info.Count(); ++i)
343 pos = AEChannelToPAChannel(info[i]);
344 if(pos != PA_CHANNEL_POSITION_INVALID)
346 // remember channel name and increase channel count
347 map.map[map.channels++] = pos;
353 static CAEChannelInfo PAChannelToAEChannelMap(pa_channel_map channels)
358 for (unsigned int i=0; i<channels.channels; i++)
360 ch = PAChannelToAEChannel(channels.map[i]);
367 static void SinkInfoRequestCallback(pa_context *c, const pa_sink_info *i, int eol, void *userdata)
370 SinkInfoStruct *sinkStruct = (SinkInfoStruct *)userdata;
372 if(sinkStruct && sinkStruct->list->empty())
374 //add a default device first
375 CAEDeviceInfo defaultDevice;
376 defaultDevice.m_deviceName = std::string("Default");
377 defaultDevice.m_displayName = std::string("Default");
378 defaultDevice.m_displayNameExtra = std::string("Default Output Device (PULSEAUDIO)");
379 defaultDevice.m_dataFormats.insert(defaultDevice.m_dataFormats.end(), defaultDataFormats, defaultDataFormats + sizeof(defaultDataFormats) / sizeof(defaultDataFormats[0]));
380 defaultDevice.m_channels = CAEChannelInfo(AE_CH_LAYOUT_2_0);
381 defaultDevice.m_sampleRates.assign(defaultSampleRates, defaultSampleRates + sizeof(defaultSampleRates) / sizeof(defaultSampleRates[0]));
382 defaultDevice.m_deviceType = AE_DEVTYPE_PCM;
383 sinkStruct->list->push_back(defaultDevice);
388 CAEDeviceInfo device;
390 device.m_deviceName = string(i->name);
391 device.m_displayName = string(i->description);
392 if (i->active_port && i->active_port->description)
393 device.m_displayNameExtra = std::string((i->active_port->description)).append(" (PULSEAUDIO)");
395 device.m_displayNameExtra = std::string((i->description)).append(" (PULSEAUDIO)");
396 unsigned int device_type = AE_DEVTYPE_PCM; //0
398 device.m_channels = PAChannelToAEChannelMap(i->channel_map);
400 // Don't add devices that would not have a channel map
401 if(device.m_channels.Count() == 0)
404 device.m_sampleRates.assign(defaultSampleRates, defaultSampleRates + sizeof(defaultSampleRates) / sizeof(defaultSampleRates[0]));
406 for (unsigned int j = 0; j < i->n_formats; j++)
408 switch(i->formats[j]->encoding)
410 case PA_ENCODING_AC3_IEC61937:
411 device.m_dataFormats.push_back(AE_FMT_AC3);
412 device_type = AE_DEVTYPE_IEC958;
414 case PA_ENCODING_DTS_IEC61937:
415 device.m_dataFormats.push_back(AE_FMT_DTS);
416 device_type = AE_DEVTYPE_IEC958;
418 case PA_ENCODING_EAC3_IEC61937:
419 device.m_dataFormats.push_back(AE_FMT_EAC3);
420 device_type = AE_DEVTYPE_IEC958;
422 case PA_ENCODING_PCM:
423 device.m_dataFormats.insert(device.m_dataFormats.end(), defaultDataFormats, defaultDataFormats + sizeof(defaultDataFormats) / sizeof(defaultDataFormats[0]));
429 // passthrough is only working when device has Stereo channel config
430 if (device_type > AE_DEVTYPE_PCM && device.m_channels.Count() == 2)
431 device.m_deviceType = AE_DEVTYPE_IEC958;
433 device.m_deviceType = AE_DEVTYPE_PCM;
436 CLog::Log(LOGDEBUG, "PulseAudio: Found %s with devicestring %s", device.m_displayName.c_str(), device.m_deviceName.c_str());
437 sinkStruct->list->push_back(device);
441 CLog::Log(LOGDEBUG, "PulseAudio: Skipped %s with devicestring %s", device.m_displayName.c_str(), device.m_deviceName.c_str());
444 pa_threaded_mainloop_signal(sinkStruct->mainloop, 0);
447 /* PulseAudio class memberfunctions*/
450 CAESinkPULSE::CAESinkPULSE()
452 m_IsAllocated = false;
453 m_passthrough = false;
455 m_BytesPerSecond = 0;
462 CAESinkPULSE::~CAESinkPULSE()
467 bool CAESinkPULSE::Initialize(AEAudioFormat &format, std::string &device)
470 CSingleLock lock(m_sec);
471 m_IsAllocated = false;
473 m_passthrough = false;
474 m_BytesPerSecond = 0;
480 if (!SetupContext(NULL, &m_Context, &m_MainLoop))
482 CLog::Log(LOGNOTICE, "PulseAudio might not be running. Context was not created.");
487 pa_threaded_mainloop_lock(m_MainLoop);
490 // Register Callback for Sink changes
491 CSingleLock lock(m_sec);
492 pa_context_set_subscribe_callback(m_Context, SinkChangedCallback, this);
493 const pa_subscription_mask_t mask = PA_SUBSCRIPTION_MASK_SINK;
494 pa_operation *op = pa_context_subscribe(m_Context, mask, NULL, this);
496 pa_operation_unref(op);
499 struct pa_channel_map map;
500 pa_channel_map_init(&map);
502 m_passthrough = AE_IS_RAW(format.m_dataFormat);
507 format.m_channelLayout = AE_CH_LAYOUT_2_0;
511 map = AEChannelMapToPAChannel(format.m_channelLayout);
512 // if count has changed we need to fit the AE Map
513 if(map.channels != format.m_channelLayout.Count())
514 format.m_channelLayout = PAChannelToAEChannelMap(map);
516 m_Channels = format.m_channelLayout.Count();
518 // store information about current sink
519 SinkInfoStruct sinkStruct;
520 sinkStruct.mainloop = m_MainLoop;
521 sinkStruct.device_found = false;
523 // get real sample rate of the device we want to open - to avoid resampling
524 bool isDefaultDevice = (device == "Default");
525 WaitForOperation(pa_context_get_sink_info_by_name(m_Context, isDefaultDevice ? NULL : device.c_str(), SinkInfoCallback, &sinkStruct), m_MainLoop, "Get Sink Info");
526 // only check if the device is existing - don't alter the sample rate
527 if (!sinkStruct.device_found)
529 CLog::Log(LOGERROR, "PulseAudio: Sink %s not found", device.c_str());
530 pa_threaded_mainloop_unlock(m_MainLoop);
535 // Pulse can resample everything between 1 hz and 192000 hz
536 // Make sure we are in the range that we originally added
537 format.m_sampleRate = std::max(5512U, std::min(format.m_sampleRate, 192000U));
539 pa_format_info *info[1];
540 info[0] = pa_format_info_new();
541 info[0]->encoding = AEFormatToPulseEncoding(format.m_dataFormat);
544 pa_format_info_set_sample_format(info[0], AEFormatToPulseFormat(format.m_dataFormat));
545 pa_format_info_set_channel_map(info[0], &map);
547 pa_format_info_set_channels(info[0], m_Channels);
549 // PA requires m_encodedRate in order to do EAC3
550 unsigned int samplerate;
553 if (format.m_encodedRate == 0 || format.m_encodedRate > format.m_sampleRate)
555 CLog::Log(LOGNOTICE, "PulseAudio: Passthrough in use but m_encodedRate is not set or too large: %u - fallback to m_sampleRate", format.m_encodedRate);
556 samplerate = format.m_sampleRate;
559 samplerate = format.m_encodedRate;
562 samplerate = format.m_sampleRate;
564 pa_format_info_set_rate(info[0], samplerate);
566 if (!pa_format_info_valid(info[0]))
568 CLog::Log(LOGERROR, "PulseAudio: Invalid format info");
569 pa_format_info_free(info[0]);
570 pa_threaded_mainloop_unlock(m_MainLoop);
576 #if PA_CHECK_VERSION(2,0,0)
577 pa_format_info_to_sample_spec(info[0], &spec, NULL);
579 spec.rate = (AEFormatToPulseEncoding(format.m_dataFormat) == PA_ENCODING_EAC3_IEC61937) ? 4 * samplerate : samplerate;
580 spec.format = AEFormatToPulseFormat(format.m_dataFormat);
581 spec.channels = m_Channels;
583 if (!pa_sample_spec_valid(&spec))
585 CLog::Log(LOGERROR, "PulseAudio: Invalid sample spec");
586 pa_format_info_free(info[0]);
587 pa_threaded_mainloop_unlock(m_MainLoop);
592 m_BytesPerSecond = pa_bytes_per_second(&spec);
593 unsigned int frameSize = pa_frame_size(&spec);
595 m_Stream = pa_stream_new_extended(m_Context, "xbmc audio stream", info, 1, NULL);
596 pa_format_info_free(info[0]);
598 if (m_Stream == NULL)
600 CLog::Log(LOGERROR, "PulseAudio: Could not create a stream");
601 pa_threaded_mainloop_unlock(m_MainLoop);
606 pa_stream_set_state_callback(m_Stream, StreamStateCallback, m_MainLoop);
607 pa_stream_set_write_callback(m_Stream, StreamRequestCallback, m_MainLoop);
608 pa_stream_set_latency_update_callback(m_Stream, StreamLatencyUpdateCallback, m_MainLoop);
610 pa_buffer_attr buffer_attr;
613 // 50ms min packet size
614 if(sinkStruct.isHWDevice || isDefaultDevice)
616 unsigned int latency = m_BytesPerSecond / 5;
617 unsigned int process_time = latency / 4;
618 memset(&buffer_attr, 0, sizeof(buffer_attr));
619 buffer_attr.tlength = (uint32_t) latency;
620 buffer_attr.minreq = (uint32_t) process_time;
621 buffer_attr.maxlength = (uint32_t) -1;
622 buffer_attr.prebuf = (uint32_t) -1;
623 buffer_attr.fragsize = (uint32_t) latency;
626 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)), NULL, NULL) < 0)
628 CLog::Log(LOGERROR, "PulseAudio: Failed to connect stream to output");
629 pa_threaded_mainloop_unlock(m_MainLoop);
634 /* Wait until the stream is ready */
637 pa_threaded_mainloop_wait(m_MainLoop);
638 CLog::Log(LOGDEBUG, "PulseAudio: Stream %s", StreamStateToString(pa_stream_get_state(m_Stream)));
640 while (pa_stream_get_state(m_Stream) != PA_STREAM_READY && pa_stream_get_state(m_Stream) != PA_STREAM_FAILED);
642 if (pa_stream_get_state(m_Stream) == PA_STREAM_FAILED)
644 CLog::Log(LOGERROR, "PulseAudio: Waited for the stream but it failed");
645 pa_threaded_mainloop_unlock(m_MainLoop);
650 //update local volume if we are in non passthrough mode
653 unsigned int sink_input_idx = pa_stream_get_index(m_Stream);
654 SinkInputInfoStruct sii;
655 sii.mainloop = m_MainLoop;
656 bool success = WaitForOperation(pa_context_get_sink_input_info(m_Context, sink_input_idx, SinkInputInfoCallback, &sii), m_MainLoop, "Get Sink Input Info");
657 if(success && sii.is_valid)
659 // we don't have per channel values so use avg of them
660 pa_volume_t p_vol = pa_cvolume_avg(&sii.volume);
661 // store it internally
662 m_Volume = sii.volume;
663 float sValue = (float) pa_sw_volume_to_linear(p_vol);
664 CLog::Log(LOGDEBUG, "Restored Stream value to %f", sValue);
665 g_application.SetVolume(sValue, false);
666 if (sii.mute && sValue > 0)
668 CLog::Log(LOGDEBUG, "PulseAudio: Stream is muted - perhaps was a user wish - if volume is changed we unmute");
673 const pa_buffer_attr *a;
675 if (!(a = pa_stream_get_buffer_attr(m_Stream)))
677 CLog::Log(LOGERROR, "PulseAudio: %s", pa_strerror(pa_context_errno(m_Context)));
678 pa_threaded_mainloop_unlock(m_MainLoop);
684 unsigned int packetSize = a->minreq;
685 m_BufferSize = a->tlength;
687 format.m_frames = packetSize / frameSize;
690 pa_threaded_mainloop_unlock(m_MainLoop);
692 format.m_frameSize = frameSize;
693 format.m_frameSamples = format.m_frames * format.m_channelLayout.Count();
695 format.m_dataFormat = m_passthrough ? AE_FMT_S16NE : format.m_dataFormat;
699 CSingleLock lock(m_sec);
700 m_IsAllocated = true;
706 void CAESinkPULSE::Deinitialize()
708 CSingleLock lock(m_sec);
709 m_IsAllocated = false;
710 m_passthrough = false;
716 pa_threaded_mainloop_stop(m_MainLoop);
720 pa_stream_disconnect(m_Stream);
721 pa_stream_unref(m_Stream);
727 pa_context_disconnect(m_Context);
728 pa_context_unref(m_Context);
734 pa_threaded_mainloop_free(m_MainLoop);
739 double CAESinkPULSE::GetDelay()
745 pa_usec_t latency = (pa_usec_t) -1;
746 pa_threaded_mainloop_lock(m_MainLoop);
747 if ((error = pa_stream_get_latency(m_Stream, &latency, NULL)) < 0)
749 if (error == -PA_ERR_NODATA)
751 WaitForOperation(pa_stream_update_timing_info(m_Stream, NULL,NULL), m_MainLoop, "Update Timing Information");
752 if ((error = pa_stream_get_latency(m_Stream, &latency, NULL)) < 0)
754 CLog::Log(LOGDEBUG, "GetDelay - Failed to get Latency %d", error);
759 latency = (pa_usec_t) 0;
761 pa_threaded_mainloop_unlock(m_MainLoop);
762 return latency / 1000000.0;
765 double CAESinkPULSE::GetCacheTotal()
767 return (float)m_BufferSize / (float)m_BytesPerSecond;
770 unsigned int CAESinkPULSE::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
775 pa_threaded_mainloop_lock(m_MainLoop);
777 unsigned int available = frames * m_format.m_frameSize;
778 unsigned int length = 0;
779 // revisit me after Gotham - should use a callback for the write function
780 while ((length = pa_stream_writable_size(m_Stream)) == 0)
781 pa_threaded_mainloop_wait(m_MainLoop);
783 length = std::min((unsigned int)length, available);
785 int error = pa_stream_write(m_Stream, data, length, NULL, 0, PA_SEEK_RELATIVE);
786 pa_threaded_mainloop_unlock(m_MainLoop);
790 CLog::Log(LOGERROR, "CPulseAudioDirectSound::AddPackets - pa_stream_write failed\n");
794 return (unsigned int)(length / m_format.m_frameSize);
797 void CAESinkPULSE::Drain()
802 pa_threaded_mainloop_lock(m_MainLoop);
803 WaitForOperation(pa_stream_drain(m_Stream, NULL, NULL), m_MainLoop, "Drain");
804 pa_threaded_mainloop_unlock(m_MainLoop);
807 void CAESinkPULSE::SetVolume(float volume)
809 if (m_IsAllocated && !m_passthrough)
811 // clamp possibly too large / low values
812 float per_cent_volume = std::max(0.0f, std::min(volume, 1.0f));
814 pa_threaded_mainloop_lock(m_MainLoop);
815 bool external_change = false;
816 //check if internal volume and sink input volume do not match
817 unsigned int sink_input_idx = pa_stream_get_index(m_Stream);
818 SinkInputInfoStruct sii;
819 sii.mainloop = m_MainLoop;
820 bool success = WaitForOperation(pa_context_get_sink_input_info(m_Context, sink_input_idx, SinkInputInfoCallback, &sii), m_MainLoop, "Get Sink Input Info");
822 if(success && sii.is_valid)
824 // we don't have per channel values so use avg of them
825 pa_volume_t n_vol = pa_cvolume_avg(&sii.volume);
826 pa_volume_t o_vol = pa_cvolume_avg(&m_Volume);
827 sValue = (float) pa_sw_volume_to_linear(n_vol);
830 external_change = true;
831 // update internal volume
832 m_Volume = sii.volume;
833 CLog::Log(LOGDEBUG, "Restored Volume cause of external change to value to %f", sValue);
834 g_application.SetVolume(sValue, false);
836 // unmute if we should not be muted
837 if (sii.mute && sValue > 0)
839 pa_operation *op = pa_context_set_sink_input_mute(m_Context, sii.index, 0, NULL, NULL);
841 CLog::Log(LOGERROR, "PulseAudio: Failed to unmute the stream");
843 pa_operation_unref(op);
846 else // we don't know stream volume so don't change anything
848 external_change = true;
850 if (!external_change)
852 pa_volume_t pavolume = pa_sw_volume_from_linear(per_cent_volume);
854 pa_cvolume_mute(&m_Volume, m_Channels);
856 pa_cvolume_set(&m_Volume, m_Channels, pavolume);
857 pa_operation *op = pa_context_set_sink_input_volume(m_Context, sink_input_idx, &m_Volume, NULL, NULL);
859 CLog::Log(LOGERROR, "PulseAudio: Failed to set volume");
861 pa_operation_unref(op);
863 pa_threaded_mainloop_unlock(m_MainLoop);
867 void CAESinkPULSE::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
870 pa_threaded_mainloop *mainloop;
872 if (!SetupContext(NULL, &context, &mainloop))
874 CLog::Log(LOGNOTICE, "PulseAudio might not be running. Context was not created.");
878 pa_threaded_mainloop_lock(mainloop);
880 SinkInfoStruct sinkStruct;
881 sinkStruct.mainloop = mainloop;
882 sinkStruct.list = &list;
883 WaitForOperation(pa_context_get_sink_info_list(context, SinkInfoRequestCallback, &sinkStruct), mainloop, "EnumerateAudioSinks");
885 pa_threaded_mainloop_unlock(mainloop);
888 pa_threaded_mainloop_stop(mainloop);
892 pa_context_disconnect(context);
893 pa_context_unref(context);
899 pa_threaded_mainloop_free(mainloop);
904 bool CAESinkPULSE::IsInitialized()
906 CSingleLock lock(m_sec);
907 return m_IsAllocated;
910 bool CAESinkPULSE::Pause(bool pause)
912 pa_threaded_mainloop_lock(m_MainLoop);
914 if (!WaitForOperation(pa_stream_cork(m_Stream, pause ? 1 : 0, NULL, NULL), m_MainLoop, pause ? "Pause" : "Resume"))
917 pa_threaded_mainloop_unlock(m_MainLoop);
922 inline bool CAESinkPULSE::WaitForOperation(pa_operation *op, pa_threaded_mainloop *mainloop, const char *LogEntry = "")
929 while (pa_operation_get_state(op) == PA_OPERATION_RUNNING)
930 pa_threaded_mainloop_wait(mainloop);
932 if (pa_operation_get_state(op) != PA_OPERATION_DONE)
934 CLog::Log(LOGERROR, "PulseAudio: %s Operation failed", LogEntry);
938 pa_operation_unref(op);
942 bool CAESinkPULSE::SetupContext(const char *host, pa_context **context, pa_threaded_mainloop **mainloop)
944 if ((*mainloop = pa_threaded_mainloop_new()) == NULL)
946 CLog::Log(LOGERROR, "PulseAudio: Failed to allocate main loop");
950 if (((*context) = pa_context_new(pa_threaded_mainloop_get_api(*mainloop), "XBMC")) == NULL)
952 CLog::Log(LOGERROR, "PulseAudio: Failed to allocate context");
956 pa_context_set_state_callback(*context, ContextStateCallback, *mainloop);
958 if (pa_context_connect(*context, host, (pa_context_flags_t)0, NULL) < 0)
960 CLog::Log(LOGERROR, "PulseAudio: Failed to connect context");
963 pa_threaded_mainloop_lock(*mainloop);
965 if (pa_threaded_mainloop_start(*mainloop) < 0)
967 CLog::Log(LOGERROR, "PulseAudio: Failed to start MainLoop");
968 pa_threaded_mainloop_unlock(*mainloop);
972 /* Wait until the context is ready */
975 pa_threaded_mainloop_wait(*mainloop);
976 CLog::Log(LOGDEBUG, "PulseAudio: Context %s", ContextStateToString(pa_context_get_state(*context)));
978 while (pa_context_get_state(*context) != PA_CONTEXT_READY && pa_context_get_state(*context) != PA_CONTEXT_FAILED);
980 if (pa_context_get_state(*context) == PA_CONTEXT_FAILED)
982 CLog::Log(LOGERROR, "PulseAudio: Waited for the Context but it failed");
983 pa_threaded_mainloop_unlock(*mainloop);
987 pa_threaded_mainloop_unlock(*mainloop);