Mercurial > mplayer.hg
annotate libao2/ao_win32.c @ 14315:3bd9ef7083d3
synced to 1.51
author | gabrov |
---|---|
date | Mon, 03 Jan 2005 00:36:14 +0000 |
parents | cb5fbade8a5c |
children | cae0dbeb44bb |
rev | line source |
---|---|
7913 | 1 /****************************************************************************** |
2 * ao_win32.c: Windows waveOut interface for MPlayer | |
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
|
3 * Copyright (c) 2002 - 2004 Sascha Sommer <saschasommer@freenet.de>. |
7913 | 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 of the License, or | |
8 * (at your option) 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 this program; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. | |
18 * | |
19 *****************************************************************************/ | |
20 | |
21 #include <stdio.h> | |
22 #include <stdlib.h> | |
23 #include <windows.h> | |
24 #include <mmsystem.h> | |
25 | |
14245 | 26 #include "libaf/af_format.h" |
7913 | 27 #include "audio_out.h" |
28 #include "audio_out_internal.h" | |
14123 | 29 #include "mp_msg.h" |
30 #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
|
31 #include "osdep/timer.h" |
7913 | 32 |
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
|
33 #define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092 |
13017 | 34 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE |
35 | |
36 static const GUID KSDATAFORMAT_SUBTYPE_PCM = { | |
37 0x1,0x0000,0x0010,{0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71} | |
38 }; | |
39 | |
40 typedef struct { | |
41 WAVEFORMATEX Format; | |
42 union { | |
43 WORD wValidBitsPerSample; | |
44 WORD wSamplesPerBlock; | |
45 WORD wReserved; | |
46 } Samples; | |
47 DWORD dwChannelMask; | |
48 GUID SubFormat; | |
49 } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; | |
50 | |
51 #define SPEAKER_FRONT_LEFT 0x1 | |
52 #define SPEAKER_FRONT_RIGHT 0x2 | |
53 #define SPEAKER_FRONT_CENTER 0x4 | |
54 #define SPEAKER_LOW_FREQUENCY 0x8 | |
55 #define SPEAKER_BACK_LEFT 0x10 | |
56 #define SPEAKER_BACK_RIGHT 0x20 | |
57 #define SPEAKER_FRONT_LEFT_OF_CENTER 0x40 | |
58 #define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80 | |
59 #define SPEAKER_BACK_CENTER 0x100 | |
60 #define SPEAKER_SIDE_LEFT 0x200 | |
61 #define SPEAKER_SIDE_RIGHT 0x400 | |
62 #define SPEAKER_TOP_CENTER 0x800 | |
63 #define SPEAKER_TOP_FRONT_LEFT 0x1000 | |
64 #define SPEAKER_TOP_FRONT_CENTER 0x2000 | |
65 #define SPEAKER_TOP_FRONT_RIGHT 0x4000 | |
66 #define SPEAKER_TOP_BACK_LEFT 0x8000 | |
67 #define SPEAKER_TOP_BACK_CENTER 0x10000 | |
68 #define SPEAKER_TOP_BACK_RIGHT 0x20000 | |
69 | |
70 static const int channel_mask[] = { | |
71 SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY, | |
72 SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY, | |
73 SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_CENTER | SPEAKER_LOW_FREQUENCY, | |
74 SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | |
75 }; | |
76 | |
77 | |
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
|
78 |
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
|
79 #define SAMPLESIZE 1024 |
7913 | 80 #define BUFFER_SIZE 4096 |
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
|
81 #define BUFFER_COUNT 16 |
7913 | 82 |
83 | |
84 static WAVEHDR* waveBlocks; //pointer to our ringbuffer memory | |
85 static HWAVEOUT hWaveOut; //handle to the waveout device | |
86 static unsigned int buf_write=0; | |
87 static unsigned int buf_write_pos=0; | |
88 static int full_buffers=0; | |
89 static int buffered_bytes=0; | |
90 | |
91 | |
92 static ao_info_t info = | |
93 { | |
94 "Windows waveOut audio output", | |
95 "win32", | |
96 "Sascha Sommer <saschasommer@freenet.de>", | |
97 "" | |
98 }; | |
99 | |
100 LIBAO_EXTERN(win32) | |
101 | |
102 static void CALLBACK waveOutProc(HWAVEOUT hWaveOut,UINT uMsg,DWORD dwInstance, | |
103 DWORD dwParam1,DWORD dwParam2) | |
104 { | |
105 if(uMsg != WOM_DONE) | |
106 return; | |
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
|
107 if (full_buffers) { |
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
|
108 buffered_bytes-=BUFFER_SIZE; |
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
|
109 --full_buffers; |
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
|
110 } else { |
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
|
111 buffered_bytes=0; |
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
|
112 } |
7913 | 113 } |
114 | |
115 // to set/get/query special features/parameters | |
9633
12b1790038b0
64bit libao2 fix by Jens Axboe <mplayer-dev@kernel.dk>
alex
parents:
9589
diff
changeset
|
116 static int control(int cmd,void *arg) |
7913 | 117 { |
118 DWORD volume; | |
119 switch (cmd) | |
120 { | |
121 case AOCONTROL_GET_VOLUME: | |
122 { | |
123 ao_control_vol_t* vol = (ao_control_vol_t*)arg; | |
124 waveOutGetVolume(hWaveOut,&volume); | |
125 vol->left = (float)(LOWORD(volume)/655.35); | |
126 vol->right = (float)(HIWORD(volume)/655.35); | |
127 mp_msg(MSGT_AO, MSGL_DBG2,"ao_win32: volume left:%f volume right:%f\n",vol->left,vol->right); | |
128 return CONTROL_OK; | |
129 } | |
130 case AOCONTROL_SET_VOLUME: | |
131 { | |
132 ao_control_vol_t* vol = (ao_control_vol_t*)arg; | |
133 volume = MAKELONG(vol->left*655.35,vol->right*655.35); | |
134 waveOutSetVolume(hWaveOut,volume); | |
135 return CONTROL_OK; | |
136 } | |
137 } | |
138 return -1; | |
139 } | |
140 | |
141 // open & setup audio device | |
142 // return: 1=success 0=fail | |
143 static int init(int rate,int channels,int format,int flags) | |
144 { | |
13017 | 145 WAVEFORMATEXTENSIBLE wformat; |
7913 | 146 DWORD totalBufferSize = (BUFFER_SIZE + sizeof(WAVEHDR)) * BUFFER_COUNT; |
147 MMRESULT result; | |
148 unsigned char* buffer; | |
149 int i; | |
150 | |
14135 | 151 switch(format){ |
14245 | 152 case AF_FORMAT_AC3: |
153 case AF_FORMAT_S24_LE: | |
154 case AF_FORMAT_S16_LE: | |
155 case AF_FORMAT_S8: | |
14135 | 156 break; |
157 default: | |
14264 | 158 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 | 159 format=AF_FORMAT_S16_LE; |
14135 | 160 } |
7913 | 161 //fill global ao_data |
162 ao_data.channels=channels; | |
163 ao_data.samplerate=rate; | |
164 ao_data.format=format; | |
165 ao_data.bps=channels*rate; | |
14245 | 166 if(format != AF_FORMAT_U8 && format != AF_FORMAT_S8) |
7913 | 167 ao_data.bps*=2; |
168 if(ao_data.buffersize==-1) | |
169 { | |
14264 | 170 ao_data.buffersize=af_fmt2bits(format)/8; |
7913 | 171 ao_data.buffersize*= channels; |
172 ao_data.buffersize*= SAMPLESIZE; | |
173 } | |
14264 | 174 mp_msg(MSGT_AO, MSGL_V,"ao_win32: Samplerate:%iHz Channels:%i Format:%s\n",rate, channels, af_fmt2str_short(format)); |
7913 | 175 mp_msg(MSGT_AO, MSGL_V,"ao_win32: Buffersize:%d\n",ao_data.buffersize); |
176 | |
177 //fill waveformatex | |
13017 | 178 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
|
179 wformat.Format.cbSize = (channels>2)?sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX):0; |
13017 | 180 wformat.Format.nChannels = channels; |
181 wformat.Format.nSamplesPerSec = rate; | |
14245 | 182 if(format == AF_FORMAT_AC3) |
12684
47598beff93a
ac3 passthrough, initial patch by Gianluigi Tiesi <sherpya at netfarm.it>
faust3
parents:
12155
diff
changeset
|
183 { |
13017 | 184 wformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF; |
185 wformat.Format.wBitsPerSample = 16; | |
186 wformat.Format.nBlockAlign = 4; | |
12684
47598beff93a
ac3 passthrough, initial patch by Gianluigi Tiesi <sherpya at netfarm.it>
faust3
parents:
12155
diff
changeset
|
187 } |
47598beff93a
ac3 passthrough, initial patch by Gianluigi Tiesi <sherpya at netfarm.it>
faust3
parents:
12155
diff
changeset
|
188 else |
47598beff93a
ac3 passthrough, initial patch by Gianluigi Tiesi <sherpya at netfarm.it>
faust3
parents:
12155
diff
changeset
|
189 { |
13017 | 190 wformat.Format.wFormatTag = (channels>2)?WAVE_FORMAT_EXTENSIBLE:WAVE_FORMAT_PCM; |
14264 | 191 wformat.Format.wBitsPerSample = af_fmt2bits(format); |
13017 | 192 wformat.Format.nBlockAlign = wformat.Format.nChannels * (wformat.Format.wBitsPerSample >> 3); |
193 } | |
194 if(channels>2) | |
195 { | |
196 wformat.dwChannelMask = channel_mask[channels-3]; | |
197 wformat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; | |
14264 | 198 wformat.Samples.wValidBitsPerSample=af_fmt2bits(format); |
13017 | 199 } |
200 | |
201 wformat.Format.nAvgBytesPerSec = wformat.Format.nSamplesPerSec * wformat.Format.nBlockAlign; | |
7913 | 202 |
203 //open sound device | |
204 //WAVE_MAPPER always points to the default wave device on the system | |
13017 | 205 result = waveOutOpen(&hWaveOut,WAVE_MAPPER,(WAVEFORMATEX*)&wformat,(DWORD_PTR)waveOutProc,0,CALLBACK_FUNCTION|WAVE_FORMAT_DIRECT); |
7913 | 206 if(result == WAVERR_BADFORMAT) |
207 { | |
208 mp_msg(MSGT_AO, MSGL_ERR,"ao_win32: format not supported switching to default\n"); | |
13017 | 209 ao_data.channels = wformat.Format.nChannels = 2; |
210 ao_data.samplerate = wformat.Format.nSamplesPerSec = 44100; | |
14245 | 211 ao_data.format = AF_FORMAT_S16_LE; |
13017 | 212 ao_data.bps=ao_data.channels * ao_data.samplerate*2; |
213 wformat.Format.wBitsPerSample=16; | |
214 wformat.Format.wFormatTag=WAVE_FORMAT_PCM; | |
215 wformat.Format.nBlockAlign = wformat.Format.nChannels * (wformat.Format.wBitsPerSample >> 3); | |
216 wformat.Format.nAvgBytesPerSec = wformat.Format.nSamplesPerSec * wformat.Format.nBlockAlign; | |
217 ao_data.buffersize=(wformat.Format.wBitsPerSample>>3)*wformat.Format.nChannels*SAMPLESIZE; | |
218 result = waveOutOpen(&hWaveOut,WAVE_MAPPER,(WAVEFORMATEX*)&wformat,(DWORD_PTR)waveOutProc,0,CALLBACK_FUNCTION); | |
7913 | 219 } |
220 if(result != MMSYSERR_NOERROR) | |
221 { | |
222 mp_msg(MSGT_AO, MSGL_ERR,"ao_win32: unable to open wave mapper device\n"); | |
223 return 0; | |
224 } | |
225 //allocate buffer memory as one big block | |
226 buffer = malloc(totalBufferSize); | |
9589 | 227 memset(buffer,0x0,totalBufferSize); |
7913 | 228 //and setup pointers to each buffer |
229 waveBlocks = (WAVEHDR*)buffer; | |
230 buffer += sizeof(WAVEHDR) * BUFFER_COUNT; | |
231 for(i = 0; i < BUFFER_COUNT; i++) { | |
232 waveBlocks[i].lpData = buffer; | |
233 buffer += BUFFER_SIZE; | |
234 } | |
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
|
235 buf_write=0; |
83c5f9888576
ringbuffer variable intialization fix for multifile playback patch by Rune Petersen <rune.mail-list at mail.tele.dk>
faust3
parents:
13017
diff
changeset
|
236 buf_write_pos=0; |
83c5f9888576
ringbuffer variable intialization fix for multifile playback patch by Rune Petersen <rune.mail-list at mail.tele.dk>
faust3
parents:
13017
diff
changeset
|
237 full_buffers=0; |
83c5f9888576
ringbuffer variable intialization fix for multifile playback patch by Rune Petersen <rune.mail-list at mail.tele.dk>
faust3
parents:
13017
diff
changeset
|
238 buffered_bytes=0; |
7913 | 239 |
240 return 1; | |
241 } | |
242 | |
243 // close audio device | |
12145 | 244 static void uninit(int immed) |
7913 | 245 { |
12146 | 246 if(!immed)while(buffered_bytes > 0)usec_sleep(50000); |
247 else buffered_bytes=0; | |
7913 | 248 waveOutReset(hWaveOut); |
249 waveOutClose(hWaveOut); | |
250 mp_msg(MSGT_AO, MSGL_V,"waveOut device closed\n"); | |
251 free(waveBlocks); | |
252 mp_msg(MSGT_AO, MSGL_V,"buffer memory freed\n"); | |
253 } | |
254 | |
255 // stop playing and empty buffers (for seeking/pause) | |
256 static void reset() | |
257 { | |
258 waveOutReset(hWaveOut); | |
259 buf_write=0; | |
260 buf_write_pos=0; | |
261 full_buffers=0; | |
262 buffered_bytes=0; | |
263 } | |
264 | |
265 // stop playing, keep buffers (for pause) | |
266 static void audio_pause() | |
267 { | |
268 waveOutPause(hWaveOut); | |
269 } | |
270 | |
271 // resume playing, after audio_pause() | |
272 static void audio_resume() | |
273 { | |
274 waveOutRestart(hWaveOut); | |
275 } | |
276 | |
277 // return: how many bytes can be played without blocking | |
278 static int get_space() | |
279 { | |
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
|
280 return BUFFER_COUNT*BUFFER_SIZE - buffered_bytes; |
7913 | 281 } |
282 | |
283 //writes data into buffer, based on ringbuffer code in ao_sdl.c | |
284 static int write_waveOutBuffer(unsigned char* data,int len){ | |
285 WAVEHDR* current; | |
286 int len2=0; | |
287 int x; | |
288 while(len>0){ | |
289 current = &waveBlocks[buf_write]; | |
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
|
290 if(buffered_bytes==BUFFER_COUNT*BUFFER_SIZE) break; |
7913 | 291 //unprepare the header if it is prepared |
292 if(current->dwFlags & WHDR_PREPARED) | |
293 waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR)); | |
294 x=BUFFER_SIZE-buf_write_pos; | |
295 if(x>len) x=len; | |
296 memcpy(current->lpData+buf_write_pos,data+len2,x); | |
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
|
297 if(buf_write_pos==0)full_buffers++; |
7913 | 298 len2+=x; len-=x; |
299 buffered_bytes+=x; buf_write_pos+=x; | |
300 //prepare header and write data to device | |
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
|
301 current->dwBufferLength = buf_write_pos; |
7913 | 302 waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR)); |
303 waveOutWrite(hWaveOut, current, sizeof(WAVEHDR)); | |
304 | |
305 if(buf_write_pos>=BUFFER_SIZE){ //buffer is full find next | |
306 // block is full, find next! | |
307 buf_write=(buf_write+1)%BUFFER_COUNT; | |
308 buf_write_pos=0; | |
309 } | |
310 } | |
311 return len2; | |
312 } | |
313 | |
314 // plays 'len' bytes of 'data' | |
315 // it should round it down to outburst*n | |
316 // return: number of bytes played | |
317 static int play(void* data,int len,int flags) | |
318 { | |
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
|
319 len = (len/ao_data.outburst)*ao_data.outburst; |
7913 | 320 return write_waveOutBuffer(data,len); |
321 } | |
10106 | 322 |
7913 | 323 // return: delay in seconds between first and last sample in buffer |
324 static float get_delay() | |
325 { | |
326 return (float)(buffered_bytes + ao_data.buffersize)/(float)ao_data.bps; | |
327 } |