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 "threads/SingleLock.h"
23 #include "utils/log.h"
24 #include "utils/MathUtils.h"
26 #include "cores/AudioEngine/AEFactory.h"
27 #include "cores/AudioEngine/Utils/AEUtil.h"
30 #include "ActiveAEStream.h"
32 using namespace ActiveAE;
34 /* typecast AE to CActiveAE */
35 #define AE (*((CActiveAE*)CAEFactory::GetEngine()))
38 CActiveAEStream::CActiveAEStream(AEAudioFormat *format)
42 m_currentBuffer = NULL;
48 m_streamSpace = m_format.m_frameSize * m_format.m_frames;
49 m_streamDraining = false;
50 m_streamDrained = false;
51 m_streamFading = false;
52 m_streamFreeBuffers = 0;
53 m_streamIsBuffering = true;
56 m_leftoverBuffer = new uint8_t[m_format.m_frameSize];
58 m_forceResampler = false;
61 m_streamResampleRatio = 1.0;
64 CActiveAEStream::~CActiveAEStream()
66 delete [] m_leftoverBuffer;
71 void CActiveAEStream::IncFreeBuffers()
73 CSingleLock lock(m_streamLock);
74 m_streamFreeBuffers++;
77 void CActiveAEStream::DecFreeBuffers()
79 CSingleLock lock(m_streamLock);
80 m_streamFreeBuffers--;
83 void CActiveAEStream::ResetFreeBuffers()
85 CSingleLock lock(m_streamLock);
86 m_streamFreeBuffers = 0;
89 void CActiveAEStream::InitRemapper()
91 // check if input format follows ffmpeg channel mask
92 bool needRemap = false;
93 unsigned int avLast, avCur = 0;
94 for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
97 avCur = CActiveAEResample::GetAVChannel(m_format.m_channelLayout[i]);
107 CLog::Log(LOGDEBUG, "CActiveAEStream::%s - initialize remapper", __FUNCTION__);
109 m_remapper = new CActiveAEResample();
110 uint64_t avLayout = CActiveAEResample::GetAVChannelLayout(m_format.m_channelLayout);
112 // build layout according to ffmpeg channel order
113 // we need this for reference
114 CAEChannelInfo ffmpegLayout;
115 ffmpegLayout.Reset();
117 for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
119 for(unsigned int j=0; j<m_format.m_channelLayout.Count(); j++)
121 idx = m_remapper->GetAVChannelIndex(m_format.m_channelLayout[j], avLayout);
124 ffmpegLayout += m_format.m_channelLayout[j];
130 // build remap layout we can pass to resampler as destination layout
131 CAEChannelInfo remapLayout;
133 for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
135 for(unsigned int j=0; j<m_format.m_channelLayout.Count(); j++)
137 idx = m_remapper->GetAVChannelIndex(m_format.m_channelLayout[j], avLayout);
140 remapLayout += ffmpegLayout[j];
146 // initialize resampler for only doing remapping
147 m_remapper->Init(avLayout,
148 m_format.m_channelLayout.Count(),
149 m_format.m_sampleRate,
150 CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
151 CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
153 m_format.m_channelLayout.Count(),
154 m_format.m_sampleRate,
155 CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
156 CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
160 AE_QUALITY_LOW); // not used for remapping
162 // extra sound packet, we can't resample to the same buffer
163 m_remapBuffer = new CSoundPacket(m_inputBuffers->m_allSamples[0]->pkt->config, m_inputBuffers->m_allSamples[0]->pkt->max_nb_samples);
167 void CActiveAEStream::RemapBuffer()
171 int samples = m_remapper->Resample(m_remapBuffer->data, m_remapBuffer->max_nb_samples,
172 m_currentBuffer->pkt->data, m_currentBuffer->pkt->nb_samples,
175 if (samples != m_currentBuffer->pkt->nb_samples)
177 CLog::Log(LOGERROR, "CActiveAEStream::%s - error remapping", __FUNCTION__);
180 // swap sound packets
181 CSoundPacket *tmp = m_remapBuffer;
182 tmp = m_currentBuffer->pkt;
183 m_currentBuffer->pkt = m_remapBuffer;
188 unsigned int CActiveAEStream::GetSpace()
190 CSingleLock lock(m_streamLock);
191 return m_streamFreeBuffers * m_streamSpace;
194 unsigned int CActiveAEStream::AddData(void *data, unsigned int size)
197 unsigned int copied = 0;
198 unsigned int bytesToCopy = size;
199 uint8_t *buf = (uint8_t*)data;
203 buf = ((uint8_t*)data) + copied;
204 bytesToCopy = size - copied;
208 // fill leftover buffer and copy it first
209 if (m_leftoverBytes && bytesToCopy >= (m_format.m_frameSize - m_leftoverBytes))
211 int fillbytes = m_format.m_frameSize - m_leftoverBytes;
212 memcpy(m_leftoverBuffer+m_leftoverBytes, buf, fillbytes);
214 // leftover buffer will be copied on next cycle
215 buf = m_leftoverBuffer;
216 bytesToCopy = m_format.m_frameSize;
220 int start = m_currentBuffer->pkt->nb_samples *
221 m_currentBuffer->pkt->bytes_per_sample *
222 m_currentBuffer->pkt->config.channels /
223 m_currentBuffer->pkt->planes;
225 int freeSamples = m_currentBuffer->pkt->max_nb_samples - m_currentBuffer->pkt->nb_samples;
226 int availableSamples = bytesToCopy / m_format.m_frameSize;
228 // if we don't have a full frame, copy to leftover buffer
229 if (!availableSamples && bytesToCopy)
231 memcpy(m_leftoverBuffer+m_leftoverBytes, buf, bytesToCopy);
232 m_leftoverBytes = bytesToCopy;
233 copied += bytesToCopy;
236 int samples = std::min(freeSamples, availableSamples);
237 int bytes = samples * m_format.m_frameSize;
239 //TODO: handle planar formats
241 m_convertFn(buf, samples*m_currentBuffer->pkt->config.channels, (float*)(m_currentBuffer->pkt->data[0] + start));
243 memcpy(m_currentBuffer->pkt->data[0] + start, buf, bytes);
245 CSingleLock lock(*m_statsLock);
246 m_currentBuffer->pkt->nb_samples += samples;
247 m_bufferedTime += (double)samples / m_currentBuffer->pkt->config.sample_rate;
249 if (buf != m_leftoverBuffer)
251 if (m_currentBuffer->pkt->nb_samples == m_currentBuffer->pkt->max_nb_samples)
253 MsgStreamSample msgData;
254 msgData.buffer = m_currentBuffer;
255 msgData.stream = this;
257 m_streamPort->SendOutMessage(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
258 m_currentBuffer = NULL;
262 else if (m_streamPort->ReceiveInMessage(&msg))
264 if (msg->signal == CActiveAEDataProtocol::STREAMBUFFER)
266 m_currentBuffer = *((CSampleBuffer**)msg->data);
273 CLog::Log(LOGERROR, "CActiveAEStream::AddData - unknown signal");
278 if (!m_inMsgEvent.WaitMSec(200))
284 double CActiveAEStream::GetDelay()
286 return AE.GetDelay(this);
289 bool CActiveAEStream::IsBuffering()
291 CSingleLock lock(m_streamLock);
292 return m_streamIsBuffering;
295 double CActiveAEStream::GetCacheTime()
297 return AE.GetCacheTime(this);
300 double CActiveAEStream::GetCacheTotal()
302 return AE.GetCacheTotal(this);
305 void CActiveAEStream::Pause()
307 AE.PauseStream(this, true);
310 void CActiveAEStream::Resume()
312 AE.PauseStream(this, false);
315 void CActiveAEStream::Drain(bool wait)
318 CActiveAEStream *stream = this;
320 m_streamDraining = true;
321 m_streamDrained = false;
324 if (m_streamPort->SendOutMessageSync(CActiveAEDataProtocol::DRAINSTREAM,
326 &stream, sizeof(CActiveAEStream*)))
328 bool success = reply->signal == CActiveAEDataProtocol::ACC ? true : false;
332 CLog::Log(LOGERROR, "CActiveAEStream::Drain - no acc");
338 MsgStreamSample msgData;
339 msgData.buffer = m_currentBuffer;
340 msgData.stream = this;
342 m_streamPort->SendOutMessage(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
343 m_currentBuffer = NULL;
346 XbmcThreads::EndTime timer(2000);
347 while (!timer.IsTimePast())
349 if (m_streamPort->ReceiveInMessage(&msg))
351 if (msg->signal == CActiveAEDataProtocol::STREAMBUFFER)
353 MsgStreamSample msgData;
354 msgData.stream = this;
355 msgData.buffer = *((CSampleBuffer**)msg->data);
356 msg->Reply(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
360 else if (msg->signal == CActiveAEDataProtocol::STREAMDRAINED)
369 m_inMsgEvent.WaitMSec(timer.MillisLeft());
371 CLog::Log(LOGERROR, "CActiveAEStream::Drain - timeout out");
374 bool CActiveAEStream::IsDraining()
376 CSingleLock lock(m_streamLock);
377 return m_streamDraining;
380 bool CActiveAEStream::IsDrained()
382 CSingleLock lock(m_streamLock);
383 return m_streamDrained;
386 void CActiveAEStream::Flush()
388 m_currentBuffer = NULL;
390 AE.FlushStream(this);
394 float CActiveAEStream::GetAmplification()
396 return m_streamAmplify;
399 void CActiveAEStream::SetAmplification(float amplify)
401 m_streamAmplify = amplify;
402 AE.SetStreamAmplification(this, m_streamAmplify);
405 float CActiveAEStream::GetReplayGain()
407 return m_streamRgain;
410 void CActiveAEStream::SetReplayGain(float factor)
412 m_streamRgain = std::max( 0.0f, factor);
413 AE.SetStreamReplaygain(this, m_streamRgain);
416 float CActiveAEStream::GetVolume()
418 return m_streamVolume;
421 void CActiveAEStream::SetVolume(float volume)
423 m_streamVolume = std::max( 0.0f, std::min(1.0f, volume));
424 AE.SetStreamVolume(this, m_streamVolume);
427 double CActiveAEStream::GetResampleRatio()
429 return m_streamResampleRatio;
432 bool CActiveAEStream::SetResampleRatio(double ratio)
434 m_streamResampleRatio = ratio;
435 AE.SetStreamResampleRatio(this, m_streamResampleRatio);
439 void CActiveAEStream::FadeVolume(float from, float target, unsigned int time)
441 if (time == 0 || AE_IS_RAW(m_format.m_dataFormat))
444 m_streamFading = true;
445 AE.SetStreamFade(this, from, target, time);
448 bool CActiveAEStream::IsFading()
450 CSingleLock lock(m_streamLock);
451 return m_streamFading;
454 const unsigned int CActiveAEStream::GetFrameSize() const
456 return m_format.m_frameSize;
459 const unsigned int CActiveAEStream::GetChannelCount() const
461 return m_format.m_channelLayout.Count();
464 const unsigned int CActiveAEStream::GetSampleRate() const
466 return m_format.m_sampleRate;
469 const unsigned int CActiveAEStream::GetEncodedSampleRate() const
471 return m_format.m_encodedRate;
474 const enum AEDataFormat CActiveAEStream::GetDataFormat() const
476 return m_format.m_dataFormat;
479 void CActiveAEStream::RegisterAudioCallback(IAudioCallback* pCallback)
483 void CActiveAEStream::UnRegisterAudioCallback()
487 void CActiveAEStream::RegisterSlave(IAEStream *slave)
489 CSingleLock lock(m_streamLock);
490 m_streamSlave = slave;