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;
61 CActiveAEStream::~CActiveAEStream()
63 delete [] m_leftoverBuffer;
66 void CActiveAEStream::IncFreeBuffers()
68 CSingleLock lock(m_streamLock);
69 m_streamFreeBuffers++;
72 void CActiveAEStream::DecFreeBuffers()
74 CSingleLock lock(m_streamLock);
75 m_streamFreeBuffers--;
78 void CActiveAEStream::ResetFreeBuffers()
80 CSingleLock lock(m_streamLock);
81 m_streamFreeBuffers = 0;
84 unsigned int CActiveAEStream::GetSpace()
86 CSingleLock lock(m_streamLock);
87 return m_streamFreeBuffers * m_streamSpace;
90 unsigned int CActiveAEStream::AddData(void *data, unsigned int size)
93 unsigned int copied = 0;
94 unsigned int bytesToCopy = size;
95 uint8_t *buf = (uint8_t*)data;
100 bytesToCopy = size - copied;
104 // fill leftover buffer and copy it first
105 if (m_leftoverBytes && bytesToCopy >= (m_format.m_frameSize - m_leftoverBytes))
107 int fillbytes = m_format.m_frameSize - m_leftoverBytes;
108 memcpy(m_leftoverBuffer+m_leftoverBytes, (uint8_t*)data, fillbytes);
109 data = (uint8_t*)data + fillbytes;
111 // leftover buffer will be copied on next cycle
112 buf = m_leftoverBuffer;
113 bytesToCopy = m_format.m_frameSize;
117 int start = m_currentBuffer->pkt->nb_samples *
118 m_currentBuffer->pkt->bytes_per_sample *
119 m_currentBuffer->pkt->config.channels /
120 m_currentBuffer->pkt->planes;
122 int freeSamples = m_currentBuffer->pkt->max_nb_samples - m_currentBuffer->pkt->nb_samples;
123 int availableSamples = bytesToCopy / m_format.m_frameSize;
125 // if we don't have a full frame, copy to leftover buffer
126 if (!availableSamples && bytesToCopy)
128 memcpy(m_leftoverBuffer+m_leftoverBytes, buf+copied, bytesToCopy);
129 m_leftoverBytes = bytesToCopy;
130 copied += bytesToCopy;
133 int samples = std::min(freeSamples, availableSamples);
134 int bytes = samples * m_format.m_frameSize;
136 //TODO: handle planar formats
138 m_convertFn(buf+copied, samples*m_currentBuffer->pkt->config.channels, (float*)(m_currentBuffer->pkt->data[0] + start));
140 memcpy(m_currentBuffer->pkt->data[0] + start, buf+copied, bytes);
142 CSingleLock lock(*m_statsLock);
143 m_currentBuffer->pkt->nb_samples += samples;
144 m_bufferedTime += (double)samples / m_currentBuffer->pkt->config.sample_rate;
146 if (buf != m_leftoverBuffer)
148 if (m_currentBuffer->pkt->nb_samples == m_currentBuffer->pkt->max_nb_samples)
150 MsgStreamSample msgData;
151 msgData.buffer = m_currentBuffer;
152 msgData.stream = this;
153 m_streamPort->SendOutMessage(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
154 m_currentBuffer = NULL;
158 else if (m_streamPort->ReceiveInMessage(&msg))
160 if (msg->signal == CActiveAEDataProtocol::STREAMBUFFER)
162 m_currentBuffer = *((CSampleBuffer**)msg->data);
169 CLog::Log(LOGERROR, "CActiveAEStream::AddData - unknown signal");
174 if (!m_inMsgEvent.WaitMSec(200))
180 double CActiveAEStream::GetDelay()
182 return AE.GetDelay(this);
185 bool CActiveAEStream::IsBuffering()
187 CSingleLock lock(m_streamLock);
188 return m_streamIsBuffering;
191 double CActiveAEStream::GetCacheTime()
193 return AE.GetCacheTime(this);
196 double CActiveAEStream::GetCacheTotal()
198 return AE.GetCacheTotal(this);
201 void CActiveAEStream::Pause()
203 AE.PauseStream(this, true);
206 void CActiveAEStream::Resume()
208 AE.PauseStream(this, false);
211 void CActiveAEStream::Drain(bool wait)
214 CActiveAEStream *stream = this;
216 m_streamDraining = true;
217 m_streamDrained = false;
220 if (m_streamPort->SendOutMessageSync(CActiveAEDataProtocol::DRAINSTREAM,
222 &stream, sizeof(CActiveAEStream*)))
224 bool success = reply->signal == CActiveAEDataProtocol::ACC ? true : false;
228 CLog::Log(LOGERROR, "CActiveAEStream::Drain - no acc");
234 MsgStreamSample msgData;
235 msgData.buffer = m_currentBuffer;
236 msgData.stream = this;
237 m_streamPort->SendOutMessage(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
238 m_currentBuffer = NULL;
241 XbmcThreads::EndTime timer(2000);
242 while (!timer.IsTimePast())
244 if (m_streamPort->ReceiveInMessage(&msg))
246 if (msg->signal == CActiveAEDataProtocol::STREAMBUFFER)
248 MsgStreamSample msgData;
249 msgData.stream = this;
250 msgData.buffer = *((CSampleBuffer**)msg->data);
251 msg->Reply(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
255 else if (msg->signal == CActiveAEDataProtocol::STREAMDRAINED)
264 m_inMsgEvent.WaitMSec(timer.MillisLeft());
266 CLog::Log(LOGERROR, "CActiveAEStream::Drain - timeout out");
269 bool CActiveAEStream::IsDraining()
271 CSingleLock lock(m_streamLock);
272 return m_streamDraining;
275 bool CActiveAEStream::IsDrained()
277 CSingleLock lock(m_streamLock);
278 return m_streamDrained;
281 void CActiveAEStream::Flush()
283 m_currentBuffer = NULL;
285 AE.FlushStream(this);
289 float CActiveAEStream::GetAmplification()
291 return m_streamAmplify;
294 void CActiveAEStream::SetAmplification(float amplify)
296 m_streamAmplify = amplify;
297 AE.SetStreamAmplification(this, m_streamAmplify);
300 float CActiveAEStream::GetReplayGain()
302 return m_streamRgain;
305 void CActiveAEStream::SetReplayGain(float factor)
307 m_streamRgain = std::max( 0.0f, factor);
308 AE.SetStreamReplaygain(this, m_streamRgain);
311 float CActiveAEStream::GetVolume()
313 return m_streamVolume;
316 void CActiveAEStream::SetVolume(float volume)
318 m_streamVolume = std::max( 0.0f, std::min(1.0f, volume));
319 AE.SetStreamVolume(this, m_streamVolume);
322 double CActiveAEStream::GetResampleRatio()
324 return m_streamResampleRatio;
327 bool CActiveAEStream::SetResampleRatio(double ratio)
329 m_streamResampleRatio = ratio;
330 AE.SetStreamResampleRatio(this, m_streamResampleRatio);
334 void CActiveAEStream::FadeVolume(float from, float target, unsigned int time)
336 if (time == 0 || AE_IS_RAW(m_format.m_dataFormat))
339 m_streamFading = true;
340 AE.SetStreamFade(this, from, target, time);
343 bool CActiveAEStream::IsFading()
345 CSingleLock lock(m_streamLock);
346 return m_streamFading;
349 const unsigned int CActiveAEStream::GetFrameSize() const
351 return m_format.m_frameSize;
354 const unsigned int CActiveAEStream::GetChannelCount() const
356 return m_format.m_channelLayout.Count();
359 const unsigned int CActiveAEStream::GetSampleRate() const
361 return m_format.m_sampleRate;
364 const unsigned int CActiveAEStream::GetEncodedSampleRate() const
366 return m_format.m_encodedRate;
369 const enum AEDataFormat CActiveAEStream::GetDataFormat() const
371 return m_format.m_dataFormat;
374 void CActiveAEStream::RegisterAudioCallback(IAudioCallback* pCallback)
378 void CActiveAEStream::UnRegisterAudioCallback()
382 void CActiveAEStream::RegisterSlave(IAEStream *slave)
384 CSingleLock lock(m_streamLock);
385 m_streamSlave = slave;