2 * Copyright (C) 2011-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 "CoreAudioAE.h"
25 #include "CoreAudioAEStream.h"
26 #include "CoreAudioAESound.h"
27 #include "Application.h"
28 #include "cores/AudioEngine/Utils/AEUtil.h"
29 #include "settings/AdvancedSettings.h"
30 #include "settings/Settings.h"
31 #include "threads/SingleLock.h"
32 #include "utils/EndianSwap.h"
33 #include "utils/log.h"
34 #include "utils/TimeUtils.h"
35 #include "utils/MathUtils.h"
36 #include "threads/SystemClock.h"
38 #define DELAY_FRAME_TIME 20
39 #define BUFFERSIZE 16416
41 // on darwin when the devicelist changes
42 // reinit by calling opencoreaudio with the last engine parameters
43 // (this will fallback to default
44 // device when our current output device vanishes
45 // and on the other hand will go back to that device
47 #if defined(TARGET_DARWIN_OSX)
48 OSStatus deviceChangedCB( AudioObjectID inObjectID,
49 UInt32 inNumberAddresses,
50 const AudioObjectPropertyAddress inAddresses[],
53 CCoreAudioAE *pEngine = (CCoreAudioAE *)inClientData;
54 if (pEngine->GetHAL())
56 pEngine->AudioDevicesChanged();
57 CLog::Log(LOGDEBUG, "CCoreAudioAE - audiodevicelist changed!");
62 void RegisterDeviceChangedCB(bool bRegister, void *ref)
65 const AudioObjectPropertyAddress inAdr =
67 kAudioHardwarePropertyDevices,
68 kAudioObjectPropertyScopeGlobal,
69 kAudioObjectPropertyElementMaster
73 ret = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref);
75 ret = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref);
78 CLog::Log(LOGERROR, "CCoreAudioAE::Deinitialize - error %s a listener callback for device changes!", bRegister?"attaching":"removing");
81 void RegisterDeviceChangedCB(bool bRegister, void *ref){}
84 CCoreAudioAE::CCoreAudioAE() :
85 m_Initialized (false ),
86 m_deviceLost (false ),
87 m_callbackRunning (false ),
88 m_lastStreamFormat (AE_FMT_INVALID),
89 m_lastChLayoutCount (0 ),
90 m_lastSampleRate (0 ),
92 m_rawPassthrough (false ),
94 m_volumeBeforeMute (1.0f ),
96 m_soundMode (AE_SOUND_OFF ),
97 m_streamsPlaying (false ),
98 m_isSuspended (false ),
99 m_softSuspend (false ),
100 m_softSuspendTimer (0 )
102 HAL = new CCoreAudioAEHAL;
104 RegisterDeviceChangedCB(true, this);
107 CCoreAudioAE::~CCoreAudioAE()
109 RegisterDeviceChangedCB(false, this);
113 void CCoreAudioAE::Shutdown()
115 CSingleLock engineLock(m_engineLock);
121 /* free the streams */
122 CSingleLock streamLock(m_streamLock);
123 while (!m_streams.empty())
125 CCoreAudioAEStream *s = m_streams.front();
126 m_sounds.pop_front();
130 /* free the sounds */
131 CSingleLock soundLock(m_soundLock);
132 while (!m_sounds.empty())
134 CCoreAudioAESound *s = m_sounds.front();
135 m_sounds.pop_front();
143 void CCoreAudioAE::AudioDevicesChanged()
145 if (!m_Initialized && !m_deviceLost)
148 CSingleLock engineLock(m_engineLock);
150 // re-check initialized since it can have changed when we waited and grabbed the lock
151 if (!m_Initialized && !m_deviceLost)
154 OpenCoreAudio(m_lastSampleRate, COREAUDIO_IS_RAW(m_lastStreamFormat), m_lastStreamFormat, m_transcode);
156 // when we tried to open the default device or the last device
157 // again there was an error preventing us from doing it (mostly
158 // the device couldn't be found) - in that case
159 // mark our device as lost and hope that another callback
160 // for changed device list fires (e.x. device reappears)
164 m_deviceLost = false;
167 bool CCoreAudioAE::Initialize()
169 CSingleLock engineLock(m_engineLock);
175 bool ret = OpenCoreAudio(44100, false, AE_FMT_FLOAT, false);
176 m_lastSampleRate = 44100;
177 m_lastStreamFormat = AE_FMT_FLOAT;
184 bool CCoreAudioAE::OpenCoreAudio(unsigned int sampleRate, bool forceRaw,
185 enum AEDataFormat rawDataFormat, bool forceTranscode)
187 unsigned int maxChannelCountInStreams = 0;
188 // remove any deleted streams
189 CSingleLock streamLock(m_streamLock);
190 for (StreamList::iterator itt = m_streams.begin(); itt != m_streams.end();)
192 CCoreAudioAEStream *stream = *itt;
193 if (stream->IsDestroyed())
195 itt = m_streams.erase(itt);
201 // close all converter
202 stream->CloseConverter();
205 if (stream->GetChannelCount() > maxChannelCountInStreams)
206 maxChannelCountInStreams = stream->GetChannelCount();
211 /* override the sample rate based on the oldest stream if there is one */
212 if (!m_streams.empty())
213 sampleRate = m_streams.front()->GetSampleRate();
216 m_rawPassthrough = true;
218 m_rawPassthrough = !m_streams.empty() && m_streams.front()->IsRaw();
221 if (m_rawPassthrough)
222 CLog::Log(LOGINFO, "CCoreAudioAE::OpenCoreAudio - RAW passthrough enabled");
224 m_transcode = forceTranscode;
227 CLog::Log(LOGINFO, "CCoreAudioAE::OpenCoreAudio - transcode to ac3 enabled");
229 std::string m_outputDevice = CSettings::Get().GetString("audiooutput.audiodevice");
231 // on iOS devices we set fixed to two channels.
232 m_stdChLayout = AE_CH_LAYOUT_2_0;
233 #if defined(TARGET_DARWIN_OSX)
234 switch (CSettings::Get().GetInt("audiooutput.channels"))
237 case 0: m_stdChLayout = AE_CH_LAYOUT_2_0; break; /* do not allow 1_0 output */
238 case 1: m_stdChLayout = AE_CH_LAYOUT_2_0; break;
239 case 2: m_stdChLayout = AE_CH_LAYOUT_2_1; break;
240 case 3: m_stdChLayout = AE_CH_LAYOUT_3_0; break;
241 case 4: m_stdChLayout = AE_CH_LAYOUT_3_1; break;
242 case 5: m_stdChLayout = AE_CH_LAYOUT_4_0; break;
243 case 6: m_stdChLayout = AE_CH_LAYOUT_4_1; break;
244 case 7: m_stdChLayout = AE_CH_LAYOUT_5_0; break;
245 case 8: m_stdChLayout = AE_CH_LAYOUT_5_1; break;
246 case 9: m_stdChLayout = AE_CH_LAYOUT_7_0; break;
247 case 10: m_stdChLayout = AE_CH_LAYOUT_7_1; break;
251 // setup the desired format
252 m_format.m_channelLayout = CAEChannelInfo(m_stdChLayout);
254 // if there is an audio resample rate set, use it.
255 if (CSettings::Get().GetInt("audiooutput.config") == AE_CONFIG_FIXED && !m_rawPassthrough)
257 sampleRate = CSettings::Get().GetInt("audiooutput.samplerate");
258 CLog::Log(LOGINFO, "CCoreAudioAE::passthrough - Forcing samplerate to %d", sampleRate);
261 if (m_rawPassthrough && !m_transcode)
263 switch (rawDataFormat)
267 m_format.m_channelLayout = CAEChannelInfo(AE_CH_LAYOUT_2_0);
268 m_format.m_sampleRate = 48000;
269 m_format.m_dataFormat = AE_FMT_S16NE;
272 m_format.m_channelLayout = CAEChannelInfo(AE_CH_LAYOUT_2_0);
273 m_format.m_sampleRate = 192000;
274 m_format.m_dataFormat = AE_FMT_S16NE;
278 m_format.m_channelLayout = CAEChannelInfo(AE_CH_LAYOUT_7_1);
279 m_format.m_sampleRate = 192000;
280 m_format.m_dataFormat = AE_FMT_S16NE;
283 // audio midi setup can be setup to 2.0 or 7.1
284 // if we have the number of max channels from streams we use that for
285 // selecting either 2.0 or 7.1 setup depending on that.
286 // This allows DPII modes on amps for enhancing stereo sound
287 // (when switching to 7.1 - all 8 channels will be pushed out preventing most amps
288 // to switch to DPII mode)
289 if (maxChannelCountInStreams == 1 || maxChannelCountInStreams == 2)
290 m_format.m_channelLayout = CAEChannelInfo(AE_CH_LAYOUT_2_0);
292 m_format.m_channelLayout = CAEChannelInfo(AE_CH_LAYOUT_7_1);
293 m_format.m_sampleRate = sampleRate;
294 m_format.m_dataFormat = AE_FMT_FLOAT;
300 else if (m_transcode)
302 // transcode is to ac3 only, do we copy the ac3 settings from above
303 m_format.m_channelLayout = CAEChannelInfo(AE_CH_LAYOUT_2_0);
304 m_format.m_sampleRate = 48000;
305 m_format.m_dataFormat = AE_FMT_S16NE;
309 m_format.m_sampleRate = sampleRate;
310 m_format.m_channelLayout = CAEChannelInfo(m_stdChLayout);
311 m_format.m_dataFormat = AE_FMT_FLOAT;
314 m_format.m_encodedRate = 0;
316 if (m_outputDevice.empty())
317 m_outputDevice = "default";
319 AEAudioFormat initformat = m_format;
321 // initialize audio hardware
322 m_Initialized = HAL->Initialize(this, m_rawPassthrough || m_transcode, initformat, m_transcode ? AE_FMT_AC3 : rawDataFormat, m_outputDevice, m_volume);
324 unsigned int bps = CAEUtil::DataFormatToBits(m_format.m_dataFormat);
325 m_chLayoutCount = m_format.m_channelLayout.Count();
326 m_format.m_frameSize = (bps>>3) * m_chLayoutCount; //initformat.m_frameSize;
327 //m_format.m_frames = (unsigned int)(((float)m_format.m_sampleRate / 1000.0f) * (float)DELAY_FRAME_TIME);
328 //m_format.m_frameSamples = m_format.m_frames * m_format.m_channelLayout.Count();
330 if ((initformat.m_channelLayout.Count() != m_chLayoutCount) && !m_rawPassthrough && !m_transcode)
332 /* readjust parameters. hardware didn't accept channel count*/
333 CLog::Log(LOGINFO, "CCoreAudioAE::Initialize: Setup channels (%d) greater than possible hardware channels (%d).",
334 m_chLayoutCount, initformat.m_channelLayout.Count());
336 m_format.m_channelLayout = CAEChannelInfo(initformat.m_channelLayout);
337 m_chLayoutCount = m_format.m_channelLayout.Count();
338 m_format.m_frameSize = (bps>>3) * m_chLayoutCount; //initformat.m_frameSize;
339 //m_format.m_frameSamples = m_format.m_frames * m_format.m_channelLayout.Count();
342 CLog::Log(LOGINFO, "CCoreAudioAE::Initialize:");
343 CLog::Log(LOGINFO, " Output Device : %s", m_outputDevice.c_str());
344 CLog::Log(LOGINFO, " Sample Rate : %d", m_format.m_sampleRate);
345 CLog::Log(LOGINFO, " Sample Format : %s", CAEUtil::DataFormatToStr(m_format.m_dataFormat));
346 CLog::Log(LOGINFO, " Channel Count : %d", m_chLayoutCount);
347 CLog::Log(LOGINFO, " Channel Layout: %s", ((std::string)m_format.m_channelLayout).c_str());
348 CLog::Log(LOGINFO, " Frame Size : %d", m_format.m_frameSize);
349 CLog::Log(LOGINFO, " Volume Level : %f", m_volume);
350 CLog::Log(LOGINFO, " Passthrough : %d", m_rawPassthrough);
351 CLog::Log(LOGINFO, " Transcode : %d", m_transcode);
353 CSingleLock soundLock(m_soundLock);
356 // re-init sounds and unlock
357 for (SoundList::iterator itt = m_sounds.begin(); itt != m_sounds.end(); ++itt)
358 (*itt)->Initialize();
362 // if we are not in m_rawPassthrough reinit the streams
363 if (!m_rawPassthrough)
365 /* re-init streams */
367 for (StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
368 (*itt)->Initialize();
372 return m_Initialized;
375 void CCoreAudioAE::Deinitialize()
380 // close all open converters
381 CSingleLock streamLock(m_streamLock);
382 for (StreamList::iterator itt = m_streams.begin(); itt != m_streams.end();++itt)
383 (*itt)->CloseConverter();
386 m_Initialized = false;
388 CSingleLock callbackLock(m_callbackLock);
391 while(m_callbackRunning)
398 void CCoreAudioAE::OnSettingsChange(const std::string& setting)
400 if (setting == "audiooutput.dontnormalizelevels")
402 // re-init streams remapper
403 CSingleLock streamLock(m_streamLock);
404 for (StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
405 (*itt)->InitializeRemap();
409 if (setting == "audiooutput.passthroughdevice" ||
410 setting == "audiooutput.custompassthrough" ||
411 setting == "audiooutput.audiodevice" ||
412 setting == "audiooutput.customdevice" ||
413 setting == "audiooutput.ac3passthrough" ||
414 setting == "audiooutput.eac3passthrough" ||
415 setting == "audiooutput.dtspassthrough" ||
416 setting == "audiooutput.channels" ||
417 setting == "audiooutput.samplerate" ||
418 setting == "audiooutput.config" ||
419 setting == "audiooutput.passthrough" )
421 // only reinit the engine if we not
422 // suspended (resume will initialize
423 // us again in that case)
429 unsigned int CCoreAudioAE::GetSampleRate()
431 return m_format.m_sampleRate;
434 unsigned int CCoreAudioAE::GetEncodedSampleRate()
436 return m_format.m_encodedRate;
439 CAEChannelInfo CCoreAudioAE::GetChannelLayout()
441 return m_format.m_channelLayout;
444 unsigned int CCoreAudioAE::GetChannelCount()
446 return m_chLayoutCount;
449 enum AEDataFormat CCoreAudioAE::GetDataFormat()
451 return m_format.m_dataFormat;
454 AEAudioFormat CCoreAudioAE::GetAudioFormat()
459 double CCoreAudioAE::GetDelay()
461 return HAL->GetDelay();
464 float CCoreAudioAE::GetVolume()
469 void CCoreAudioAE::SetVolume(float volume)
471 if (m_rawPassthrough)
475 // track volume if we are not muted
476 // we need this because m_volume is init'ed via
477 // SetVolume and need to also init m_volumeBeforeMute.
479 m_volumeBeforeMute = volume;
481 HAL->SetVolume(m_volume);
484 void CCoreAudioAE::SetMute(const bool enabled)
489 m_volumeBeforeMute = m_volume;
490 SetVolume(VOLUME_MINIMUM);
494 SetVolume(m_volumeBeforeMute);
498 bool CCoreAudioAE::IsMuted()
503 bool CCoreAudioAE::IsSuspended()
505 return m_isSuspended;
508 void CCoreAudioAE::SetSoundMode(const int mode)
512 /* stop all currently playing sounds if they are being turned off */
513 if (mode == AE_SOUND_OFF || (mode == AE_SOUND_IDLE && m_streamsPlaying))
517 bool CCoreAudioAE::SupportsRaw(AEDataFormat format)
531 bool CCoreAudioAE::IsSettingVisible(const std::string &settingId)
533 if (settingId == "audiooutput.samplerate")
535 if (CSettings::Get().GetInt("audiooutput.config") == AE_CONFIG_FIXED)
540 else if (settingId == "audiooutput.stereoupmix")
542 if (CSettings::Get().GetInt("audiooutput.channels") > AE_CH_LAYOUT_2_0)
549 CCoreAudioAEHAL* CCoreAudioAE::GetHAL()
554 IAEStream* CCoreAudioAE::MakeStream(enum AEDataFormat dataFormat,
555 unsigned int sampleRate, unsigned int encodedSamplerate, CAEChannelInfo channelLayout, unsigned int options)
557 // if we are suspended we don't
558 // want anyone to mess with us
559 if (m_isSuspended && !m_softSuspend)
560 #if defined(TARGET_DARWIN_IOS) && !defined(TARGET_DARWIN_IOS_ATV)
566 CAEChannelInfo channelInfo(channelLayout);
567 CLog::Log(LOGINFO, "CCoreAudioAE::MakeStream - %s, %u, %u, %s",
568 CAEUtil::DataFormatToStr(dataFormat), sampleRate, encodedSamplerate, ((std::string)channelInfo).c_str());
570 bool multichannelpcm = CSettings::Get().GetInt("audiooutput.channels") > AE_CH_LAYOUT_2_0; //if more then 2 channels are set - assume lpcm capability
571 #if defined(TARGET_DARWIN_IOS)
572 multichannelpcm = false;
574 // determine if we need to transcode this audio
575 // when we're called, we'll either get the audio in an encoded form (COREAUDIO_IS_RAW==true)
576 // that we can passthrough based on user options, or we'll get it unencoded
577 // if it's unencoded, and is 5.1, we'll transcode it to AC3 if possible
578 bool transcode = CSettings::Get().GetBool("audiooutput.passthrough") && CSettings::Get().GetBool("audiooutput.ac3passthrough") && !multichannelpcm &&
579 !COREAUDIO_IS_RAW(dataFormat) &&
580 (channelInfo.Count() == 6);
582 CCoreAudioAEStream *stream = new CCoreAudioAEStream(dataFormat, sampleRate, encodedSamplerate, channelLayout, options, transcode);
583 CSingleLock streamLock(m_streamLock);
584 m_streams.push_back(stream);
587 if ((options & AESTREAM_PAUSED) == 0)
590 // reinit the engine if pcm format changes or always on raw format or always on transcode
591 if (m_Initialized && ( m_lastStreamFormat != dataFormat ||
592 m_lastChLayoutCount != channelLayout.Count() ||
593 m_lastSampleRate != sampleRate ||
594 COREAUDIO_IS_RAW(dataFormat) ||
597 CSingleLock engineLock(m_engineLock);
600 m_Initialized = OpenCoreAudio(sampleRate, COREAUDIO_IS_RAW(dataFormat), dataFormat, transcode);
601 m_lastStreamFormat = dataFormat;
602 m_lastChLayoutCount = channelLayout.Count();
603 m_lastSampleRate = sampleRate;
606 /* if the stream was not initialized, do it now */
607 if (!stream->IsValid())
608 stream->Initialize();
610 if ((options & AESTREAM_PAUSED) == 0)
613 m_streamsPlaying = true;
618 IAEStream* CCoreAudioAE::FreeStream(IAEStream *stream)
620 CSingleLock streamLock(m_streamLock);
621 /* ensure the stream still exists */
622 for (StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); )
624 CCoreAudioAEStream *del = *itt;
627 itt = m_streams.erase(itt);
628 delete (CCoreAudioAEStream *)stream;
630 else if (del->IsDestroyed())
632 itt = m_streams.erase(itt);
641 m_streamsPlaying = !m_streams.empty();
645 // When we have been in passthrough mode and are not suspended,
646 // reinit the hardware to come back to anlog out
647 if (/*m_streams.empty() || */ m_rawPassthrough && !m_isSuspended)
649 CLog::Log(LOGINFO, "CCoreAudioAE::FreeStream Reinit, no streams left" );
656 void CCoreAudioAE::PlaySound(IAESound *sound)
658 if (m_soundMode == AE_SOUND_OFF || (m_soundMode == AE_SOUND_IDLE && m_streamsPlaying) || (m_isSuspended && !m_softSuspend))
661 float *samples = ((CCoreAudioAESound*)sound)->GetSamples();
662 if (!samples && !m_Initialized)
665 /* add the sound to the play list */
666 CSingleLock soundSampleLock(m_soundSampleLock);
668 ((CCoreAudioAESound*)sound),
670 ((CCoreAudioAESound*)sound)->GetSampleCount()
672 m_playing_sounds.push_back(ss);
675 void CCoreAudioAE::StopSound(IAESound *sound)
677 CSingleLock lock(m_soundSampleLock);
678 for (SoundStateList::iterator itt = m_playing_sounds.begin(); itt != m_playing_sounds.end(); )
680 if ((*itt).owner == sound)
682 (*itt).owner->ReleaseSamples();
683 itt = m_playing_sounds.erase(itt);
690 IAESound *CCoreAudioAE::MakeSound(const std::string& file)
692 // we don't make sounds
697 CSingleLock soundLock(m_soundLock);
699 // first check if we have the file cached
700 for (SoundList::iterator itt = m_sounds.begin(); itt != m_sounds.end(); ++itt)
702 if ((*itt)->GetFileName() == file)
706 CCoreAudioAESound *sound = new CCoreAudioAESound(file);
707 if (!sound->Initialize())
713 m_sounds.push_back(sound);
717 void CCoreAudioAE::FreeSound(IAESound *sound)
723 CSingleLock soundLock(m_soundLock);
724 for (SoundList::iterator itt = m_sounds.begin(); itt != m_sounds.end(); ++itt)
731 delete (CCoreAudioAESound*)sound;
734 void CCoreAudioAE::StopAllSounds()
736 CSingleLock lock(m_soundSampleLock);
737 while (!m_playing_sounds.empty())
739 SoundState *ss = &(*m_playing_sounds.begin());
740 m_playing_sounds.pop_front();
741 ss->owner->ReleaseSamples();
745 void CCoreAudioAE::MixSounds(float *buffer, unsigned int samples)
750 SoundStateList::iterator itt;
752 CSingleLock lock(m_soundSampleLock);
753 for (itt = m_playing_sounds.begin(); itt != m_playing_sounds.end(); )
755 SoundState *ss = &(*itt);
757 // no more frames, so remove it from the list
758 if (ss->sampleCount == 0)
760 ss->owner->ReleaseSamples();
761 itt = m_playing_sounds.erase(itt);
765 unsigned int mixSamples = std::min(ss->sampleCount, samples);
766 float volume = ss->owner->GetVolume();
768 for (unsigned int i = 0; i < mixSamples; ++i)
769 buffer[i] = (buffer[i] + (ss->samples[i] * volume));
771 ss->sampleCount -= mixSamples;
772 ss->samples += mixSamples;
778 void CCoreAudioAE::GarbageCollect()
780 #if defined(TARGET_DARWIN_OSX)
781 if (CSettings::Get().GetInt("audiooutput.streamsilence") != 0)
784 if (!m_streamsPlaying && m_playing_sounds.empty())
788 m_softSuspend = true;
789 m_softSuspendTimer = XbmcThreads::SystemClockMillis() + 10000; //10.0 second delay for softSuspend
796 CSingleLock engineLock(m_engineLock);
797 CLog::Log(LOGDEBUG, "CCoreAudioAE::GarbageCollect - Acquire CA HAL.");
799 m_isSuspended = false;
801 m_softSuspend = false;
804 unsigned int curSystemClock = XbmcThreads::SystemClockMillis();
805 if (!m_isSuspended && m_softSuspend && curSystemClock > m_softSuspendTimer)
807 Suspend();// locks m_engineLock internally
808 CLog::Log(LOGDEBUG, "CCoreAudioAE::GarbageCollect - Release CA HAL.");
810 #endif // TARGET_DARWIN_OSX
813 void CCoreAudioAE::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough)
815 if (m_isSuspended && !m_softSuspend)
818 HAL->EnumerateOutputDevices(devices, passthrough);
821 void CCoreAudioAE::Start()
829 void CCoreAudioAE::Stop()
837 bool CCoreAudioAE::Suspend()
839 CSingleLock engineLock(m_engineLock);
840 CLog::Log(LOGDEBUG, "CCoreAudioAE::Suspend - Suspending AE processing");
841 m_isSuspended = true;
842 // stop all gui sounds
844 // stop the CA thread
850 bool CCoreAudioAE::Resume()
852 // fire up the engine again
853 bool ret = Initialize();
854 CLog::Log(LOGDEBUG, "CCoreAudioAE::Resume - Resuming AE processing");
855 m_isSuspended = false;
860 //***********************************************************************************************
862 //***********************************************************************************************
863 OSStatus CCoreAudioAE::OnRender(AudioUnitRenderActionFlags *actionFlags,
864 const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
866 UInt32 frames = inNumberFrames;
868 unsigned int rSamples = frames * m_chLayoutCount;
869 int size = frames * m_format.m_frameSize;
870 //int size = frames * HAL->m_BytesPerFrame;
872 for (UInt32 i = 0; i < ioData->mNumberBuffers; i++)
873 bzero(ioData->mBuffers[i].mData, ioData->mBuffers[i].mDataByteSize);
877 m_callbackRunning = false;
881 CSingleLock callbackLock(m_callbackLock);
883 m_callbackRunning = true;
886 CSingleLock streamLock(m_streamLock);
887 // Remove any destroyed stream
888 if (!m_streams.empty())
890 for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end();)
892 CCoreAudioAEStream *stream = *itt;
894 if (stream->IsDestroyed())
896 itt = m_streams.erase(itt);
906 // when not in passthrough output mix sounds
907 if (!m_rawPassthrough && m_soundMode != AE_SOUND_OFF)
909 MixSounds((float *)ioData->mBuffers[0].mData, rSamples);
910 ioData->mBuffers[0].mDataByteSize = size;
911 if (!size && actionFlags)
912 *actionFlags |= kAudioUnitRenderAction_OutputIsSilence;
915 m_callbackRunning = false;
920 // Static Callback from AudioUnit
921 OSStatus CCoreAudioAE::Render(AudioUnitRenderActionFlags* actionFlags,
922 const AudioTimeStamp* pTimeStamp, UInt32 busNumber, UInt32 frameCount, AudioBufferList* pBufList)
924 OSStatus ret = OnRender(actionFlags, pTimeStamp, busNumber, frameCount, pBufList);