Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / content / media / video / src / nsAudioStream.cpp
bloba3f9ec7c5ba20abe11daf76bace00cb3180f8b44
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is Mozilla code.
18 * The Initial Developer of the Original Code is the Mozilla Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2007
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Chris Double <chris.double@double.co.nz>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
38 #include <stdio.h>
39 #include <math.h>
40 #include "prlog.h"
41 #include "prmem.h"
42 #include "nsAutoPtr.h"
43 #include "nsAudioStream.h"
44 #include "nsAlgorithm.h"
45 extern "C" {
46 #include "sydneyaudio/sydney_audio.h"
49 #ifdef PR_LOGGING
50 PRLogModuleInfo* gAudioStreamLog = nsnull;
51 #endif
53 #define FAKE_BUFFER_SIZE 176400
55 static float CurrentTimeInSeconds()
57 return PR_IntervalToMilliseconds(PR_IntervalNow()) / 1000.0;
60 void nsAudioStream::InitLibrary()
62 #ifdef PR_LOGGING
63 gAudioStreamLog = PR_NewLogModule("nsAudioStream");
64 #endif
67 void nsAudioStream::ShutdownLibrary()
71 nsAudioStream::nsAudioStream() :
72 mVolume(1.0),
73 mAudioHandle(0),
74 mRate(0),
75 mChannels(0),
76 mSavedPauseBytes(0),
77 mPauseBytes(0),
78 mPauseTime(0.0),
79 mSamplesBuffered(0),
80 mFormat(FORMAT_S16_LE),
81 mPaused(PR_FALSE)
85 void nsAudioStream::Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat)
87 mRate = aRate;
88 mChannels = aNumChannels;
89 mFormat = aFormat;
90 mStartTime = CurrentTimeInSeconds();
91 if (sa_stream_create_pcm(reinterpret_cast<sa_stream_t**>(&mAudioHandle),
92 NULL,
93 SA_MODE_WRONLY,
94 SA_PCM_FORMAT_S16_LE,
95 aRate,
96 aNumChannels) != SA_SUCCESS) {
97 mAudioHandle = nsnull;
98 PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_create_pcm error"));
99 return;
102 if (sa_stream_open(static_cast<sa_stream_t*>(mAudioHandle)) != SA_SUCCESS) {
103 sa_stream_destroy(static_cast<sa_stream_t*>(mAudioHandle));
104 mAudioHandle = nsnull;
105 PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_open error"));
106 return;
110 void nsAudioStream::Shutdown()
112 if (!mAudioHandle)
113 return;
115 sa_stream_destroy(static_cast<sa_stream_t*>(mAudioHandle));
116 mAudioHandle = nsnull;
119 void nsAudioStream::Write(const void* aBuf, PRUint32 aCount)
121 NS_ABORT_IF_FALSE(aCount % mChannels == 0,
122 "Buffer size must be divisible by channel count");
124 mSamplesBuffered += aCount;
125 PRUint32 offset = mBufferOverflow.Length();
126 PRInt32 count = aCount + offset;
128 if (!mAudioHandle)
129 return;
131 nsAutoArrayPtr<short> s_data(new short[count]);
133 if (s_data) {
134 for (PRUint32 i=0; i < offset; ++i) {
135 s_data[i] = mBufferOverflow.ElementAt(i);
137 mBufferOverflow.Clear();
139 switch (mFormat) {
140 case FORMAT_U8: {
141 const PRUint8* buf = static_cast<const PRUint8*>(aBuf);
142 PRInt32 volume = PRInt32((1 << 16) * mVolume);
143 for (PRUint32 i = 0; i < aCount; ++i) {
144 s_data[i + offset] = short(((PRInt32(buf[i]) - 128) * volume) >> 8);
146 break;
148 case FORMAT_S16_LE: {
149 const short* buf = static_cast<const short*>(aBuf);
150 PRInt32 volume = PRInt32((1 << 16) * mVolume);
151 for (PRUint32 i = 0; i < aCount; ++i) {
152 s_data[i + offset] = short((PRInt32(buf[i]) * volume) >> 16);
154 break;
156 case FORMAT_FLOAT32_LE: {
157 const float* buf = static_cast<const float*>(aBuf);
158 for (PRUint32 i = 0; i < aCount; ++i) {
159 float scaled_value = floorf(0.5 + 32768 * buf[i] * mVolume);
160 if (buf[i] < 0.0) {
161 s_data[i + offset] = (scaled_value < -32768.0) ?
162 -32768 :
163 short(scaled_value);
164 } else {
165 s_data[i+offset] = (scaled_value > 32767.0) ?
166 32767 :
167 short(scaled_value);
170 break;
174 PRInt32 available = Available();
175 if (available < count) {
176 mBufferOverflow.AppendElements(s_data.get() + available, (count - available));
177 count = available;
180 if (sa_stream_write(static_cast<sa_stream_t*>(mAudioHandle),
181 s_data.get(), count * sizeof(short)) != SA_SUCCESS) {
182 PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_write error"));
183 Shutdown();
188 PRInt32 nsAudioStream::Available()
190 // If the audio backend failed to open, lie and say we'll accept some
191 // data.
192 if (!mAudioHandle)
193 return FAKE_BUFFER_SIZE;
195 size_t s = 0;
196 sa_stream_get_write_size(static_cast<sa_stream_t*>(mAudioHandle), &s);
197 return s / sizeof(short);
200 float nsAudioStream::GetVolume()
202 return mVolume;
205 void nsAudioStream::SetVolume(float aVolume)
207 NS_ASSERTION(aVolume >= 0.0 && aVolume <= 1.0, "Invalid volume");
208 mVolume = aVolume;
211 void nsAudioStream::Drain()
213 if (!mAudioHandle) {
214 // mSamplesBuffered already accounts for the data in the
215 // mBufferOverflow array.
216 PRUint32 drainTime = (float(mSamplesBuffered) / mRate / mChannels - GetTime()) * 1000.0;
217 PR_Sleep(PR_MillisecondsToInterval(drainTime));
218 return;
221 // Write any remaining unwritten sound data in the overflow buffer
222 if (!mBufferOverflow.IsEmpty()) {
223 if (sa_stream_write(static_cast<sa_stream_t*>(mAudioHandle),
224 mBufferOverflow.Elements(),
225 mBufferOverflow.Length() * sizeof(short)) != SA_SUCCESS)
226 return;
229 if (sa_stream_drain(static_cast<sa_stream_t*>(mAudioHandle)) != SA_SUCCESS) {
230 PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_drain error"));
231 Shutdown();
235 void nsAudioStream::Pause()
237 if (mPaused)
238 return;
240 // Save the elapsed playback time. Used to offset the wall-clock time
241 // when resuming.
242 mPauseTime = CurrentTimeInSeconds() - mStartTime;
244 mPaused = PR_TRUE;
246 if (!mAudioHandle)
247 return;
249 int64_t bytes = 0;
250 #if !defined(WIN32)
251 sa_stream_get_position(static_cast<sa_stream_t*>(mAudioHandle), SA_POSITION_WRITE_SOFTWARE, &bytes);
252 #endif
253 mSavedPauseBytes = bytes;
255 sa_stream_pause(static_cast<sa_stream_t*>(mAudioHandle));
258 void nsAudioStream::Resume()
260 if (!mPaused)
261 return;
263 // Reset the start time to the current time offset backwards by the
264 // elapsed time saved when the stream paused.
265 mStartTime = CurrentTimeInSeconds() - mPauseTime;
267 mPaused = PR_FALSE;
269 if (!mAudioHandle)
270 return;
272 sa_stream_resume(static_cast<sa_stream_t*>(mAudioHandle));
274 #if !defined(WIN32)
275 mPauseBytes += mSavedPauseBytes;
276 #endif
279 double nsAudioStream::GetTime()
281 // If the audio backend failed to open, emulate the current playback
282 // position using the system clock.
283 if (!mAudioHandle) {
284 if (mPaused) {
285 return mPauseTime;
287 float curTime = CurrentTimeInSeconds() - mStartTime;
288 float maxTime = float(mSamplesBuffered) / mRate / mChannels;
289 return NS_MIN(curTime, maxTime);
292 int64_t bytes = 0;
293 #if defined(WIN32)
294 sa_stream_get_position(static_cast<sa_stream_t*>(mAudioHandle), SA_POSITION_WRITE_HARDWARE, &bytes);
295 #else
296 sa_stream_get_position(static_cast<sa_stream_t*>(mAudioHandle), SA_POSITION_WRITE_SOFTWARE, &bytes);
297 #endif
298 return double(bytes + mPauseBytes) / (sizeof(short) * mChannels * mRate);