Merge pull request #1129 from jmarshallnz/remove_smb_auth_details_in_add_source
[vuplus_xbmc] / xbmc / cores / dvdplayer / DVDAudio.cpp
1 /*
2  *      Copyright (C) 2005-2008 Team XBMC
3  *      http://www.xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "threads/SingleLock.h"
23 #include "utils/log.h"
24 #include "DVDAudio.h"
25 #include "Util.h"
26 #include "DVDClock.h"
27 #include "DVDCodecs/DVDCodecs.h"
28 #include "DVDPlayerAudio.h"
29 #include "cores/AudioEngine/AEFactory.h"
30 #include "cores/AudioEngine/Interfaces/AEStream.h"
31 #include "settings/Settings.h"
32
33 using namespace std;
34
35 CDVDAudio::CDVDAudio(volatile bool &bStop)
36   : m_bStop(bStop)
37 {
38   m_pAudioStream = NULL;
39   m_iBufferSize = 0;
40   m_dwPacketSize = 0;
41   m_pBuffer = NULL;
42   m_bPassthrough = false;
43   m_iBitsPerSample = 0;
44   m_iBitrate = 0;
45   m_SecondsPerByte = 0.0;
46   m_bPaused = true;
47 }
48
49 CDVDAudio::~CDVDAudio()
50 {
51   CSingleLock lock (m_critSection);
52   if (m_pAudioStream)
53     CAEFactory::FreeStream(m_pAudioStream);
54
55   free(m_pBuffer);
56 }
57
58 bool CDVDAudio::Create(const DVDAudioFrame &audioframe, CodecID codec, bool needresampler)
59 {
60   CLog::Log(LOGNOTICE,
61     "Creating audio stream (codec id: %i, channels: %i, sample rate: %i, %s)",
62     codec,
63     audioframe.channel_count,
64     audioframe.sample_rate,
65     audioframe.passthrough ? "pass-through" : "no pass-through"
66   );
67
68   // if passthrough isset do something else
69   CSingleLock lock(m_critSection);
70   unsigned int options = needresampler && !audioframe.passthrough ? AESTREAM_FORCE_RESAMPLE : 0;
71   options |= AESTREAM_AUTOSTART;
72
73   m_pAudioStream = CAEFactory::MakeStream(
74     audioframe.data_format,
75     audioframe.sample_rate,
76     audioframe.encoded_sample_rate,
77     audioframe.channel_layout,
78     options
79   );
80   if (!m_pAudioStream) return false;
81
82   m_iBitrate       = audioframe.sample_rate;
83   m_iBitsPerSample = audioframe.bits_per_sample;
84   m_bPassthrough   = audioframe.passthrough;
85   m_channelLayout  = audioframe.channel_layout;
86   m_dwPacketSize   = m_pAudioStream->GetFrameSize();
87
88   if(m_channelLayout.Count() && m_iBitrate && m_iBitsPerSample)
89     m_SecondsPerByte = 1.0 / (m_channelLayout.Count() * m_iBitrate * (m_iBitsPerSample>>3));
90   else
91     m_SecondsPerByte = 0.0;
92
93   m_iBufferSize = 0;
94   SetDynamicRangeCompression((long)(g_settings.m_currentVideoSettings.m_VolumeAmplification * 100));
95
96   return true;
97 }
98
99 void CDVDAudio::Destroy()
100 {
101   CSingleLock lock (m_critSection);
102
103   if (m_pAudioStream)
104     CAEFactory::FreeStream(m_pAudioStream);
105
106   free(m_pBuffer);
107   m_pBuffer = NULL;
108   m_dwPacketSize = 0;
109   m_pAudioStream = NULL;
110   m_iBufferSize = 0;
111   m_iBitrate = 0;
112   m_iBitsPerSample = 0;
113   m_bPassthrough = false;
114   m_bPaused = true;
115 }
116
117 DWORD CDVDAudio::AddPacketsRenderer(unsigned char* data, DWORD len, CSingleLock &lock)
118 {
119   if(!m_pAudioStream)
120     return 0;
121
122   DWORD bps = m_channelLayout.Count() * m_iBitrate * (m_iBitsPerSample>>3);
123   if(!bps)
124     return 0;
125
126   //Calculate a timeout when this definitely should be done
127   double timeout;
128   timeout  = DVD_SEC_TO_TIME(m_pAudioStream->GetDelay() + len * m_SecondsPerByte);
129   timeout += DVD_SEC_TO_TIME(1.0);
130   timeout += CDVDClock::GetAbsoluteClock();
131
132   DWORD  total = len;
133   DWORD  copied;
134   do
135   {
136     copied = m_pAudioStream->AddData(data, len);
137     data += copied;
138     len -= copied;
139     if (len < m_dwPacketSize)
140       break;
141
142     if (copied == 0 && timeout < CDVDClock::GetAbsoluteClock())
143     {
144       CLog::Log(LOGERROR, "CDVDAudio::AddPacketsRenderer - timeout adding data to renderer");
145       break;
146     }
147
148     lock.Leave();
149     Sleep(1);
150     lock.Enter();
151   } while (!m_bStop);
152
153   return total - len;
154 }
155
156 DWORD CDVDAudio::AddPackets(const DVDAudioFrame &audioframe)
157 {
158   CSingleLock lock (m_critSection);
159
160   unsigned char* data = audioframe.data;
161   DWORD len = audioframe.size;
162
163   DWORD total = len;
164   DWORD copied;
165
166   if (m_iBufferSize > 0) // See if there are carryover bytes from the last call. need to add them 1st.
167   {
168     copied = std::min(m_dwPacketSize - m_iBufferSize % m_dwPacketSize, len); // Smaller of either the data provided or the leftover data
169     if(copied)
170     {
171       m_pBuffer = (BYTE*)realloc(m_pBuffer, m_iBufferSize + copied);
172       memcpy(m_pBuffer + m_iBufferSize, data, copied); // Tack the caller's data onto the end of the buffer
173       data += copied; // Move forward in caller's data
174       len -= copied; // Decrease amount of data available from caller
175       m_iBufferSize += copied; // Increase amount of data available in buffer
176     }
177
178     if(m_iBufferSize < m_dwPacketSize) // If we don't have enough data to give to the renderer, wait until next time
179       return copied;
180
181     if(AddPacketsRenderer(m_pBuffer, m_iBufferSize, lock) != m_iBufferSize)
182     {
183       m_iBufferSize = 0;
184       CLog::Log(LOGERROR, "%s - failed to add leftover bytes to render", __FUNCTION__);
185       return copied;
186     }
187
188     m_iBufferSize = 0;
189     if (!len)
190       return copied; // We used up all the caller's data
191   }
192
193   copied = AddPacketsRenderer(data, len, lock);
194   data += copied;
195   len -= copied;
196
197   // if we have more data left, save it for the next call to this funtion
198   if (len > 0 && !m_bStop)
199   {
200     m_pBuffer     = (BYTE*)realloc(m_pBuffer, len);
201     m_iBufferSize = len;
202     memcpy(m_pBuffer, data, len);
203   }
204   return total;
205 }
206
207 void CDVDAudio::Finish()
208 {
209   CSingleLock lock (m_critSection);
210   if (!m_pAudioStream)
211     return;
212
213   DWORD silence = m_dwPacketSize - m_iBufferSize % m_dwPacketSize;
214
215   if(silence > 0 && m_iBufferSize > 0)
216   {
217     CLog::Log(LOGDEBUG, "CDVDAudio::Drain - adding %d bytes of silence, buffer size: %d, chunk size: %d", silence, m_iBufferSize, m_dwPacketSize);
218     m_pBuffer = (BYTE*)realloc(m_pBuffer, m_iBufferSize + silence);
219     memset(m_pBuffer+m_iBufferSize, 0, silence);
220     m_iBufferSize += silence;
221   }
222
223   if(AddPacketsRenderer(m_pBuffer, m_iBufferSize, lock) != m_iBufferSize)
224     CLog::Log(LOGERROR, "CDVDAudio::Drain - failed to play the final %d bytes", m_iBufferSize);
225
226   m_iBufferSize = 0;
227 }
228
229 void CDVDAudio::Drain()
230 {
231   Finish();
232   CSingleLock lock (m_critSection);
233   if (m_pAudioStream)
234     m_pAudioStream->Drain();
235 }
236
237 void CDVDAudio::SetVolume(float volume)
238 {
239   CSingleLock lock (m_critSection);
240   if (m_pAudioStream) m_pAudioStream->SetVolume(volume);
241 }
242
243 void CDVDAudio::SetDynamicRangeCompression(long drc)
244 {
245
246 }
247
248 float CDVDAudio::GetCurrentAttenuation()
249 {
250   CSingleLock lock (m_critSection);
251   if (m_pAudioStream)
252     return m_pAudioStream->GetVolume();
253   else
254     return 1.0f;
255 }
256
257 void CDVDAudio::Pause()
258 {
259   CSingleLock lock (m_critSection);
260   if (m_pAudioStream) m_pAudioStream->Pause();
261 }
262
263 void CDVDAudio::Resume()
264 {
265   CSingleLock lock (m_critSection);
266   if (m_pAudioStream) m_pAudioStream->Resume();
267 }
268
269 double CDVDAudio::GetDelay()
270 {
271   CSingleLock lock (m_critSection);
272
273   double delay = 0.0;
274   if(m_pAudioStream)
275     delay = m_pAudioStream->GetDelay();
276
277   delay += m_SecondsPerByte * m_iBufferSize;
278
279   return delay * DVD_TIME_BASE;
280 }
281
282 void CDVDAudio::Flush()
283 {
284   CSingleLock lock (m_critSection);
285
286   if (m_pAudioStream)
287   {
288     m_pAudioStream->Flush();
289   }
290   m_iBufferSize = 0;
291 }
292
293 bool CDVDAudio::IsValidFormat(const DVDAudioFrame &audioframe)
294 {
295   if(!m_pAudioStream)
296     return false;
297
298   if(audioframe.passthrough != m_bPassthrough)
299     return false;
300
301   if(m_iBitrate       != audioframe.sample_rate
302   || m_iBitsPerSample != audioframe.bits_per_sample
303   || m_channelLayout  != audioframe.channel_layout)
304     return false;
305
306   return true;
307 }
308
309 void CDVDAudio::SetResampleRatio(double ratio)
310 {
311   CSingleLock lock (m_critSection);
312
313   if(m_pAudioStream)
314     m_pAudioStream->SetResampleRatio(ratio);
315 }
316
317 double CDVDAudio::GetCacheTime()
318 {
319   CSingleLock lock (m_critSection);
320   if(!m_pAudioStream)
321     return 0.0;
322
323   double delay = 0.0;
324   if(m_pAudioStream)
325     delay = m_pAudioStream->GetCacheTime();
326
327   delay += m_SecondsPerByte * m_iBufferSize;
328
329   return delay;
330 }
331
332 double CDVDAudio::GetCacheTotal()
333 {
334   CSingleLock lock (m_critSection);
335   if(!m_pAudioStream)
336     return 0.0;
337   return m_pAudioStream->GetCacheTotal();
338 }