Mercurial > mplayer.hg
annotate libao2/ao_win32.c @ 36838:7df9dd22f234
Don't set win32 as audio driver if none has been given.
Select from the list of audio drivers instead.
Having win32 as selected item in the combo box although
this isn't used by MPlayer by default is confusing as well.
Besides that, there seem to be issues with this driver
when changing from or to it during playback.
author | ib |
---|---|
date | Tue, 25 Feb 2014 13:16:35 +0000 |
parents | 996a7f82f859 |
children |
rev | line source |
---|---|
26743
0f42fb42843c
Use standard license headers with standard formatting.
diego
parents:
23457
diff
changeset
|
1 /* |
0f42fb42843c
Use standard license headers with standard formatting.
diego
parents:
23457
diff
changeset
|
2 * Windows waveOut interface |
7913 | 3 * |
26743
0f42fb42843c
Use standard license headers with standard formatting.
diego
parents:
23457
diff
changeset
|
4 * Copyright (c) 2002 - 2004 Sascha Sommer <saschasommer@freenet.de> |
0f42fb42843c
Use standard license headers with standard formatting.
diego
parents:
23457
diff
changeset
|
5 * |
0f42fb42843c
Use standard license headers with standard formatting.
diego
parents:
23457
diff
changeset
|
6 * This file is part of MPlayer. |
0f42fb42843c
Use standard license headers with standard formatting.
diego
parents:
23457
diff
changeset
|
7 * |
0f42fb42843c
Use standard license headers with standard formatting.
diego
parents:
23457
diff
changeset
|
8 * MPlayer is free software; you can redistribute it and/or modify |
7913 | 9 * it under the terms of the GNU General Public License as published by |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
26743
0f42fb42843c
Use standard license headers with standard formatting.
diego
parents:
23457
diff
changeset
|
13 * MPlayer is distributed in the hope that it will be useful, |
7913 | 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
26743
0f42fb42843c
Use standard license headers with standard formatting.
diego
parents:
23457
diff
changeset
|
18 * You should have received a copy of the GNU General Public License along |
0f42fb42843c
Use standard license headers with standard formatting.
diego
parents:
23457
diff
changeset
|
19 * with MPlayer; if not, write to the Free Software Foundation, Inc., |
0f42fb42843c
Use standard license headers with standard formatting.
diego
parents:
23457
diff
changeset
|
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
0f42fb42843c
Use standard license headers with standard formatting.
diego
parents:
23457
diff
changeset
|
21 */ |
7913 | 22 |
23 #include <stdio.h> | |
24 #include <stdlib.h> | |
25 #include <windows.h> | |
26 #include <mmsystem.h> | |
27 | |
14479 | 28 #include "config.h" |
14245 | 29 #include "libaf/af_format.h" |
7913 | 30 #include "audio_out.h" |
31 #include "audio_out_internal.h" | |
14123 | 32 #include "mp_msg.h" |
33 #include "libvo/fastmemcpy.h" | |
12093
f54d02f6ddbf
let uninit wait until sound is completely played, don't restore volume at exit, fixed ringbuffer bug, patch by Nehal <nehalmistry at gmx.net>\n
faust3
parents:
11511
diff
changeset
|
34 #include "osdep/timer.h" |
7913 | 35 |
12699
02efc0619f61
10l WAVE_FORMAT_DOLBY_AC3_SPDIF needs to be defined first, patch by Gianluigi Tiesi <sherpya at netfarm.it>
faust3
parents:
12684
diff
changeset
|
36 #define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092 |
13017 | 37 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE |
38 | |
39 static const GUID KSDATAFORMAT_SUBTYPE_PCM = { | |
40 0x1,0x0000,0x0010,{0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71} | |
41 }; | |
42 | |
43 typedef struct { | |
44 WAVEFORMATEX Format; | |
45 union { | |
46 WORD wValidBitsPerSample; | |
47 WORD wSamplesPerBlock; | |
48 WORD wReserved; | |
49 } Samples; | |
50 DWORD dwChannelMask; | |
51 GUID SubFormat; | |
52 } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; | |
53 | |
54 #define SPEAKER_FRONT_LEFT 0x1 | |
55 #define SPEAKER_FRONT_RIGHT 0x2 | |
56 #define SPEAKER_FRONT_CENTER 0x4 | |
57 #define SPEAKER_LOW_FREQUENCY 0x8 | |
58 #define SPEAKER_BACK_LEFT 0x10 | |
59 #define SPEAKER_BACK_RIGHT 0x20 | |
60 #define SPEAKER_FRONT_LEFT_OF_CENTER 0x40 | |
61 #define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80 | |
62 #define SPEAKER_BACK_CENTER 0x100 | |
63 #define SPEAKER_SIDE_LEFT 0x200 | |
64 #define SPEAKER_SIDE_RIGHT 0x400 | |
65 #define SPEAKER_TOP_CENTER 0x800 | |
66 #define SPEAKER_TOP_FRONT_LEFT 0x1000 | |
67 #define SPEAKER_TOP_FRONT_CENTER 0x2000 | |
68 #define SPEAKER_TOP_FRONT_RIGHT 0x4000 | |
69 #define SPEAKER_TOP_BACK_LEFT 0x8000 | |
70 #define SPEAKER_TOP_BACK_CENTER 0x10000 | |
71 #define SPEAKER_TOP_BACK_RIGHT 0x20000 | |
72 | |
73 static const int channel_mask[] = { | |
74 SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY, | |
75 SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY, | |
76 SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_CENTER | SPEAKER_LOW_FREQUENCY, | |
77 SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | |
78 }; | |
79 | |
80 | |
12699
02efc0619f61
10l WAVE_FORMAT_DOLBY_AC3_SPDIF needs to be defined first, patch by Gianluigi Tiesi <sherpya at netfarm.it>
faust3
parents:
12684
diff
changeset
|
81 |
12155
deb95ac21f14
restore original ringbuffer constants as the current values are causing heavy stutter here, especially noticable after moving the video window
faust3
parents:
12151
diff
changeset
|
82 #define SAMPLESIZE 1024 |
deb95ac21f14
restore original ringbuffer constants as the current values are causing heavy stutter here, especially noticable after moving the video window
faust3
parents:
12151
diff
changeset
|
83 #define BUFFER_COUNT 16 |
7913 | 84 |
85 | |
86 static WAVEHDR* waveBlocks; //pointer to our ringbuffer memory | |
87 static HWAVEOUT hWaveOut; //handle to the waveout device | |
88 static unsigned int buf_write=0; | |
28822
2c00a46b99c8
Use code that is actually thread-safe to calculate delay, free space etc. in ao_win32
reimar
parents:
28821
diff
changeset
|
89 static volatile int buf_read=0; |
7913 | 90 |
91 | |
28823 | 92 static const ao_info_t info = |
7913 | 93 { |
94 "Windows waveOut audio output", | |
95 "win32", | |
96 "Sascha Sommer <saschasommer@freenet.de>", | |
97 "" | |
98 }; | |
99 | |
100 LIBAO_EXTERN(win32) | |
101 | |
28821 | 102 static void CALLBACK waveOutProc(HWAVEOUT hWaveOut,UINT uMsg,DWORD dwInstance, |
7913 | 103 DWORD dwParam1,DWORD dwParam2) |
104 { | |
105 if(uMsg != WOM_DONE) | |
106 return; | |
28822
2c00a46b99c8
Use code that is actually thread-safe to calculate delay, free space etc. in ao_win32
reimar
parents:
28821
diff
changeset
|
107 buf_read = (buf_read + 1) % BUFFER_COUNT; |
7913 | 108 } |
109 | |
110 // to set/get/query special features/parameters | |
9633
12b1790038b0
64bit libao2 fix by Jens Axboe <mplayer-dev@kernel.dk>
alex
parents:
9589
diff
changeset
|
111 static int control(int cmd,void *arg) |
7913 | 112 { |
113 DWORD volume; | |
114 switch (cmd) | |
115 { | |
116 case AOCONTROL_GET_VOLUME: | |
117 { | |
118 ao_control_vol_t* vol = (ao_control_vol_t*)arg; | |
119 waveOutGetVolume(hWaveOut,&volume); | |
35844 | 120 vol->left = LOWORD(volume)/655.35; |
121 vol->right = HIWORD(volume)/655.35; | |
7913 | 122 mp_msg(MSGT_AO, MSGL_DBG2,"ao_win32: volume left:%f volume right:%f\n",vol->left,vol->right); |
123 return CONTROL_OK; | |
124 } | |
125 case AOCONTROL_SET_VOLUME: | |
126 { | |
127 ao_control_vol_t* vol = (ao_control_vol_t*)arg; | |
128 volume = MAKELONG(vol->left*655.35,vol->right*655.35); | |
129 waveOutSetVolume(hWaveOut,volume); | |
130 return CONTROL_OK; | |
131 } | |
132 } | |
133 return -1; | |
134 } | |
135 | |
136 // open & setup audio device | |
137 // return: 1=success 0=fail | |
138 static int init(int rate,int channels,int format,int flags) | |
139 { | |
28821 | 140 WAVEFORMATEXTENSIBLE wformat; |
7913 | 141 MMRESULT result; |
142 unsigned char* buffer; | |
143 int i; | |
28821 | 144 |
30241
02b9c1a452e1
Add support for distinguishing between little- and big-endian SPDIF AC3
reimar
parents:
30240
diff
changeset
|
145 if (AF_FORMAT_IS_AC3(format)) |
02b9c1a452e1
Add support for distinguishing between little- and big-endian SPDIF AC3
reimar
parents:
30240
diff
changeset
|
146 format = AF_FORMAT_AC3_NE; |
14135 | 147 switch(format){ |
30241
02b9c1a452e1
Add support for distinguishing between little- and big-endian SPDIF AC3
reimar
parents:
30240
diff
changeset
|
148 case AF_FORMAT_AC3_NE: |
14245 | 149 case AF_FORMAT_S24_LE: |
150 case AF_FORMAT_S16_LE: | |
28815
ce24a9f06ccb
The 8 bit per sample formats are unsigned on Windows, fixes playback with
reimar
parents:
28793
diff
changeset
|
151 case AF_FORMAT_U8: |
14135 | 152 break; |
153 default: | |
14264 | 154 mp_msg(MSGT_AO, MSGL_V,"ao_win32: format %s not supported defaulting to Signed 16-bit Little-Endian\n",af_fmt2str_short(format)); |
14245 | 155 format=AF_FORMAT_S16_LE; |
28821 | 156 } |
19835
807cdfafa0ce
disable multichannel mode, it never worked reliable
faust3
parents:
19614
diff
changeset
|
157 |
28821 | 158 //fill global ao_data |
7913 | 159 ao_data.channels=channels; |
160 ao_data.samplerate=rate; | |
161 ao_data.format=format; | |
162 ao_data.bps=channels*rate; | |
35277 | 163 ao_data.bps*=af_fmt2bits(format)/8; |
7913 | 164 if(ao_data.buffersize==-1) |
165 { | |
14264 | 166 ao_data.buffersize=af_fmt2bits(format)/8; |
7913 | 167 ao_data.buffersize*= channels; |
168 ao_data.buffersize*= SAMPLESIZE; | |
169 } | |
35278 | 170 ao_data.outburst = ao_data.buffersize; |
14264 | 171 mp_msg(MSGT_AO, MSGL_V,"ao_win32: Samplerate:%iHz Channels:%i Format:%s\n",rate, channels, af_fmt2str_short(format)); |
7913 | 172 mp_msg(MSGT_AO, MSGL_V,"ao_win32: Buffersize:%d\n",ao_data.buffersize); |
28821 | 173 |
7913 | 174 //fill waveformatex |
13017 | 175 ZeroMemory( &wformat, sizeof(WAVEFORMATEXTENSIBLE)); |
13735
83c5f9888576
ringbuffer variable intialization fix for multifile playback patch by Rune Petersen <rune.mail-list at mail.tele.dk>
faust3
parents:
13017
diff
changeset
|
176 wformat.Format.cbSize = (channels>2)?sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX):0; |
28821 | 177 wformat.Format.nChannels = channels; |
178 wformat.Format.nSamplesPerSec = rate; | |
35277 | 179 wformat.Format.wBitsPerSample = af_fmt2bits(format); |
30240 | 180 if(AF_FORMAT_IS_AC3(format)) |
12684
47598beff93a
ac3 passthrough, initial patch by Gianluigi Tiesi <sherpya at netfarm.it>
faust3
parents:
12155
diff
changeset
|
181 { |
13017 | 182 wformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF; |
183 wformat.Format.nBlockAlign = 4; | |
12684
47598beff93a
ac3 passthrough, initial patch by Gianluigi Tiesi <sherpya at netfarm.it>
faust3
parents:
12155
diff
changeset
|
184 } |
28821 | 185 else |
12684
47598beff93a
ac3 passthrough, initial patch by Gianluigi Tiesi <sherpya at netfarm.it>
faust3
parents:
12155
diff
changeset
|
186 { |
13017 | 187 wformat.Format.wFormatTag = (channels>2)?WAVE_FORMAT_EXTENSIBLE:WAVE_FORMAT_PCM; |
188 wformat.Format.nBlockAlign = wformat.Format.nChannels * (wformat.Format.wBitsPerSample >> 3); | |
189 } | |
190 if(channels>2) | |
191 { | |
192 wformat.dwChannelMask = channel_mask[channels-3]; | |
193 wformat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; | |
14264 | 194 wformat.Samples.wValidBitsPerSample=af_fmt2bits(format); |
13017 | 195 } |
28821 | 196 |
13017 | 197 wformat.Format.nAvgBytesPerSec = wformat.Format.nSamplesPerSec * wformat.Format.nBlockAlign; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28883
diff
changeset
|
198 |
7913 | 199 //open sound device |
200 //WAVE_MAPPER always points to the default wave device on the system | |
14529
cc9c088305d9
WAVE_FORMAT_DIRECT seems to cause problems with certain os/driver combinations and seems to be useless anyway
faust3
parents:
14503
diff
changeset
|
201 result = waveOutOpen(&hWaveOut,WAVE_MAPPER,(WAVEFORMATEX*)&wformat,(DWORD_PTR)waveOutProc,0,CALLBACK_FUNCTION); |
7913 | 202 if(result == WAVERR_BADFORMAT) |
203 { | |
204 mp_msg(MSGT_AO, MSGL_ERR,"ao_win32: format not supported switching to default\n"); | |
13017 | 205 ao_data.channels = wformat.Format.nChannels = 2; |
206 ao_data.samplerate = wformat.Format.nSamplesPerSec = 44100; | |
14245 | 207 ao_data.format = AF_FORMAT_S16_LE; |
13017 | 208 ao_data.bps=ao_data.channels * ao_data.samplerate*2; |
209 wformat.Format.wBitsPerSample=16; | |
210 wformat.Format.wFormatTag=WAVE_FORMAT_PCM; | |
211 wformat.Format.nBlockAlign = wformat.Format.nChannels * (wformat.Format.wBitsPerSample >> 3); | |
212 wformat.Format.nAvgBytesPerSec = wformat.Format.nSamplesPerSec * wformat.Format.nBlockAlign; | |
213 ao_data.buffersize=(wformat.Format.wBitsPerSample>>3)*wformat.Format.nChannels*SAMPLESIZE; | |
214 result = waveOutOpen(&hWaveOut,WAVE_MAPPER,(WAVEFORMATEX*)&wformat,(DWORD_PTR)waveOutProc,0,CALLBACK_FUNCTION); | |
7913 | 215 } |
216 if(result != MMSYSERR_NOERROR) | |
217 { | |
14503 | 218 mp_msg(MSGT_AO, MSGL_ERR,"ao_win32: unable to open wave mapper device (result=%i)\n",result); |
7913 | 219 return 0; |
220 } | |
221 //allocate buffer memory as one big block | |
35278 | 222 buffer = calloc(BUFFER_COUNT, ao_data.buffersize + sizeof(WAVEHDR)); |
28821 | 223 //and setup pointers to each buffer |
7913 | 224 waveBlocks = (WAVEHDR*)buffer; |
225 buffer += sizeof(WAVEHDR) * BUFFER_COUNT; | |
226 for(i = 0; i < BUFFER_COUNT; i++) { | |
227 waveBlocks[i].lpData = buffer; | |
35278 | 228 buffer += ao_data.buffersize; |
7913 | 229 } |
13735
83c5f9888576
ringbuffer variable intialization fix for multifile playback patch by Rune Petersen <rune.mail-list at mail.tele.dk>
faust3
parents:
13017
diff
changeset
|
230 buf_write=0; |
28822
2c00a46b99c8
Use code that is actually thread-safe to calculate delay, free space etc. in ao_win32
reimar
parents:
28821
diff
changeset
|
231 buf_read=0; |
7913 | 232 |
233 return 1; | |
234 } | |
235 | |
236 // close audio device | |
12145 | 237 static void uninit(int immed) |
7913 | 238 { |
28793
afbd8dd23299
Sleep based on get_delay in ao_win32 uninit instead of a loop.
reimar
parents:
28776
diff
changeset
|
239 if(!immed) |
afbd8dd23299
Sleep based on get_delay in ao_win32 uninit instead of a loop.
reimar
parents:
28776
diff
changeset
|
240 usec_sleep(get_delay() * 1000 * 1000); |
28883
c3f295ceae51
Do not call waveOutReset in uninit if you should wait till playing finishes,
reimar
parents:
28823
diff
changeset
|
241 else |
7913 | 242 waveOutReset(hWaveOut); |
28883
c3f295ceae51
Do not call waveOutReset in uninit if you should wait till playing finishes,
reimar
parents:
28823
diff
changeset
|
243 while (waveOutClose(hWaveOut) == WAVERR_STILLPLAYING) usec_sleep(0); |
7913 | 244 mp_msg(MSGT_AO, MSGL_V,"waveOut device closed\n"); |
245 free(waveBlocks); | |
246 mp_msg(MSGT_AO, MSGL_V,"buffer memory freed\n"); | |
247 } | |
248 | |
249 // stop playing and empty buffers (for seeking/pause) | |
18915
99e20a22d5d0
modifies function declarations without parameters from ()
reynaldo
parents:
14529
diff
changeset
|
250 static void reset(void) |
7913 | 251 { |
252 waveOutReset(hWaveOut); | |
253 buf_write=0; | |
28822
2c00a46b99c8
Use code that is actually thread-safe to calculate delay, free space etc. in ao_win32
reimar
parents:
28821
diff
changeset
|
254 buf_read=0; |
7913 | 255 } |
256 | |
257 // stop playing, keep buffers (for pause) | |
18915
99e20a22d5d0
modifies function declarations without parameters from ()
reynaldo
parents:
14529
diff
changeset
|
258 static void audio_pause(void) |
7913 | 259 { |
260 waveOutPause(hWaveOut); | |
261 } | |
262 | |
263 // resume playing, after audio_pause() | |
18915
99e20a22d5d0
modifies function declarations without parameters from ()
reynaldo
parents:
14529
diff
changeset
|
264 static void audio_resume(void) |
7913 | 265 { |
266 waveOutRestart(hWaveOut); | |
267 } | |
268 | |
269 // return: how many bytes can be played without blocking | |
18915
99e20a22d5d0
modifies function declarations without parameters from ()
reynaldo
parents:
14529
diff
changeset
|
270 static int get_space(void) |
7913 | 271 { |
28822
2c00a46b99c8
Use code that is actually thread-safe to calculate delay, free space etc. in ao_win32
reimar
parents:
28821
diff
changeset
|
272 int free = buf_read - buf_write - 1; |
2c00a46b99c8
Use code that is actually thread-safe to calculate delay, free space etc. in ao_win32
reimar
parents:
28821
diff
changeset
|
273 if (free < 0) free += BUFFER_COUNT; |
35278 | 274 return free * ao_data.buffersize; |
7913 | 275 } |
276 | |
277 //writes data into buffer, based on ringbuffer code in ao_sdl.c | |
278 static int write_waveOutBuffer(unsigned char* data,int len){ | |
279 WAVEHDR* current; | |
280 int len2=0; | |
281 int x; | |
28821 | 282 while(len>0){ |
28822
2c00a46b99c8
Use code that is actually thread-safe to calculate delay, free space etc. in ao_win32
reimar
parents:
28821
diff
changeset
|
283 int buf_next = (buf_write + 1) % BUFFER_COUNT; |
7913 | 284 current = &waveBlocks[buf_write]; |
28822
2c00a46b99c8
Use code that is actually thread-safe to calculate delay, free space etc. in ao_win32
reimar
parents:
28821
diff
changeset
|
285 if(buf_next == buf_read) break; |
7913 | 286 //unprepare the header if it is prepared |
28821 | 287 if(current->dwFlags & WHDR_PREPARED) |
7913 | 288 waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR)); |
35278 | 289 x=ao_data.buffersize; |
28821 | 290 if(x>len) x=len; |
291 fast_memcpy(current->lpData,data+len2,x); | |
292 len2+=x; len-=x; | |
7913 | 293 //prepare header and write data to device |
28818
e3d54ef875a5
Always write full buffers in ao_win32, except for the last block.
reimar
parents:
28817
diff
changeset
|
294 current->dwBufferLength = x; |
7913 | 295 waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR)); |
296 waveOutWrite(hWaveOut, current, sizeof(WAVEHDR)); | |
28821 | 297 |
28822
2c00a46b99c8
Use code that is actually thread-safe to calculate delay, free space etc. in ao_win32
reimar
parents:
28821
diff
changeset
|
298 buf_write = buf_next; |
7913 | 299 } |
300 return len2; | |
301 } | |
302 | |
303 // plays 'len' bytes of 'data' | |
304 // it should round it down to outburst*n | |
305 // return: number of bytes played | |
306 static int play(void* data,int len,int flags) | |
307 { | |
20250
7cfd3a04d537
Implement AOPLAY_FINAL_CHUNK support for dshow and win32 out.
reimar
parents:
19835
diff
changeset
|
308 if (!(flags & AOPLAY_FINAL_CHUNK)) |
12151
75fdb659f5bf
round len to outburst and increment full_buffers at the correct time, patch by Nehal <nehalmistry at gmx.net>
faust3
parents:
12146
diff
changeset
|
309 len = (len/ao_data.outburst)*ao_data.outburst; |
7913 | 310 return write_waveOutBuffer(data,len); |
311 } | |
10106 | 312 |
7913 | 313 // return: delay in seconds between first and last sample in buffer |
18915
99e20a22d5d0
modifies function declarations without parameters from ()
reynaldo
parents:
14529
diff
changeset
|
314 static float get_delay(void) |
7913 | 315 { |
28822
2c00a46b99c8
Use code that is actually thread-safe to calculate delay, free space etc. in ao_win32
reimar
parents:
28821
diff
changeset
|
316 int used = buf_write - buf_read; |
2c00a46b99c8
Use code that is actually thread-safe to calculate delay, free space etc. in ao_win32
reimar
parents:
28821
diff
changeset
|
317 if (used < 0) used += BUFFER_COUNT; |
35278 | 318 return (float)((used + 1) * ao_data.buffersize)/(float)ao_data.bps; |
7913 | 319 } |