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 "cores/AudioEngine/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 AEDeviceType CActiveAESink::GetDeviceType(const std::string &device)
81 std::string dev = device;
83 CAESinkFactory::ParseDevice(dev, dri);
84 for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt)
86 for (AEDeviceInfoList::iterator itt2 = itt->m_deviceInfoList.begin(); itt2 != itt->m_deviceInfoList.end(); ++itt2)
88 CAEDeviceInfo& info = *itt2;
89 if (info.m_deviceName == dev)
90 return info.m_deviceType;
93 return AE_DEVTYPE_PCM;
96 bool CActiveAESink::HasPassthroughDevice()
98 for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt)
100 for (AEDeviceInfoList::iterator itt2 = itt->m_deviceInfoList.begin(); itt2 != itt->m_deviceInfoList.end(); ++itt2)
102 CAEDeviceInfo& info = *itt2;
103 if (info.m_deviceType != AE_DEVTYPE_PCM)
113 S_TOP_UNCONFIGURED, // 1
114 S_TOP_CONFIGURED, // 2
115 S_TOP_CONFIGURED_SUSPEND, // 3
116 S_TOP_CONFIGURED_IDLE, // 4
117 S_TOP_CONFIGURED_PLAY, // 5
118 S_TOP_CONFIGURED_SILENCE, // 6
121 int SINK_parentStates[] = {
123 0, //TOP_UNCONFIGURED
125 2, //TOP_CONFIGURED_SUSPEND
126 2, //TOP_CONFIGURED_IDLE
127 2, //TOP_CONFIGURED_PLAY
128 2, //TOP_CONFIGURED_SILENCE
131 void CActiveAESink::StateMachine(int signal, Protocol *port, Message *msg)
133 for (int state = m_state; ; state = SINK_parentStates[state])
138 if (port == &m_controlPort)
142 case CSinkControlProtocol::CONFIGURE:
144 data = (SinkConfig*)msg->data;
147 m_requestedFormat = data->format;
148 m_stats = data->stats;
149 m_device = *(data->device);
152 m_extSilenceTimer = 0;
159 reply.format = m_sinkFormat;
160 reply.cacheTotal = m_sink->GetCacheTotal();
161 reply.latency = m_sink->GetLatency();
162 reply.hasVolume = m_sink->HasVolume();
163 m_state = S_TOP_CONFIGURED_IDLE;
164 m_extTimeout = 10000;
165 msg->Reply(CSinkControlProtocol::ACC, &reply, sizeof(SinkReply));
169 m_state = S_TOP_UNCONFIGURED;
170 msg->Reply(CSinkControlProtocol::ERR);
174 case CSinkControlProtocol::UNCONFIGURE:
179 m_sink->Deinitialize();
183 m_state = S_TOP_UNCONFIGURED;
184 msg->Reply(CSinkControlProtocol::ACC);
187 case CSinkControlProtocol::FLUSH:
189 msg->Reply(CSinkControlProtocol::ACC);
196 else if (port == &m_dataPort)
200 case CSinkDataProtocol::DRAIN:
201 msg->Reply(CSinkDataProtocol::ACC);
202 m_state = S_TOP_UNCONFIGURED;
210 std::string portName = port == NULL ? "timer" : port->portName;
211 CLog::Log(LOGWARNING, "CActiveAESink::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
215 case S_TOP_UNCONFIGURED:
216 if (port == NULL) // timeout
220 case CSinkControlProtocol::TIMEOUT:
227 else if (port == &m_dataPort)
231 case CSinkDataProtocol::SAMPLE:
232 CSampleBuffer *samples;
234 samples = *((CSampleBuffer**)msg->data);
235 timeout = 1000*samples->pkt->nb_samples/samples->pkt->config.sample_rate;
237 msg->Reply(CSinkDataProtocol::RETURNSAMPLE, &samples, sizeof(CSampleBuffer*));
246 case S_TOP_CONFIGURED:
247 if (port == &m_controlPort)
251 case CSinkControlProtocol::SILENCEMODE:
253 silencemode = *(bool*)msg->data;
255 m_extSilenceTimeout = XbmcThreads::EndTime::InfiniteValue;
257 m_extSilenceTimeout = CSettings::Get().GetInt("audiooutput.streamsilence") * 60000;
258 m_extSilenceTimer.Set(m_extSilenceTimeout);
259 if (!m_extSilenceTimer.IsTimePast())
261 m_state = S_TOP_CONFIGURED_SILENCE;
265 case CSinkControlProtocol::VOLUME:
266 m_volume = *(float*)msg->data;
267 m_sink->SetVolume(m_volume);
273 else if (port == &m_dataPort)
277 case CSinkDataProtocol::DRAIN:
279 msg->Reply(CSinkDataProtocol::ACC);
280 m_state = S_TOP_CONFIGURED_IDLE;
281 m_extTimeout = 10000;
283 case CSinkDataProtocol::SAMPLE:
284 CSampleBuffer *samples;
286 samples = *((CSampleBuffer**)msg->data);
287 delay = OutputSamples(samples);
288 msg->Reply(CSinkDataProtocol::RETURNSAMPLE, &samples, sizeof(CSampleBuffer*));
291 m_sink->Deinitialize();
294 m_state = S_TOP_CONFIGURED_SUSPEND;
299 m_state = S_TOP_CONFIGURED_PLAY;
300 m_extTimeout = delay / 2;
301 m_extSilenceTimer.Set(m_extSilenceTimeout);
310 case S_TOP_CONFIGURED_SUSPEND:
311 if (port == &m_controlPort)
315 case CSinkControlProtocol::SILENCEMODE:
317 case CSinkControlProtocol::VOLUME:
318 m_volume = *(float*)msg->data;
324 else if (port == &m_dataPort)
328 case CSinkDataProtocol::SAMPLE:
331 OutputSamples(&m_sampleOfSilence);
332 m_state = S_TOP_CONFIGURED_PLAY;
334 m_bStateMachineSelfTrigger = true;
336 case CSinkDataProtocol::DRAIN:
337 msg->Reply(CSinkDataProtocol::ACC);
343 else if (port == NULL) // timeout
347 case CSinkControlProtocol::TIMEOUT:
348 m_extTimeout = 10000;
356 case S_TOP_CONFIGURED_IDLE:
357 if (port == &m_dataPort)
361 case CSinkDataProtocol::SAMPLE:
362 OutputSamples(&m_sampleOfSilence);
363 m_state = S_TOP_CONFIGURED_PLAY;
365 m_bStateMachineSelfTrigger = true;
371 else if (port == NULL) // timeout
375 case CSinkControlProtocol::TIMEOUT:
376 m_sink->Deinitialize();
379 m_state = S_TOP_CONFIGURED_SUSPEND;
380 m_extTimeout = 10000;
388 case S_TOP_CONFIGURED_PLAY:
389 if (port == NULL) // timeout
393 case CSinkControlProtocol::TIMEOUT:
394 if (!m_extSilenceTimer.IsTimePast())
396 m_state = S_TOP_CONFIGURED_SILENCE;
402 m_state = S_TOP_CONFIGURED_IDLE;
403 m_extTimeout = 10000;
412 case S_TOP_CONFIGURED_SILENCE:
413 if (port == NULL) // timeout
417 case CSinkControlProtocol::TIMEOUT:
418 OutputSamples(&m_sampleOfSilence);
421 m_sink->Deinitialize();
424 m_state = S_TOP_CONFIGURED_SUSPEND;
427 m_state = S_TOP_CONFIGURED_PLAY;
436 default: // we are in no state, should not happen
437 CLog::Log(LOGERROR, "CActiveAESink::%s - no valid state: %d", __FUNCTION__, m_state);
443 void CActiveAESink::Process()
446 Protocol *port = NULL;
448 XbmcThreads::EndTime timer;
450 m_state = S_TOP_UNCONFIGURED;
452 m_bStateMachineSelfTrigger = false;
457 timer.Set(m_extTimeout);
459 if (m_bStateMachineSelfTrigger)
461 m_bStateMachineSelfTrigger = false;
462 // self trigger state machine
463 StateMachine(msg->signal, port, msg);
464 if (!m_bStateMachineSelfTrigger)
471 // check control port
472 else if (m_controlPort.ReceiveOutMessage(&msg))
475 port = &m_controlPort;
478 else if (m_dataPort.ReceiveOutMessage(&msg))
486 StateMachine(msg->signal, port, msg);
487 if (!m_bStateMachineSelfTrigger)
496 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
498 m_extTimeout = timer.MillisLeft();
504 msg = m_controlPort.GetMessage();
505 msg->signal = CSinkControlProtocol::TIMEOUT;
507 // signal timeout to state machine
508 StateMachine(msg->signal, port, msg);
509 if (!m_bStateMachineSelfTrigger)
518 void CActiveAESink::EnumerateSinkList(bool force)
520 if (!m_sinkInfoList.empty() && !force)
523 unsigned int c_retry = 5;
524 m_sinkInfoList.clear();
525 CAESinkFactory::EnumerateEx(m_sinkInfoList);
526 while(m_sinkInfoList.size() == 0 && c_retry > 0)
528 CLog::Log(LOGNOTICE, "No Devices found - retry: %d", c_retry);
531 // retry the enumeration
532 CAESinkFactory::EnumerateEx(m_sinkInfoList, true);
534 CLog::Log(LOGNOTICE, "Found %lu Lists of Devices", m_sinkInfoList.size());
538 void CActiveAESink::PrintSinks()
540 for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt)
542 CLog::Log(LOGNOTICE, "Enumerated %s devices:", itt->m_sinkName.c_str());
544 for (AEDeviceInfoList::iterator itt2 = itt->m_deviceInfoList.begin(); itt2 != itt->m_deviceInfoList.end(); ++itt2)
546 CLog::Log(LOGNOTICE, " Device %d", ++count);
547 CAEDeviceInfo& info = *itt2;
548 std::stringstream ss((std::string)info);
550 while(std::getline(ss, line, '\n'))
551 CLog::Log(LOGNOTICE, " %s", line.c_str());
556 void CActiveAESink::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough)
558 EnumerateSinkList(false);
560 for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt)
562 AESinkInfo sinkInfo = *itt;
563 for (AEDeviceInfoList::iterator itt2 = sinkInfo.m_deviceInfoList.begin(); itt2 != sinkInfo.m_deviceInfoList.end(); ++itt2)
565 CAEDeviceInfo devInfo = *itt2;
566 if (passthrough && devInfo.m_deviceType == AE_DEVTYPE_PCM)
569 std::string device = sinkInfo.m_sinkName + ":" + devInfo.m_deviceName;
571 std::stringstream ss;
573 /* add the sink name if we have more then one sink type */
574 if (m_sinkInfoList.size() > 1)
575 ss << sinkInfo.m_sinkName << ": ";
577 ss << devInfo.m_displayName;
578 if (!devInfo.m_displayNameExtra.empty())
579 ss << ", " << devInfo.m_displayNameExtra;
581 devices.push_back(AEDevice(ss.str(), device));
586 std::string CActiveAESink::GetDefaultDevice(bool passthrough)
588 EnumerateSinkList(false);
590 for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt)
592 AESinkInfo sinkInfo = *itt;
593 for (AEDeviceInfoList::iterator itt2 = sinkInfo.m_deviceInfoList.begin(); itt2 != sinkInfo.m_deviceInfoList.end(); ++itt2)
595 CAEDeviceInfo devInfo = *itt2;
596 if (passthrough && devInfo.m_deviceType == AE_DEVTYPE_PCM)
599 std::string device = sinkInfo.m_sinkName + ":" + devInfo.m_deviceName;
606 void CActiveAESink::GetDeviceFriendlyName(std::string &device)
608 m_deviceFriendlyName = "Device not found";
609 /* Match the device and find its friendly name */
610 for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt)
612 AESinkInfo sinkInfo = *itt;
613 for (AEDeviceInfoList::iterator itt2 = sinkInfo.m_deviceInfoList.begin(); itt2 != sinkInfo.m_deviceInfoList.end(); ++itt2)
615 CAEDeviceInfo& devInfo = *itt2;
616 if (devInfo.m_deviceName == device)
618 m_deviceFriendlyName = devInfo.m_displayName;
626 void CActiveAESink::OpenSink()
628 // we need a copy of m_device here because ParseDevice and CreateDevice write back
629 // into this variable
630 std::string device = m_device;
632 bool passthrough = AE_IS_RAW(m_requestedFormat.m_dataFormat);
634 CAESinkFactory::ParseDevice(device, driver);
635 if (driver.empty() && m_sink)
636 driver = m_sink->GetName();
638 CLog::Log(LOGINFO, "CActiveAESink::OpenSink - initialize sink");
643 m_sink->Deinitialize();
648 // get the display name of the device
649 GetDeviceFriendlyName(device);
651 // if we already have a driver, prepend it to the device string
653 device = driver + ":" + device;
655 // WARNING: this changes format and does not use passthrough
656 m_sinkFormat = m_requestedFormat;
657 CLog::Log(LOGDEBUG, "CActiveAESink::OpenSink - trying to open device %s", device.c_str());
658 m_sink = CAESinkFactory::Create(device, m_sinkFormat, passthrough);
660 // try first device in out list
661 if (!m_sink && !m_sinkInfoList.empty())
663 driver = m_sinkInfoList.front().m_sinkName;
664 device = m_sinkInfoList.front().m_deviceInfoList.front().m_deviceName;
665 GetDeviceFriendlyName(device);
667 device = driver + ":" + device;
668 m_sinkFormat = m_requestedFormat;
669 CLog::Log(LOGDEBUG, "CActiveAESink::OpenSink - trying to open device %s", device.c_str());
670 m_sink = CAESinkFactory::Create(device, m_sinkFormat, passthrough);
674 // TODO: should not be required by ActiveAE
677 device = "NULL:NULL";
678 m_sinkFormat = m_requestedFormat;
679 CLog::Log(LOGDEBUG, "CActiveAESink::OpenSink - open NULL sink");
680 m_sink = CAESinkFactory::Create(device, m_sinkFormat, passthrough);
685 CLog::Log(LOGERROR, "CActiveAESink::OpenSink - no sink was returned");
690 m_sink->SetVolume(m_volume);
692 #ifdef WORDS_BIGENDIAN
693 if (m_sinkFormat.m_dataFormat == AE_FMT_S16BE)
694 m_sinkFormat.m_dataFormat = AE_FMT_S16NE;
695 else if (m_sinkFormat.m_dataFormat == AE_FMT_S32BE)
696 m_sinkFormat.m_dataFormat = AE_FMT_S32NE;
698 if (m_sinkFormat.m_dataFormat == AE_FMT_S16LE)
699 m_sinkFormat.m_dataFormat = AE_FMT_S16NE;
700 else if (m_sinkFormat.m_dataFormat == AE_FMT_S32LE)
701 m_sinkFormat.m_dataFormat = AE_FMT_S32NE;
704 CLog::Log(LOGDEBUG, "CActiveAESink::OpenSink - %s Initialized:", m_sink->GetName());
705 CLog::Log(LOGDEBUG, " Output Device : %s", m_deviceFriendlyName.c_str());
706 CLog::Log(LOGDEBUG, " Sample Rate : %d", m_sinkFormat.m_sampleRate);
707 CLog::Log(LOGDEBUG, " Sample Format : %s", CAEUtil::DataFormatToStr(m_sinkFormat.m_dataFormat));
708 CLog::Log(LOGDEBUG, " Channel Count : %d", m_sinkFormat.m_channelLayout.Count());
709 CLog::Log(LOGDEBUG, " Channel Layout: %s", ((std::string)m_sinkFormat.m_channelLayout).c_str());
710 CLog::Log(LOGDEBUG, " Frames : %d", m_sinkFormat.m_frames);
711 CLog::Log(LOGDEBUG, " Frame Samples : %d", m_sinkFormat.m_frameSamples);
712 CLog::Log(LOGDEBUG, " Frame Size : %d", m_sinkFormat.m_frameSize);
714 // init sample of silence
716 config.fmt = CActiveAEResample::GetAVSampleFormat(m_sinkFormat.m_dataFormat);
717 config.bits_per_sample = CAEUtil::DataFormatToUsedBits(m_sinkFormat.m_dataFormat);
718 config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_sinkFormat.m_channelLayout);
719 config.channels = m_sinkFormat.m_channelLayout.Count();
720 config.sample_rate = m_sinkFormat.m_sampleRate;
722 // init sample of silence/noise
723 delete m_sampleOfSilence.pkt;
724 m_sampleOfSilence.pkt = new CSoundPacket(config, m_sinkFormat.m_frames);
725 m_sampleOfSilence.pkt->nb_samples = m_sampleOfSilence.pkt->max_nb_samples;
731 _aligned_free(m_convertBuffer);
732 m_convertBuffer = NULL;
735 m_convertState = CHECK_CONVERT;
738 void CActiveAESink::ReturnBuffers()
741 CSampleBuffer *samples;
742 while (m_dataPort.ReceiveOutMessage(&msg))
744 if (msg->signal == CSinkDataProtocol::SAMPLE)
746 samples = *((CSampleBuffer**)msg->data);
747 msg->Reply(CSinkDataProtocol::RETURNSAMPLE, &samples, sizeof(CSampleBuffer*));
752 unsigned int CActiveAESink::OutputSamples(CSampleBuffer* samples)
754 uint8_t *buffer = samples->pkt->data[0];
755 unsigned int frames = samples->pkt->nb_samples;
756 unsigned int maxFrames;
758 unsigned int written = 0;
759 double sinkDelay = 0.0;
761 switch(m_convertState)
766 EnsureConvertBuffer(samples);
767 buffer = Convert(samples);
770 Endian_Swap16_buf((uint16_t *)buffer, (uint16_t *)buffer, frames * samples->pkt->config.channels);
773 ConvertInit(samples);
774 if (m_convertState == NEED_CONVERT)
775 buffer = Convert(samples);
776 else if (m_convertState == NEED_BYTESWAP)
777 Endian_Swap16_buf((uint16_t *)buffer, (uint16_t *)buffer, frames * samples->pkt->config.channels);
785 maxFrames = std::min(frames, m_sinkFormat.m_frames);
786 written = m_sink->AddPackets(buffer, maxFrames, true, true);
789 Sleep(500*m_sinkFormat.m_frames/m_sinkFormat.m_sampleRate);
794 CLog::Log(LOGERROR, "CActiveAESink::OutputSamples - failed");
795 m_stats->UpdateSinkDelay(0, frames);
801 else if (written > maxFrames)
804 CLog::Log(LOGERROR, "CActiveAESink::OutputSamples - sink returned error");
805 m_stats->UpdateSinkDelay(0, samples->pool ? maxFrames : 0);
809 buffer += written*m_sinkFormat.m_frameSize;
810 sinkDelay = m_sink->GetDelay();
811 m_stats->UpdateSinkDelay(sinkDelay, samples->pool ? written : 0);
813 return sinkDelay*1000;
816 void CActiveAESink::ConvertInit(CSampleBuffer* samples)
818 if (CActiveAEResample::GetAESampleFormat(samples->pkt->config.fmt, samples->pkt->config.bits_per_sample) != m_sinkFormat.m_dataFormat)
820 m_convertFn = CAEConvert::FrFloat(m_sinkFormat.m_dataFormat);
822 _aligned_free(m_convertBuffer);
823 m_convertBufferSampleSize = samples->pkt->max_nb_samples;
824 m_convertBuffer = (uint8_t*)_aligned_malloc(samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize, 16);
825 memset(m_convertBuffer, 0, samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize);
826 m_convertState = NEED_CONVERT;
828 else if (AE_IS_RAW(m_requestedFormat.m_dataFormat) && CAEUtil::S16NeedsByteSwap(AE_FMT_S16NE, m_sinkFormat.m_dataFormat))
830 m_convertState = NEED_BYTESWAP;
833 m_convertState = SKIP_CONVERT;
836 void CActiveAESink::EnsureConvertBuffer(CSampleBuffer* samples)
838 if (!m_convertBuffer)
841 if (samples->pkt->max_nb_samples <= m_convertBufferSampleSize)
844 _aligned_free(m_convertBuffer);
845 m_convertBufferSampleSize = samples->pkt->max_nb_samples;
846 m_convertBuffer = (uint8_t*)_aligned_malloc(samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize, 16);
847 memset(m_convertBuffer, 0, samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize);
850 uint8_t* CActiveAESink::Convert(CSampleBuffer* samples)
852 m_convertFn((float*)samples->pkt->data[0], samples->pkt->nb_samples * samples->pkt->config.channels, m_convertBuffer);
853 return m_convertBuffer;
856 #define PI 3.1415926536f
858 void CActiveAESink::GenerateNoise()
860 int nb_floats = m_sinkFormat.m_frames*m_sinkFormat.m_channelLayout.Count();
861 float *noise = (float*)_aligned_malloc(nb_floats*sizeof(float), 16);
864 for(int i=0; i<nb_floats;i++)
868 R1 = (float) rand() / (float) RAND_MAX;
869 R2 = (float) rand() / (float) RAND_MAX;
873 noise[i] = (float) sqrt( -2.0f * log( R1 )) * cos( 2.0f * PI * R2 ) * 0.00001f;
876 AEDataFormat fmt = CActiveAEResample::GetAESampleFormat(m_sampleOfSilence.pkt->config.fmt, m_sampleOfSilence.pkt->config.bits_per_sample);
877 CAEConvert::AEConvertFrFn convertFn = CAEConvert::FrFloat(fmt);
878 convertFn(noise, nb_floats, m_sampleOfSilence.pkt->data[0]);
879 _aligned_free(noise);