Mercurial > mplayer.hg
annotate libao2/ao_win32.c @ 10508:e2a88f1d47f6
BBC .rm fix, based on patch by Balatoni Denes <pnis@coder.hu>
author | arpi |
---|---|
date | Sat, 02 Aug 2003 18:45:24 +0000 |
parents | b5b7b2f4f069 |
children | 6e580b901205 |
rev | line source |
---|---|
7913 | 1 /****************************************************************************** |
2 * ao_win32.c: Windows waveOut interface for MPlayer | |
3 * Copyright (c) 2002 Sascha Sommer <saschasommer@freenet.de>. | |
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 | |
26 #include "afmt.h" | |
27 #include "audio_out.h" | |
28 #include "audio_out_internal.h" | |
29 #include "../mp_msg.h" | |
30 #include "../libvo/fastmemcpy.h" | |
31 | |
32 #define SAMPLESIZE 1024 | |
33 #define BUFFER_SIZE 4096 | |
34 #define BUFFER_COUNT 16 | |
35 | |
36 | |
37 static WAVEHDR* waveBlocks; //pointer to our ringbuffer memory | |
38 static HWAVEOUT hWaveOut; //handle to the waveout device | |
39 static DWORD restoredvolume; //saves the volume to restore after playing | |
40 static unsigned int buf_write=0; | |
41 static unsigned int buf_write_pos=0; | |
42 static int full_buffers=0; | |
43 static int buffered_bytes=0; | |
44 | |
45 | |
46 static ao_info_t info = | |
47 { | |
48 "Windows waveOut audio output", | |
49 "win32", | |
50 "Sascha Sommer <saschasommer@freenet.de>", | |
51 "" | |
52 }; | |
53 | |
54 LIBAO_EXTERN(win32) | |
55 | |
56 static void CALLBACK waveOutProc(HWAVEOUT hWaveOut,UINT uMsg,DWORD dwInstance, | |
57 DWORD dwParam1,DWORD dwParam2) | |
58 { | |
59 if(uMsg != WOM_DONE) | |
60 return; | |
61 if(full_buffers==0) return; //no more data buffered! | |
8657 | 62 buffered_bytes-=BUFFER_SIZE; |
7913 | 63 --full_buffers; |
64 } | |
65 | |
66 // to set/get/query special features/parameters | |
9633
12b1790038b0
64bit libao2 fix by Jens Axboe <mplayer-dev@kernel.dk>
alex
parents:
9589
diff
changeset
|
67 static int control(int cmd,void *arg) |
7913 | 68 { |
69 DWORD volume; | |
70 switch (cmd) | |
71 { | |
72 case AOCONTROL_GET_VOLUME: | |
73 { | |
74 ao_control_vol_t* vol = (ao_control_vol_t*)arg; | |
75 waveOutGetVolume(hWaveOut,&volume); | |
76 vol->left = (float)(LOWORD(volume)/655.35); | |
77 vol->right = (float)(HIWORD(volume)/655.35); | |
78 mp_msg(MSGT_AO, MSGL_DBG2,"ao_win32: volume left:%f volume right:%f\n",vol->left,vol->right); | |
79 return CONTROL_OK; | |
80 } | |
81 case AOCONTROL_SET_VOLUME: | |
82 { | |
83 ao_control_vol_t* vol = (ao_control_vol_t*)arg; | |
84 volume = MAKELONG(vol->left*655.35,vol->right*655.35); | |
85 waveOutSetVolume(hWaveOut,volume); | |
86 return CONTROL_OK; | |
87 } | |
88 } | |
89 return -1; | |
90 } | |
91 | |
92 // open & setup audio device | |
93 // return: 1=success 0=fail | |
94 static int init(int rate,int channels,int format,int flags) | |
95 { | |
96 WAVEFORMATEX wformat; | |
97 DWORD totalBufferSize = (BUFFER_SIZE + sizeof(WAVEHDR)) * BUFFER_COUNT; | |
98 MMRESULT result; | |
99 unsigned char* buffer; | |
100 int i; | |
101 | |
102 //fill global ao_data | |
103 ao_data.channels=channels; | |
104 ao_data.samplerate=rate; | |
105 ao_data.format=format; | |
106 ao_data.bps=channels*rate; | |
107 if(format != AFMT_U8 && format != AFMT_S8) | |
108 ao_data.bps*=2; | |
109 if(ao_data.buffersize==-1) | |
110 { | |
111 ao_data.buffersize=audio_out_format_bits(format)/8; | |
112 ao_data.buffersize*= channels; | |
113 ao_data.buffersize*= SAMPLESIZE; | |
114 } | |
115 mp_msg(MSGT_AO, MSGL_V,"ao_win32: Samplerate:%iHz Channels:%i Format:%s\n",rate, channels, audio_out_format_name(format)); | |
116 mp_msg(MSGT_AO, MSGL_V,"ao_win32: Buffersize:%d\n",ao_data.buffersize); | |
117 | |
118 //fill waveformatex | |
119 ZeroMemory( &wformat, sizeof(WAVEFORMATEX)); | |
120 wformat.cbSize = 0; /* size of _extra_ info */ | |
121 wformat.wFormatTag = WAVE_FORMAT_PCM; | |
122 wformat.nChannels = channels; | |
123 wformat.nSamplesPerSec = rate; | |
124 wformat.wBitsPerSample = audio_out_format_bits(format); | |
125 wformat.nBlockAlign = wformat.nChannels * (wformat.wBitsPerSample >> 3); | |
126 wformat.nAvgBytesPerSec = wformat.nSamplesPerSec * wformat.nBlockAlign; | |
127 | |
128 //open sound device | |
129 //WAVE_MAPPER always points to the default wave device on the system | |
130 result = waveOutOpen(&hWaveOut,WAVE_MAPPER,&wformat,(DWORD_PTR)waveOutProc,0,CALLBACK_FUNCTION); | |
131 if(result == WAVERR_BADFORMAT) | |
132 { | |
133 mp_msg(MSGT_AO, MSGL_ERR,"ao_win32: format not supported switching to default\n"); | |
134 ao_data.channels = wformat.nChannels = 2; | |
135 ao_data.samplerate = wformat.nSamplesPerSec = 44100; | |
136 ao_data.format = AFMT_S16_LE; | |
137 ao_data.bps=ao_data.channels * ao_data.samplerate; | |
138 ao_data.buffersize=wformat.wBitsPerSample=16; | |
139 wformat.nBlockAlign = wformat.nChannels * (wformat.wBitsPerSample >> 3); | |
140 wformat.nAvgBytesPerSec = wformat.nSamplesPerSec * wformat.nBlockAlign; | |
141 ao_data.buffersize/=8; | |
142 ao_data.buffersize*= ao_data.channels; | |
143 ao_data.buffersize*= SAMPLESIZE; | |
144 result = waveOutOpen(&hWaveOut,WAVE_MAPPER,&wformat,(DWORD_PTR)waveOutProc,0,CALLBACK_FUNCTION); | |
145 } | |
146 if(result != MMSYSERR_NOERROR) | |
147 { | |
148 mp_msg(MSGT_AO, MSGL_ERR,"ao_win32: unable to open wave mapper device\n"); | |
149 return 0; | |
150 } | |
151 //save volume | |
152 waveOutGetVolume(hWaveOut,&restoredvolume); | |
153 //allocate buffer memory as one big block | |
154 buffer = malloc(totalBufferSize); | |
9589 | 155 memset(buffer,0x0,totalBufferSize); |
7913 | 156 //and setup pointers to each buffer |
157 waveBlocks = (WAVEHDR*)buffer; | |
158 buffer += sizeof(WAVEHDR) * BUFFER_COUNT; | |
159 for(i = 0; i < BUFFER_COUNT; i++) { | |
160 waveBlocks[i].dwBufferLength = BUFFER_SIZE; | |
161 waveBlocks[i].lpData = buffer; | |
162 buffer += BUFFER_SIZE; | |
163 } | |
164 | |
165 return 1; | |
166 } | |
167 | |
168 // close audio device | |
169 static void uninit() | |
170 { | |
171 waveOutSetVolume(hWaveOut,restoredvolume); //restore volume | |
172 waveOutReset(hWaveOut); | |
173 waveOutClose(hWaveOut); | |
174 mp_msg(MSGT_AO, MSGL_V,"waveOut device closed\n"); | |
175 full_buffers=0; | |
176 free(waveBlocks); | |
177 mp_msg(MSGT_AO, MSGL_V,"buffer memory freed\n"); | |
178 } | |
179 | |
180 // stop playing and empty buffers (for seeking/pause) | |
181 static void reset() | |
182 { | |
183 waveOutReset(hWaveOut); | |
184 buf_write=0; | |
185 buf_write_pos=0; | |
186 full_buffers=0; | |
187 buffered_bytes=0; | |
188 } | |
189 | |
190 // stop playing, keep buffers (for pause) | |
191 static void audio_pause() | |
192 { | |
193 waveOutPause(hWaveOut); | |
194 } | |
195 | |
196 // resume playing, after audio_pause() | |
197 static void audio_resume() | |
198 { | |
199 waveOutRestart(hWaveOut); | |
200 } | |
201 | |
202 // return: how many bytes can be played without blocking | |
203 static int get_space() | |
204 { | |
205 return (BUFFER_COUNT-full_buffers)*BUFFER_SIZE - buf_write_pos; | |
206 } | |
207 | |
208 //writes data into buffer, based on ringbuffer code in ao_sdl.c | |
209 static int write_waveOutBuffer(unsigned char* data,int len){ | |
210 WAVEHDR* current; | |
211 int len2=0; | |
212 int x; | |
213 while(len>0){ | |
214 current = &waveBlocks[buf_write]; | |
215 if(full_buffers==BUFFER_COUNT) break; | |
216 //unprepare the header if it is prepared | |
217 if(current->dwFlags & WHDR_PREPARED) | |
218 waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR)); | |
219 x=BUFFER_SIZE-buf_write_pos; | |
220 if(x>len) x=len; | |
221 memcpy(current->lpData+buf_write_pos,data+len2,x); | |
222 len2+=x; len-=x; | |
223 buffered_bytes+=x; buf_write_pos+=x; | |
224 //prepare header and write data to device | |
225 waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR)); | |
226 waveOutWrite(hWaveOut, current, sizeof(WAVEHDR)); | |
227 | |
228 if(buf_write_pos>=BUFFER_SIZE){ //buffer is full find next | |
229 // block is full, find next! | |
230 buf_write=(buf_write+1)%BUFFER_COUNT; | |
231 ++full_buffers; | |
232 buf_write_pos=0; | |
233 } | |
234 } | |
235 return len2; | |
236 } | |
237 | |
238 // plays 'len' bytes of 'data' | |
239 // it should round it down to outburst*n | |
240 // return: number of bytes played | |
241 static int play(void* data,int len,int flags) | |
242 { | |
243 return write_waveOutBuffer(data,len); | |
244 } | |
10106 | 245 |
7913 | 246 // return: delay in seconds between first and last sample in buffer |
247 static float get_delay() | |
248 { | |
249 return (float)(buffered_bytes + ao_data.buffersize)/(float)ao_data.bps; | |
250 } |