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/>.
23 #include "ActiveAESink.h"
24 #include "Utils/AEUtil.h"
25 #include "utils/EndianSwap.h"
28 #include "settings/Settings.h"
30 using namespace ActiveAE;
32 CActiveAESink::CActiveAESink(CEvent *inMsgEvent) :
34 m_controlPort("SinkControlPort", inMsgEvent, &m_outMsgEvent),
35 m_dataPort("SinkDataPort", inMsgEvent, &m_outMsgEvent)
37 m_inMsgEvent = inMsgEvent;
40 m_convertBuffer = NULL;
44 void CActiveAESink::Start()
49 SetPriority(THREAD_PRIORITY_ABOVE_NORMAL);
53 void CActiveAESink::Dispose()
58 m_controlPort.Purge();
64 m_sink->Deinitialize();
69 delete m_sampleOfSilence.pkt;
70 m_sampleOfSilence.pkt = NULL;
74 _aligned_free(m_convertBuffer);
75 m_convertBuffer = NULL;
79 bool CActiveAESink::HasVolume()
83 return m_sink->HasVolume();
86 AEDeviceType CActiveAESink::GetDeviceType(const std::string &device)
88 std::string dev = device;
90 CAESinkFactory::ParseDevice(dev, dri);
91 for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt)
93 for (AEDeviceInfoList::iterator itt2 = itt->m_deviceInfoList.begin(); itt2 != itt->m_deviceInfoList.end(); ++itt2)
95 CAEDeviceInfo& info = *itt2;
96 if (info.m_deviceName == dev)
97 return info.m_deviceType;
100 return AE_DEVTYPE_PCM;
103 bool CActiveAESink::HasPassthroughDevice()
105 for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt)
107 for (AEDeviceInfoList::iterator itt2 = itt->m_deviceInfoList.begin(); itt2 != itt->m_deviceInfoList.end(); ++itt2)
109 CAEDeviceInfo& info = *itt2;
110 if (info.m_deviceType != AE_DEVTYPE_PCM)
120 S_TOP_UNCONFIGURED, // 1
121 S_TOP_CONFIGURED, // 2
122 S_TOP_CONFIGURED_SUSPEND, // 3
123 S_TOP_CONFIGURED_IDLE, // 4
124 S_TOP_CONFIGURED_PLAY, // 5
125 S_TOP_CONFIGURED_SILENCE, // 6
128 int SINK_parentStates[] = {
130 0, //TOP_UNCONFIGURED
132 2, //TOP_CONFIGURED_SUSPEND
133 2, //TOP_CONFIGURED_IDLE
134 2, //TOP_CONFIGURED_PLAY
135 2, //TOP_CONFIGURED_SILENCE
138 void CActiveAESink::StateMachine(int signal, Protocol *port, Message *msg)
140 for (int state = m_state; ; state = SINK_parentStates[state])
145 if (port == &m_controlPort)
149 case CSinkControlProtocol::CONFIGURE:
151 data = (SinkConfig*)msg->data;
154 m_requestedFormat = data->format;
155 m_stats = data->stats;
156 m_device = *(data->device);
159 m_extSilenceTimer = 0;
165 m_stats->SetSinkCacheTotal(m_sink->GetCacheTotal());
166 m_stats->SetSinkLatency(m_sink->GetLatency());
167 m_state = S_TOP_CONFIGURED_IDLE;
168 m_extTimeout = 10000;
169 msg->Reply(CSinkControlProtocol::ACC, &m_sinkFormat, sizeof(AEAudioFormat));
173 m_state = S_TOP_UNCONFIGURED;
174 msg->Reply(CSinkControlProtocol::ERR);
178 case CSinkControlProtocol::UNCONFIGURE:
183 m_sink->Deinitialize();
187 m_state = S_TOP_UNCONFIGURED;
188 msg->Reply(CSinkControlProtocol::ACC);
191 case CSinkControlProtocol::FLUSH:
193 msg->Reply(CSinkControlProtocol::ACC);
200 else if (port == &m_dataPort)
204 case CSinkDataProtocol::DRAIN:
205 msg->Reply(CSinkDataProtocol::ACC);
206 m_state = S_TOP_UNCONFIGURED;
214 std::string portName = port == NULL ? "timer" : port->portName;
215 CLog::Log(LOGWARNING, "CActiveAESink::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
219 case S_TOP_UNCONFIGURED:
220 if (port == NULL) // timeout
224 case CSinkControlProtocol::TIMEOUT:
231 else if (port == &m_dataPort)
235 case CSinkDataProtocol::SAMPLE:
236 CSampleBuffer *samples;
238 samples = *((CSampleBuffer**)msg->data);
239 timeout = 1000*samples->pkt->nb_samples/samples->pkt->config.sample_rate;
241 msg->Reply(CSinkDataProtocol::RETURNSAMPLE, &samples, sizeof(CSampleBuffer*));
250 case S_TOP_CONFIGURED:
251 if (port == &m_controlPort)
255 case CSinkControlProtocol::SILENCEMODE:
257 silencemode = *(bool*)msg->data;
259 m_extSilenceTimeout = XbmcThreads::EndTime::InfiniteValue;
261 m_extSilenceTimeout = CSettings::Get().GetInt("audiooutput.streamsilence") * 60000;
262 m_extSilenceTimer.Set(m_extSilenceTimeout);
263 if (!m_extSilenceTimer.IsTimePast())
265 m_state = S_TOP_CONFIGURED_SILENCE;
269 case CSinkControlProtocol::VOLUME:
270 m_volume = *(float*)msg->data;
271 m_sink->SetVolume(m_volume);
277 else if (port == &m_dataPort)
281 case CSinkDataProtocol::DRAIN:
283 msg->Reply(CSinkDataProtocol::ACC);
284 m_state = S_TOP_CONFIGURED_IDLE;
285 m_extTimeout = 10000;
287 case CSinkDataProtocol::SAMPLE:
288 CSampleBuffer *samples;
290 samples = *((CSampleBuffer**)msg->data);
291 delay = OutputSamples(samples);
292 msg->Reply(CSinkDataProtocol::RETURNSAMPLE, &samples, sizeof(CSampleBuffer*));
295 m_sink->Deinitialize();
298 m_state = S_TOP_CONFIGURED_SUSPEND;
303 m_state = S_TOP_CONFIGURED_PLAY;
304 m_extTimeout = delay / 2;
305 m_extSilenceTimer.Set(m_extSilenceTimeout);
314 case S_TOP_CONFIGURED_SUSPEND:
315 if (port == &m_controlPort)
319 case CSinkControlProtocol::SILENCEMODE:
321 case CSinkControlProtocol::VOLUME:
322 m_volume = *(float*)msg->data;
328 else if (port == &m_dataPort)
332 case CSinkDataProtocol::SAMPLE:
335 OutputSamples(&m_sampleOfSilence);
336 m_state = S_TOP_CONFIGURED_PLAY;
338 m_bStateMachineSelfTrigger = true;
340 case CSinkDataProtocol::DRAIN:
341 msg->Reply(CSinkDataProtocol::ACC);
347 else if (port == NULL) // timeout
351 case CSinkControlProtocol::TIMEOUT:
352 m_extTimeout = 10000;
360 case S_TOP_CONFIGURED_IDLE:
361 if (port == &m_dataPort)
365 case CSinkDataProtocol::SAMPLE:
366 OutputSamples(&m_sampleOfSilence);
367 m_state = S_TOP_CONFIGURED_PLAY;
369 m_bStateMachineSelfTrigger = true;
375 else if (port == NULL) // timeout
379 case CSinkControlProtocol::TIMEOUT:
380 m_sink->Deinitialize();
383 m_state = S_TOP_CONFIGURED_SUSPEND;
384 m_extTimeout = 10000;
392 case S_TOP_CONFIGURED_PLAY:
393 if (port == NULL) // timeout
397 case CSinkControlProtocol::TIMEOUT:
398 if (!m_extSilenceTimer.IsTimePast())
400 m_state = S_TOP_CONFIGURED_SILENCE;
406 m_state = S_TOP_CONFIGURED_IDLE;
407 m_extTimeout = 10000;
416 case S_TOP_CONFIGURED_SILENCE:
417 if (port == NULL) // timeout
421 case CSinkControlProtocol::TIMEOUT:
422 OutputSamples(&m_sampleOfSilence);
425 m_sink->Deinitialize();
428 m_state = S_TOP_CONFIGURED_SUSPEND;
431 m_state = S_TOP_CONFIGURED_PLAY;
440 default: // we are in no state, should not happen
441 CLog::Log(LOGERROR, "CActiveAESink::%s - no valid state: %d", __FUNCTION__, m_state);
447 void CActiveAESink::Process()
450 Protocol *port = NULL;
452 XbmcThreads::EndTime timer;
454 m_state = S_TOP_UNCONFIGURED;
456 m_bStateMachineSelfTrigger = false;
461 timer.Set(m_extTimeout);
463 if (m_bStateMachineSelfTrigger)
465 m_bStateMachineSelfTrigger = false;
466 // self trigger state machine
467 StateMachine(msg->signal, port, msg);
468 if (!m_bStateMachineSelfTrigger)
475 // check control port
476 else if (m_controlPort.ReceiveOutMessage(&msg))
479 port = &m_controlPort;
482 else if (m_dataPort.ReceiveOutMessage(&msg))
490 StateMachine(msg->signal, port, msg);
491 if (!m_bStateMachineSelfTrigger)
500 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
502 m_extTimeout = timer.MillisLeft();
508 msg = m_controlPort.GetMessage();
509 msg->signal = CSinkControlProtocol::TIMEOUT;
511 // signal timeout to state machine
512 StateMachine(msg->signal, port, msg);
513 if (!m_bStateMachineSelfTrigger)
522 void CActiveAESink::EnumerateSinkList(bool force)
524 if (!m_sinkInfoList.empty() && !force)
527 unsigned int c_retry = 5;
528 m_sinkInfoList.clear();
529 CAESinkFactory::EnumerateEx(m_sinkInfoList);
530 while(m_sinkInfoList.size() == 0 && c_retry > 0)
532 CLog::Log(LOGNOTICE, "No Devices found - retry: %d", c_retry);
535 // retry the enumeration
536 CAESinkFactory::EnumerateEx(m_sinkInfoList, true);
538 CLog::Log(LOGNOTICE, "Found %lu Lists of Devices", m_sinkInfoList.size());
542 void CActiveAESink::PrintSinks()
544 for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt)
546 CLog::Log(LOGNOTICE, "Enumerated %s devices:", itt->m_sinkName.c_str());
548 for (AEDeviceInfoList::iterator itt2 = itt->m_deviceInfoList.begin(); itt2 != itt->m_deviceInfoList.end(); ++itt2)
550 CLog::Log(LOGNOTICE, " Device %d", ++count);
551 CAEDeviceInfo& info = *itt2;
552 std::stringstream ss((std::string)info);
554 while(std::getline(ss, line, '\n'))
555 CLog::Log(LOGNOTICE, " %s", line.c_str());
560 void CActiveAESink::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough)
562 EnumerateSinkList(false);
564 for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt)
566 AESinkInfo sinkInfo = *itt;
567 for (AEDeviceInfoList::iterator itt2 = sinkInfo.m_deviceInfoList.begin(); itt2 != sinkInfo.m_deviceInfoList.end(); ++itt2)
569 CAEDeviceInfo devInfo = *itt2;
570 if (passthrough && devInfo.m_deviceType == AE_DEVTYPE_PCM)
573 std::string device = sinkInfo.m_sinkName + ":" + devInfo.m_deviceName;
575 std::stringstream ss;
577 /* add the sink name if we have more then one sink type */
578 if (m_sinkInfoList.size() > 1)
579 ss << sinkInfo.m_sinkName << ": ";
581 ss << devInfo.m_displayName;
582 if (!devInfo.m_displayNameExtra.empty())
583 ss << ", " << devInfo.m_displayNameExtra;
585 devices.push_back(AEDevice(ss.str(), device));
590 std::string CActiveAESink::GetDefaultDevice(bool passthrough)
592 EnumerateSinkList(false);
594 for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt)
596 AESinkInfo sinkInfo = *itt;
597 for (AEDeviceInfoList::iterator itt2 = sinkInfo.m_deviceInfoList.begin(); itt2 != sinkInfo.m_deviceInfoList.end(); ++itt2)
599 CAEDeviceInfo devInfo = *itt2;
600 if (passthrough && devInfo.m_deviceType == AE_DEVTYPE_PCM)
603 std::string device = sinkInfo.m_sinkName + ":" + devInfo.m_deviceName;
610 void CActiveAESink::GetDeviceFriendlyName(std::string &device)
612 m_deviceFriendlyName = "Device not found";
613 /* Match the device and find its friendly name */
614 for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt)
616 AESinkInfo sinkInfo = *itt;
617 for (AEDeviceInfoList::iterator itt2 = sinkInfo.m_deviceInfoList.begin(); itt2 != sinkInfo.m_deviceInfoList.end(); ++itt2)
619 CAEDeviceInfo& devInfo = *itt2;
620 if (devInfo.m_deviceName == device)
622 m_deviceFriendlyName = devInfo.m_displayName;
630 void CActiveAESink::OpenSink()
632 // we need a copy of m_device here because ParseDevice and CreateDevice write back
633 // into this variable
634 std::string device = m_device;
636 bool passthrough = AE_IS_RAW(m_requestedFormat.m_dataFormat);
638 CAESinkFactory::ParseDevice(device, driver);
639 if (driver.empty() && m_sink)
640 driver = m_sink->GetName();
642 CLog::Log(LOGINFO, "CActiveAESink::OpenSink - initialize sink");
647 m_sink->Deinitialize();
652 // get the display name of the device
653 GetDeviceFriendlyName(device);
655 // if we already have a driver, prepend it to the device string
657 device = driver + ":" + device;
659 // WARNING: this changes format and does not use passthrough
660 m_sinkFormat = m_requestedFormat;
661 CLog::Log(LOGDEBUG, "CActiveAESink::OpenSink - trying to open device %s", device.c_str());
662 m_sink = CAESinkFactory::Create(device, m_sinkFormat, passthrough);
666 CLog::Log(LOGERROR, "CActiveAESink::OpenSink - no sink was returned");
671 m_sink->SetVolume(m_volume);
673 #ifdef WORDS_BIGENDIAN
674 if (m_sinkFormat.m_dataFormat == AE_FMT_S16BE)
675 m_sinkFormat.m_dataFormat = AE_FMT_S16NE;
676 else if (m_sinkFormat.m_dataFormat == AE_FMT_S32BE)
677 m_sinkFormat.m_dataFormat = AE_FMT_S32NE;
679 if (m_sinkFormat.m_dataFormat == AE_FMT_S16LE)
680 m_sinkFormat.m_dataFormat = AE_FMT_S16NE;
681 else if (m_sinkFormat.m_dataFormat == AE_FMT_S32LE)
682 m_sinkFormat.m_dataFormat = AE_FMT_S32NE;
685 CLog::Log(LOGDEBUG, "CActiveAESink::OpenSink - %s Initialized:", m_sink->GetName());
686 CLog::Log(LOGDEBUG, " Output Device : %s", m_deviceFriendlyName.c_str());
687 CLog::Log(LOGDEBUG, " Sample Rate : %d", m_sinkFormat.m_sampleRate);
688 CLog::Log(LOGDEBUG, " Sample Format : %s", CAEUtil::DataFormatToStr(m_sinkFormat.m_dataFormat));
689 CLog::Log(LOGDEBUG, " Channel Count : %d", m_sinkFormat.m_channelLayout.Count());
690 CLog::Log(LOGDEBUG, " Channel Layout: %s", ((std::string)m_sinkFormat.m_channelLayout).c_str());
691 CLog::Log(LOGDEBUG, " Frames : %d", m_sinkFormat.m_frames);
692 CLog::Log(LOGDEBUG, " Frame Samples : %d", m_sinkFormat.m_frameSamples);
693 CLog::Log(LOGDEBUG, " Frame Size : %d", m_sinkFormat.m_frameSize);
695 // init sample of silence
697 config.fmt = CActiveAEResample::GetAVSampleFormat(m_sinkFormat.m_dataFormat);
698 config.bits_per_sample = CAEUtil::DataFormatToUsedBits(m_sinkFormat.m_dataFormat);
699 config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_sinkFormat.m_channelLayout);
700 config.channels = m_sinkFormat.m_channelLayout.Count();
701 config.sample_rate = m_sinkFormat.m_sampleRate;
703 // init sample of silence/noise
704 delete m_sampleOfSilence.pkt;
705 m_sampleOfSilence.pkt = new CSoundPacket(config, m_sinkFormat.m_frames);
706 m_sampleOfSilence.pkt->nb_samples = m_sampleOfSilence.pkt->max_nb_samples;
712 _aligned_free(m_convertBuffer);
713 m_convertBuffer = NULL;
716 m_convertState = CHECK_CONVERT;
719 void CActiveAESink::ReturnBuffers()
722 CSampleBuffer *samples;
723 while (m_dataPort.ReceiveOutMessage(&msg))
725 if (msg->signal == CSinkDataProtocol::SAMPLE)
727 samples = *((CSampleBuffer**)msg->data);
728 msg->Reply(CSinkDataProtocol::RETURNSAMPLE, &samples, sizeof(CSampleBuffer*));
733 unsigned int CActiveAESink::OutputSamples(CSampleBuffer* samples)
735 uint8_t *buffer = samples->pkt->data[0];
736 unsigned int frames = samples->pkt->nb_samples;
737 unsigned int maxFrames;
739 unsigned int written = 0;
740 double sinkDelay = 0.0;
742 switch(m_convertState)
747 EnsureConvertBuffer(samples);
748 buffer = Convert(samples);
751 Endian_Swap16_buf((uint16_t *)buffer, (uint16_t *)buffer, frames * samples->pkt->config.channels);
754 ConvertInit(samples);
755 if (m_convertState == NEED_CONVERT)
756 buffer = Convert(samples);
757 else if (m_convertState == NEED_BYTESWAP)
758 Endian_Swap16_buf((uint16_t *)buffer, (uint16_t *)buffer, frames * samples->pkt->config.channels);
766 maxFrames = std::min(frames, m_sinkFormat.m_frames);
767 written = m_sink->AddPackets(buffer, maxFrames, true, true);
770 Sleep(500*m_sinkFormat.m_frames/m_sinkFormat.m_sampleRate);
775 CLog::Log(LOGERROR, "CActiveAESink::OutputSamples - failed");
776 m_stats->UpdateSinkDelay(0, frames);
782 else if (written > maxFrames)
785 CLog::Log(LOGERROR, "CActiveAESink::OutputSamples - sink returned error");
786 m_stats->UpdateSinkDelay(0, samples->pool ? maxFrames : 0);
790 buffer += written*m_sinkFormat.m_frameSize;
791 sinkDelay = m_sink->GetDelay();
792 m_stats->UpdateSinkDelay(sinkDelay, samples->pool ? written : 0);
794 return sinkDelay*1000;
797 void CActiveAESink::ConvertInit(CSampleBuffer* samples)
799 if (CActiveAEResample::GetAESampleFormat(samples->pkt->config.fmt, samples->pkt->config.bits_per_sample) != m_sinkFormat.m_dataFormat)
801 m_convertFn = CAEConvert::FrFloat(m_sinkFormat.m_dataFormat);
803 _aligned_free(m_convertBuffer);
804 m_convertBufferSampleSize = samples->pkt->max_nb_samples;
805 m_convertBuffer = (uint8_t*)_aligned_malloc(samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize, 16);
806 memset(m_convertBuffer, 0, samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize);
807 m_convertState = NEED_CONVERT;
809 else if (AE_IS_RAW(m_requestedFormat.m_dataFormat) && CAEUtil::S16NeedsByteSwap(AE_FMT_S16NE, m_sinkFormat.m_dataFormat))
811 m_convertState = NEED_BYTESWAP;
814 m_convertState = SKIP_CONVERT;
817 void CActiveAESink::EnsureConvertBuffer(CSampleBuffer* samples)
819 if (!m_convertBuffer)
822 if (samples->pkt->max_nb_samples <= m_convertBufferSampleSize)
825 _aligned_free(m_convertBuffer);
826 m_convertBufferSampleSize = samples->pkt->max_nb_samples;
827 m_convertBuffer = (uint8_t*)_aligned_malloc(samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize, 16);
828 memset(m_convertBuffer, 0, samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize);
831 uint8_t* CActiveAESink::Convert(CSampleBuffer* samples)
833 m_convertFn((float*)samples->pkt->data[0], samples->pkt->nb_samples * samples->pkt->config.channels, m_convertBuffer);
834 return m_convertBuffer;
837 #define PI 3.1415926536f
839 void CActiveAESink::GenerateNoise()
841 int nb_floats = m_sinkFormat.m_frames*m_sinkFormat.m_channelLayout.Count();
842 float *noise = (float*)_aligned_malloc(nb_floats*sizeof(float), 16);
845 for(int i=0; i<nb_floats;i++)
849 R1 = (float) rand() / (float) RAND_MAX;
850 R2 = (float) rand() / (float) RAND_MAX;
854 noise[i] = (float) sqrt( -2.0f * log( R1 )) * cos( 2.0f * PI * R2 ) * 0.00001f;
857 AEDataFormat fmt = CActiveAEResample::GetAESampleFormat(m_sampleOfSilence.pkt->config.fmt, m_sampleOfSilence.pkt->config.bits_per_sample);
858 CAEConvert::AEConvertFrFn convertFn = CAEConvert::FrFloat(fmt);
859 convertFn(noise, nb_floats, m_sampleOfSilence.pkt->data[0]);
860 _aligned_free(noise);