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 "AEFactory.h"
27 #include "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;
63 CActiveAEStream::~CActiveAEStream()
65 delete [] m_leftoverBuffer;
70 void CActiveAEStream::IncFreeBuffers()
72 CSingleLock lock(m_streamLock);
73 m_streamFreeBuffers++;
76 void CActiveAEStream::DecFreeBuffers()
78 CSingleLock lock(m_streamLock);
79 m_streamFreeBuffers--;
82 void CActiveAEStream::ResetFreeBuffers()
84 CSingleLock lock(m_streamLock);
85 m_streamFreeBuffers = 0;
88 void CActiveAEStream::InitRemapper()
90 // check if input format follows ffmpeg channel mask
91 bool needRemap = false;
92 unsigned int avLast, avCur = 0;
93 for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
96 avCur = CActiveAEResample::GetAVChannel(m_format.m_channelLayout[i]);
106 CLog::Log(LOGDEBUG, "CActiveAEStream::%s - initialize remapper", __FUNCTION__);
108 m_remapper = new CActiveAEResample();
109 uint64_t avLayout = CActiveAEResample::GetAVChannelLayout(m_format.m_channelLayout);
111 // build layout according to ffmpeg channel order
112 // we need this for reference
113 CAEChannelInfo ffmpegLayout;
114 ffmpegLayout.Reset();
116 for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
118 for(unsigned int j=0; j<m_format.m_channelLayout.Count(); j++)
120 idx = m_remapper->GetAVChannelIndex(m_format.m_channelLayout[j], avLayout);
123 ffmpegLayout += m_format.m_channelLayout[j];
129 // build remap layout we can pass to resampler as destination layout
130 CAEChannelInfo remapLayout;
132 for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
134 for(unsigned int j=0; j<m_format.m_channelLayout.Count(); j++)
136 idx = m_remapper->GetAVChannelIndex(m_format.m_channelLayout[j], avLayout);
139 remapLayout += ffmpegLayout[j];
145 // initialize resampler for only doing remapping
146 m_remapper->Init(avLayout,
147 m_format.m_channelLayout.Count(),
148 m_format.m_sampleRate,
149 CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
150 CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
152 m_format.m_channelLayout.Count(),
153 m_format.m_sampleRate,
154 CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
155 CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
159 AE_QUALITY_LOW); // not used for remapping
161 // extra sound packet, we can't resample to the same buffer
162 m_remapBuffer = new CSoundPacket(m_inputBuffers->m_allSamples[0]->pkt->config, m_inputBuffers->m_allSamples[0]->pkt->max_nb_samples);
166 void CActiveAEStream::RemapBuffer()
170 int samples = m_remapper->Resample(m_remapBuffer->data, m_remapBuffer->max_nb_samples,
171 m_currentBuffer->pkt->data, m_currentBuffer->pkt->nb_samples,
174 if (samples != m_currentBuffer->pkt->nb_samples)
176 CLog::Log(LOGERROR, "CActiveAEStream::%s - error remapping", __FUNCTION__);
179 // swap sound packets
180 CSoundPacket *tmp = m_remapBuffer;
181 tmp = m_currentBuffer->pkt;
182 m_currentBuffer->pkt = m_remapBuffer;
187 unsigned int CActiveAEStream::GetSpace()
189 CSingleLock lock(m_streamLock);
190 return m_streamFreeBuffers * m_streamSpace;
193 unsigned int CActiveAEStream::AddData(void *data, unsigned int size)
196 unsigned int copied = 0;
197 unsigned int bytesToCopy = size;
198 uint8_t *buf = (uint8_t*)data;
202 buf = (uint8_t*)data;
203 bytesToCopy = size - copied;
207 // fill leftover buffer and copy it first
208 if (m_leftoverBytes && bytesToCopy >= (m_format.m_frameSize - m_leftoverBytes))
210 int fillbytes = m_format.m_frameSize - m_leftoverBytes;
211 memcpy(m_leftoverBuffer+m_leftoverBytes, (uint8_t*)data, fillbytes);
212 data = (uint8_t*)data + 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+copied, 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+copied, samples*m_currentBuffer->pkt->config.channels, (float*)(m_currentBuffer->pkt->data[0] + start));
243 memcpy(m_currentBuffer->pkt->data[0] + start, buf+copied, 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);
357 msg->Reply(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
361 else if (msg->signal == CActiveAEDataProtocol::STREAMDRAINED)
370 m_inMsgEvent.WaitMSec(timer.MillisLeft());
372 CLog::Log(LOGERROR, "CActiveAEStream::Drain - timeout out");
375 bool CActiveAEStream::IsDraining()
377 CSingleLock lock(m_streamLock);
378 return m_streamDraining;
381 bool CActiveAEStream::IsDrained()
383 CSingleLock lock(m_streamLock);
384 return m_streamDrained;
387 void CActiveAEStream::Flush()
389 m_currentBuffer = NULL;
391 AE.FlushStream(this);
395 float CActiveAEStream::GetAmplification()
397 return m_streamAmplify;
400 void CActiveAEStream::SetAmplification(float amplify)
402 m_streamAmplify = amplify;
403 AE.SetStreamAmplification(this, m_streamAmplify);
406 float CActiveAEStream::GetReplayGain()
408 return m_streamRgain;
411 void CActiveAEStream::SetReplayGain(float factor)
413 m_streamRgain = std::max( 0.0f, factor);
414 AE.SetStreamReplaygain(this, m_streamRgain);
417 float CActiveAEStream::GetVolume()
419 return m_streamVolume;
422 void CActiveAEStream::SetVolume(float volume)
424 m_streamVolume = std::max( 0.0f, std::min(1.0f, volume));
425 AE.SetStreamVolume(this, m_streamVolume);
428 double CActiveAEStream::GetResampleRatio()
430 return m_streamResampleRatio;
433 bool CActiveAEStream::SetResampleRatio(double ratio)
435 m_streamResampleRatio = ratio;
436 AE.SetStreamResampleRatio(this, m_streamResampleRatio);
440 void CActiveAEStream::FadeVolume(float from, float target, unsigned int time)
442 if (time == 0 || AE_IS_RAW(m_format.m_dataFormat))
445 m_streamFading = true;
446 AE.SetStreamFade(this, from, target, time);
449 bool CActiveAEStream::IsFading()
451 CSingleLock lock(m_streamLock);
452 return m_streamFading;
455 const unsigned int CActiveAEStream::GetFrameSize() const
457 return m_format.m_frameSize;
460 const unsigned int CActiveAEStream::GetChannelCount() const
462 return m_format.m_channelLayout.Count();
465 const unsigned int CActiveAEStream::GetSampleRate() const
467 return m_format.m_sampleRate;
470 const unsigned int CActiveAEStream::GetEncodedSampleRate() const
472 return m_format.m_encodedRate;
475 const enum AEDataFormat CActiveAEStream::GetDataFormat() const
477 return m_format.m_dataFormat;
480 void CActiveAEStream::RegisterAudioCallback(IAudioCallback* pCallback)
484 void CActiveAEStream::UnRegisterAudioCallback()
488 void CActiveAEStream::RegisterSlave(IAEStream *slave)
490 CSingleLock lock(m_streamLock);
491 m_streamSlave = slave;