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"
24 #include "CoreAudioAEStream.h"
26 #include "xbmc/cores/AudioEngine/Interfaces/AE.h"
27 #include "xbmc/cores/AudioEngine/AEFactory.h"
28 #include "xbmc/cores/AudioEngine/Utils/AEUtil.h"
29 #include "xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.h"
30 #include "settings/Settings.h"
31 #include "threads/SingleLock.h"
32 #include "settings/AdvancedSettings.h"
33 #include "utils/MathUtils.h"
34 #include "utils/log.h"
38 // typecast AE to CCoreAudioAE
39 #define AE (*(CCoreAudioAE*)CAEFactory::GetEngine())
41 void CheckOutputBufferSize(void **buffer, int *oldSize, int newSize)
43 if (newSize > *oldSize)
46 _aligned_free(*buffer);
47 *buffer = _aligned_malloc(newSize, 16);
50 memset(*buffer, 0x0, *oldSize);
55 template <class AudioDataType>
56 static inline void _Upmix(AudioDataType *input,
57 unsigned int channelsInput, AudioDataType *output,
58 unsigned int channelsOutput, unsigned int frames)
60 unsigned int unused = channelsOutput - channelsInput;
61 AudioDataType *_input = input;
62 AudioDataType *_output = output;
64 for (unsigned int i = 0; i < frames; i++)
67 for(unsigned int j = 0; j < channelsInput; j++)
68 *_output++ = *_input++;
69 // set unused channels
70 for(unsigned int j = 0; j < unused; j++)
75 void CCoreAudioAEStream::Upmix(void *input,
76 unsigned int channelsInput, void *output,
77 unsigned int channelsOutput, unsigned int frames, AEDataFormat dataFormat)
79 // input channels must be less than output channels
80 if (channelsInput >= channelsOutput)
83 switch (CAEUtil::DataFormatToBits(dataFormat))
85 case 8: _Upmix ( (unsigned char *) input, channelsInput, (unsigned char *) output, channelsOutput, frames ); break;
86 case 16: _Upmix ( (short *) input, channelsInput, (short *) output, channelsOutput, frames ); break;
87 case 32: _Upmix ( (float *) input, channelsInput, (float *) output, channelsOutput, frames ); break;
88 default: _Upmix ( (int *) input, channelsInput, (int *) output, channelsOutput, frames ); break;
92 CCoreAudioAEStream::CCoreAudioAEStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSamplerate, CAEChannelInfo channelLayout, unsigned int options, bool transcode) :
101 m_convertBuffer (NULL ),
104 m_AvgBytesPerSec (0 ),
105 m_audioCallback (NULL ),
106 m_fadeRunning (false),
109 m_firstInput (true ),
110 m_flushRequested (false),
113 m_ssrcData.data_out = NULL;
114 m_transcode = transcode;
118 m_rawDataFormat = dataFormat;
119 m_StreamFormat.m_dataFormat = dataFormat;
120 m_StreamFormat.m_sampleRate = sampleRate;
121 m_StreamFormat.m_encodedRate = 0; //we don't support this
122 m_StreamFormat.m_channelLayout = channelLayout;
123 m_isRaw = COREAUDIO_IS_RAW(dataFormat);
127 m_rawDataFormat = AE_FMT_AC3;
128 m_StreamFormat.m_dataFormat = AE_FMT_AC3;
129 m_StreamFormat.m_sampleRate = 48000;
130 m_StreamFormat.m_encodedRate = 0;
131 enum AEChannel ac3Layout[3] = {AE_CH_RAW, AE_CH_RAW, AE_CH_NULL};
132 m_StreamFormat.m_channelLayout = ac3Layout;
135 // setup encoder format
136 m_encoderFormat.m_dataFormat = dataFormat;
137 m_encoderFormat.m_sampleRate = sampleRate;
138 m_encoderFormat.m_encodedRate = 0;
139 m_encoderFormat.m_channelLayout = channelLayout;
140 m_encoderFormat.m_frames = 0;
141 m_encoderFormat.m_frameSamples = 0;
142 m_encoderFormat.m_frameSize = 0;
145 m_incomingFormat = dataFormat;
146 m_chLayoutCountStream = m_StreamFormat.m_channelLayout.Count();
147 m_StreamFormat.m_frameSize = (CAEUtil::DataFormatToBits(m_rawDataFormat) >> 3) * m_chLayoutCountStream;
148 m_OutputFormat = AE.GetAudioFormat();
149 m_chLayoutCountOutput = m_OutputFormat.m_channelLayout.Count();
151 //m_forceResample = (options & AESTREAM_FORCE_RESAMPLE) != 0;
152 m_paused = (options & AESTREAM_PAUSED) != 0;
154 m_vizRemapBufferSize = m_remapBufferSize = /*m_resampleBufferSize = */ m_upmixBufferSize = m_convertBufferSize = 16*1024;
155 m_convertBuffer = (float *)_aligned_malloc(m_convertBufferSize,16);
156 //m_resampleBuffer = (float *)_aligned_malloc(m_resampleBufferSize,16);
157 m_upmixBuffer = (uint8_t *)_aligned_malloc(m_upmixBufferSize,16);
158 m_remapBuffer = (uint8_t *)_aligned_malloc(m_remapBufferSize,16);
159 m_vizRemapBuffer = (uint8_t *)_aligned_malloc(m_vizRemapBufferSize,16);
161 m_limiter.SetSamplerate(AE.GetSampleRate());
164 CCoreAudioAEStream::~CCoreAudioAEStream()
173 _aligned_free(m_convertBuffer); m_convertBuffer = NULL;
174 //_aligned_free(m_resampleBuffer); m_resampleBuffer = NULL;
175 _aligned_free(m_remapBuffer); m_remapBuffer = NULL;
176 _aligned_free(m_vizRemapBuffer); m_vizRemapBuffer = NULL;
177 _aligned_free(m_upmixBuffer); m_upmixBuffer = NULL;
179 delete m_Buffer; m_Buffer = NULL;
185 m_unencodedBuffer.DeAlloc();
190 _aligned_free(m_ssrcData.data_out);
196 CLog::Log(LOGDEBUG, "CCoreAudioAEStream::~CCoreAudioAEStream - Destructed");
199 void CCoreAudioAEStream::InitializeRemap()
203 if (m_OutputFormat.m_channelLayout != AE.GetChannelLayout())
205 m_OutputFormat = AE.GetAudioFormat();
206 m_chLayoutCountOutput = m_OutputFormat.m_channelLayout.Count();
207 m_OutputBytesPerSample = (CAEUtil::DataFormatToBits(m_OutputFormat.m_dataFormat) >> 3);
209 // re-init the remappers
210 m_remap .Initialize(m_StreamFormat.m_channelLayout, m_OutputFormat.m_channelLayout, false);
211 m_vizRemap.Initialize(m_StreamFormat.m_channelLayout, CAEChannelInfo(AE_CH_LAYOUT_2_0), false, true);
218 void CCoreAudioAEStream::ReinitConverter()
224 // The source logic is in the HAL. The only thing we have to do here
225 // is to allocate the convrter and set the direct input call.
226 void CCoreAudioAEStream::CloseConverter()
228 // we have a converter, delete it
230 m_outputUnit = (CAUOutputDevice *) AE.GetHAL()->DestroyUnit(m_outputUnit);
232 // it is save to unregister any direct input. the HAL takes care about it.
233 AE.GetHAL()->SetDirectInput(NULL, m_OutputFormat);
236 void CCoreAudioAEStream::OpenConverter()
238 // we always allocate a converter
239 // the HAL decides if we get converter.
240 // if there is already a converter delete it.
242 m_outputUnit = (CAUOutputDevice *) AE.GetHAL()->DestroyUnit(m_outputUnit);
244 AEAudioFormat format = m_OutputFormat;
246 format.m_sampleRate = m_StreamFormat.m_sampleRate;
247 m_outputUnit = (CAUOutputDevice *) AE.GetHAL()->CreateUnit(this, format);
249 // it is safe to register any direct input. the HAL takes care about it.
250 AE.GetHAL()->SetDirectInput(this, m_OutputFormat);
253 void CCoreAudioAEStream::Initialize()
258 m_OutputFormat = AE.GetAudioFormat();
259 m_chLayoutCountOutput = m_OutputFormat.m_channelLayout.Count();
261 if (m_rawDataFormat == AE_FMT_LPCM)
262 m_OutputBytesPerSample = (CAEUtil::DataFormatToBits(AE_FMT_FLOAT) >> 3);
264 m_OutputBytesPerSample = (CAEUtil::DataFormatToBits(m_OutputFormat.m_dataFormat) >> 3);
266 if (m_isRaw || m_transcode)
268 // we are raw or transcode, which means we need to work in the output format
269 if (m_rawDataFormat != AE_FMT_LPCM)
271 m_StreamFormat = AE.GetAudioFormat();
272 m_chLayoutCountStream = m_StreamFormat.m_channelLayout.Count();
274 m_StreamBytesPerSample = (CAEUtil::DataFormatToBits(m_StreamFormat.m_dataFormat) >> 3);
279 if (!m_chLayoutCountStream)
284 // Work around a bug in TrueHD and DTSHD deliver
285 if (m_StreamFormat.m_dataFormat == AE_FMT_TRUEHD || m_StreamFormat.m_dataFormat == AE_FMT_DTSHD)
286 m_StreamBytesPerSample = (CAEUtil::DataFormatToBits(AE_FMT_S16NE) >> 3);
288 m_StreamBytesPerSample = (CAEUtil::DataFormatToBits(m_StreamFormat.m_dataFormat) >> 3);
289 m_StreamFormat.m_frameSize = m_StreamBytesPerSample * m_chLayoutCountStream;
294 if (!m_remap.Initialize(m_StreamFormat.m_channelLayout, m_OutputFormat.m_channelLayout, false))
300 m_doRemap = m_chLayoutCountStream != 2;
302 if (!m_vizRemap.Initialize(m_OutputFormat.m_channelLayout, CAEChannelInfo(AE_CH_LAYOUT_2_0), false, true))
309 // only try to convert if we're not in AE_FMT_FLOAT and (we're not raw or we are transcoding)
311 (m_StreamFormat.m_dataFormat != AE_FMT_FLOAT && !m_isRaw)
313 (m_incomingFormat != AE_FMT_FLOAT && m_transcode);
316 //m_resample = false; //(m_StreamFormat.m_sampleRate != m_OutputFormat.m_sampleRate) && !m_isRaw;
318 // if we need to convert, set it up
321 // get the conversion function and allocate a buffer for the data
322 CLog::Log(LOGDEBUG, "CCoreAudioAEStream::CCoreAudioAEStream - Converting from %s to AE_FMT_FLOAT", CAEUtil::DataFormatToStr(m_StreamFormat.m_dataFormat));
325 m_convertFn = CAEConvert::ToFloat(m_StreamFormat.m_dataFormat);
327 m_convertFn = CAEConvert::ToFloat(m_incomingFormat);
333 // if we need to transcode, set it up
336 m_unencodedBuffer.Empty();
338 if (!m_encoder || !m_encoder->IsCompatible(m_encoderFormat))
342 // if we need to resample, set it up
347 m_ssrc = src_new(SRC_SINC_MEDIUM_QUALITY, m_chLayoutCountStream, &err);
348 m_ssrcData.src_ratio = (double)m_OutputFormat.m_sampleRate / (double)m_StreamFormat.m_sampleRate;
349 m_ssrcData.data_in = m_convertBuffer;
350 m_ssrcData.end_of_input = 0;
354 // m_AvgBytesPerSec is calculated based on the output format.
355 // we have to keep in mind that we convert our data to the output format
356 m_AvgBytesPerSec = m_OutputFormat.m_frameSize * m_OutputFormat.m_sampleRate;
359 m_Buffer = new AERingBuffer(m_AvgBytesPerSec);
361 m_fadeRunning = false;
368 void CCoreAudioAEStream::Destroy()
375 unsigned int CCoreAudioAEStream::AddData(void *data, unsigned int size)
377 unsigned int frames = size / m_StreamFormat.m_frameSize;
378 unsigned int samples = size / m_StreamBytesPerSample;
379 uint8_t *adddata = (uint8_t *)data;
380 unsigned int addsize = size;
381 unsigned int channelsInBuffer = m_chLayoutCountStream;
383 if (m_flushRequested && m_paused)
386 if (!m_valid || size == 0 || data == NULL || !m_Buffer || m_flushRequested)
389 // if the stream is draining
392 // if the stream has finished draining, cork it
393 if (m_Buffer && m_Buffer->GetReadSize() == 0)
399 // convert the data if we need to
402 CheckOutputBufferSize((void **)&m_convertBuffer, &m_convertBufferSize, frames * channelsInBuffer * m_OutputBytesPerSample);
404 samples = m_convertFn(adddata, size / m_StreamBytesPerSample, m_convertBuffer);
405 frames = samples / channelsInBuffer;
406 addsize = frames * channelsInBuffer * m_OutputBytesPerSample;
407 adddata = (uint8_t *)m_convertBuffer;
411 samples = size / m_StreamBytesPerSample;
412 adddata = (uint8_t *)data;
419 // transcode if we need to
420 if (m_transcode && m_encoder)
422 // put adddata in the unencodedBuffer
423 if (m_unencodedBuffer.Free() < addsize)
424 m_unencodedBuffer.ReAlloc(m_unencodedBuffer.Used() + addsize);
426 m_unencodedBuffer.Push(adddata, addsize);
428 unsigned int block = m_encoderFormat.m_frames * m_encoderFormat.m_frameSize;
430 // only try to encode if we have enough data
431 if (m_unencodedBuffer.Used() >= block)
433 frames = m_encoder->Encode((float *)m_unencodedBuffer.Raw(block), m_encoderFormat.m_frames);
434 m_unencodedBuffer.Shift(NULL, frames * m_encoderFormat.m_frameSize);
435 addsize = m_encoder->GetData(&adddata);
436 samples = addsize / m_OutputBytesPerSample;
439 // return size here or whoever calling us will block if we return 0
440 // we have essentially been successful, because we add the audio to our buffer to encode
448 // resample it if we need to
452 unsigned int resample_frames = samples / m_chLayoutCountStream;
454 CheckOutputBufferSize((void **)&m_resampleBuffer, &m_resampleBufferSize,
455 resample_frames * std::ceil(m_ssrcData.src_ratio) * sizeof(float) * 2);
457 m_ssrcData.input_frames = resample_frames;
458 m_ssrcData.output_frames = resample_frames * std::ceil(m_ssrcData.src_ratio);
459 m_ssrcData.data_in = (float *)adddata;
460 m_ssrcData.data_out = m_resampleBuffer;
462 if (src_process(m_ssrc, &m_ssrcData) != 0)
465 frames = m_ssrcData.output_frames_gen;
466 samples = frames * m_chLayoutCountStream;
467 adddata = (uint8_t *)m_ssrcData.data_out;
471 frames = samples / m_chLayoutCountStream;
472 samples = frames * m_chLayoutCountStream;
478 addsize = frames * m_OutputBytesPerSample * m_chLayoutCountOutput;
479 CheckOutputBufferSize((void **)&m_remapBuffer, &m_remapBufferSize, addsize);
481 // downmix/remap the data
482 m_remap.Remap((float *)adddata, (float *)m_remapBuffer, frames);
483 adddata = (uint8_t *)m_remapBuffer;
484 channelsInBuffer = m_OutputFormat.m_channelLayout.Count();
487 // upmix the ouput to output channels
488 if ( (!m_isRaw || m_rawDataFormat == AE_FMT_LPCM) && (m_chLayoutCountOutput > channelsInBuffer) )
490 CheckOutputBufferSize((void **)&m_upmixBuffer, &m_upmixBufferSize, frames * m_chLayoutCountOutput * sizeof(float));
491 Upmix(adddata, channelsInBuffer, m_upmixBuffer, m_chLayoutCountOutput, frames, m_OutputFormat.m_dataFormat);
492 adddata = m_upmixBuffer;
493 addsize = frames * m_chLayoutCountOutput * sizeof(float);
496 unsigned int total_ms_sleep = 0;
497 unsigned int room = m_Buffer->GetWriteSize();
498 while (addsize > room && !m_paused && total_ms_sleep < 100)
501 if (!m_valid || !m_Buffer || m_draining )
504 unsigned int ms_sleep_time = (1000 * room) / m_AvgBytesPerSec;
505 if (ms_sleep_time == 0)
508 // sleep until we have space (estimated) or 1ms min
509 Sleep(ms_sleep_time);
510 total_ms_sleep += ms_sleep_time;
512 room = m_Buffer->GetWriteSize();
518 m_Buffer->Write(adddata, addsize);
520 // still only return size to indicate success
521 // we likely wrote something !size to m_Buffer, but our called doesn't realy care
525 // this is only called on the context of the coreaudio thread!
526 unsigned int CCoreAudioAEStream::GetFrames(uint8_t *buffer, unsigned int size)
528 // if we have been deleted
529 if (!m_valid || m_delete || !m_Buffer || m_paused)
532 if (m_flushRequested)
538 unsigned int readsize = std::min(m_Buffer->GetReadSize(), size);
539 m_Buffer->Read(buffer, readsize);
543 float *floatBuffer = (float *)buffer;
544 unsigned int samples = readsize / m_OutputBytesPerSample;
545 unsigned int frames = samples / m_chLayoutCountOutput;
547 // we have a frame, if we have a viz we need to hand the data to it.
548 // Keep in mind that our buffer is already in output format.
549 // So we remap output format to viz format !!!
550 if (m_OutputFormat.m_dataFormat == AE_FMT_FLOAT)
552 // TODO : Why the hell is vizdata limited ?
553 unsigned int samplesClamped = (samples > 512) ? 512 : samples;
556 // Viz channel count is 2
557 CheckOutputBufferSize((void **)&m_vizRemapBuffer, &m_vizRemapBufferSize, frames * 2 * sizeof(float));
559 m_vizRemap.Remap(floatBuffer, (float*)m_vizRemapBuffer, frames);
561 m_audioCallback->OnAudioData((float *)m_vizRemapBuffer, samplesClamped);
568 // TODO: check if we correctly respect the amount of our blockoperation
569 m_volume += (m_fadeStep * ((float)readsize / (float)m_OutputFormat.m_frameSize));
570 m_volume = std::min(1.0f, std::max(0.0f, m_volume));
573 if (m_volume >= m_fadeTarget)
574 m_fadeRunning = false;
578 if (m_volume <= m_fadeTarget)
579 m_fadeRunning = false;
586 CAEUtil::SSEMulArray(floatBuffer, m_volume, samples);
588 for(unsigned int i = 0; i < samples; i++)
589 floatBuffer[i] *= m_volume;
591 CAEUtil::ClampArray(floatBuffer, samples);
593 // apply volume amplification by using the sogt limiter
594 // TODO - maybe reinvent the coreaudio compressor for this after frodo
595 else if (GetAmplification() != 1.0f)
597 for(unsigned int i = 0; i < frames; i++)
599 int frameIdx = i*m_chLayoutCountOutput;
600 float amplification = RunLimiter(&floatBuffer[frameIdx], m_chLayoutCountOutput);
601 float *frameStart = &floatBuffer[frameIdx];
603 CAEUtil::SSEMulArray(frameStart, amplification, m_chLayoutCountOutput);
605 for(unsigned int n = 0; n < m_chLayoutCountOutput; n++)
606 frameStart[n] *= amplification;
616 const unsigned int CCoreAudioAEStream::GetFrameSize() const
618 return m_OutputFormat.m_frameSize;
621 unsigned int CCoreAudioAEStream::GetSpace()
623 if (!m_valid || m_draining)
626 return m_Buffer->GetWriteSize() / m_OutputBytesPerSample * m_StreamBytesPerSample;
629 double CCoreAudioAEStream::GetDelay()
631 if (m_delete || !m_Buffer || m_flushRequested)
634 double delayBuffer = (double)(m_Buffer->GetReadSize()) / (double)m_AvgBytesPerSec;
635 double delayTranscoder = 0.0;
638 delayTranscoder = (double)(m_unencodedBuffer.Used()) / (double)(m_encoderFormat.m_frameSize * m_encoderFormat.m_sampleRate);
640 return AE.GetDelay() + delayBuffer + delayTranscoder;
643 bool CCoreAudioAEStream::IsBuffering()
645 return (m_Buffer->GetReadSize() == 0 && m_unencodedBuffer.Used() == 0);
648 double CCoreAudioAEStream::GetCacheTime()
650 if (m_delete || !m_Buffer || m_flushRequested)
652 double delayBuffer = (double)(m_Buffer->GetReadSize()) / (double)m_AvgBytesPerSec;
653 double delayTranscoder = 0.0;
656 delayTranscoder = (double)(m_unencodedBuffer.Used()) / (double)(m_encoderFormat.m_frameSize * m_encoderFormat.m_sampleRate);
658 return AE.GetDelay() + delayBuffer + delayTranscoder;
661 double CCoreAudioAEStream::GetCacheTotal()
663 if (m_delete || !m_Buffer)
666 return (double)m_Buffer->GetMaxSize() / (double)m_AvgBytesPerSec;
670 bool CCoreAudioAEStream::IsPaused()
675 bool CCoreAudioAEStream::IsDraining()
680 bool CCoreAudioAEStream::IsDestroyed()
685 bool CCoreAudioAEStream::IsValid()
690 void CCoreAudioAEStream::Pause()
695 void CCoreAudioAEStream::Resume()
697 #if defined(TARGET_DARWIN_IOS) && !defined(TARGET_DARWIN_IOS_ATV)
698 if (CAEFactory::IsSuspended())
699 CAEFactory::Resume();
704 void CCoreAudioAEStream::Drain(bool wait)
709 bool CCoreAudioAEStream::IsDrained()
711 return m_Buffer->GetReadSize() == 0;
714 void CCoreAudioAEStream::Flush()
717 m_flushRequested = true;
720 float CCoreAudioAEStream::GetVolume()
725 float CCoreAudioAEStream::GetReplayGain()
730 void CCoreAudioAEStream::SetVolume(float volume)
732 m_volume = std::max( 0.0f, std::min(1.0f, volume));
735 void CCoreAudioAEStream::SetReplayGain(float factor)
737 m_rgain = std::max(-1.0f, std::max(1.0f, factor));
740 void CCoreAudioAEStream::InternalFlush()
742 // reset the resampler
745 m_ssrcData.end_of_input = 0;
750 // Read the buffer empty to avoid Reset
751 // Reset is not lock free.
754 unsigned int readsize = m_Buffer->GetReadSize();
757 uint8_t *buffer = (uint8_t *)_aligned_malloc(readsize, 16);
758 m_Buffer->Read(buffer, readsize);
759 _aligned_free(buffer);
762 // if we are draining and are out of packets, tell the slave to resume
763 if (m_draining && m_slave)
770 m_flushRequested = false;
772 // m_Buffer->Reset();
775 const unsigned int CCoreAudioAEStream::GetChannelCount() const
777 return m_chLayoutCountStream;
780 const unsigned int CCoreAudioAEStream::GetSampleRate() const
782 return m_StreamFormat.m_sampleRate;
785 const unsigned int CCoreAudioAEStream::GetEncodedSampleRate() const
787 return m_StreamFormat.m_encodedRate;
790 const enum AEDataFormat CCoreAudioAEStream::GetDataFormat() const
792 return m_StreamFormat.m_dataFormat;
795 const bool CCoreAudioAEStream::IsRaw() const
800 double CCoreAudioAEStream::GetResampleRatio()
806 double ret = m_ssrcData.src_ratio;
813 bool CCoreAudioAEStream::SetResampleRatio(double ratio)
820 src_set_ratio(m_ssrc, ratio);
821 m_ssrcData.src_ratio = ratio;
825 void CCoreAudioAEStream::RegisterAudioCallback(IAudioCallback* pCallback)
827 m_audioCallback = pCallback;
829 m_audioCallback->OnInitialize(2, m_StreamFormat.m_sampleRate, 32);
832 void CCoreAudioAEStream::UnRegisterAudioCallback()
834 m_audioCallback = NULL;
837 void CCoreAudioAEStream::FadeVolume(float from, float target, unsigned int time)
841 m_fadeRunning = false;
845 float delta = target - from;
846 m_fadeDirUp = target > from;
847 m_fadeTarget = target;
848 m_fadeStep = delta / (((float)m_OutputFormat.m_sampleRate / 1000.0f) * (float)time);
849 m_fadeRunning = true;
853 bool CCoreAudioAEStream::IsFading()
855 return m_fadeRunning;
858 void CCoreAudioAEStream::RegisterSlave(IAEStream *stream)
863 OSStatus CCoreAudioAEStream::Render(AudioUnitRenderActionFlags* actionFlags,
864 const AudioTimeStamp* pTimeStamp, UInt32 busNumber, UInt32 frameCount, AudioBufferList* pBufList)
866 OSStatus ret = OnRender(actionFlags, pTimeStamp, busNumber, frameCount, pBufList);
870 OSStatus CCoreAudioAEStream::OnRender(AudioUnitRenderActionFlags *ioActionFlags,
871 const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
873 // if we have no valid data output silence
874 if (!m_valid || m_delete || !m_Buffer || m_firstInput || m_paused)
876 for (UInt32 i = 0; i < ioData->mNumberBuffers; i++)
877 bzero(ioData->mBuffers[i].mData, ioData->mBuffers[i].mDataByteSize);
879 *ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence;
880 m_firstInput = false;
884 unsigned int size = inNumberFrames * m_OutputFormat.m_frameSize;
885 //unsigned int size = inNumberFrames * m_StreamFormat.m_frameSize;
887 // the index is important if we run encoded
888 unsigned int outputBufferIndex = AE.GetHAL()->GetBufferIndex();
890 ioData->mBuffers[outputBufferIndex].mDataByteSize = GetFrames(
891 (uint8_t*)ioData->mBuffers[outputBufferIndex].mData, size);
892 if (!ioData->mBuffers[outputBufferIndex].mDataByteSize && ioActionFlags)
893 *ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence;
898 void CCoreAudioAEStream::ResetEncoder()
902 m_unencodedBuffer.Empty();
905 bool CCoreAudioAEStream::SetupEncoder()
914 m_encoder = new CAEEncoderFFmpeg();
915 if (m_encoder && m_encoder->Initialize(m_encoderFormat))