2 * MPEG-PES audio output driver
4 * This file is part of MPlayer.
6 * MPlayer is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * MPlayer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <sys/types.h>
33 #include "audio_out.h"
34 #include "audio_out_internal.h"
36 #include "libaf/af_format.h"
37 #include "libmpdemux/mpeg_packetizer.h"
38 #include "subopt-helper.h"
44 #include <sys/ioctl.h>
45 #include <linux/dvb/audio.h>
46 audio_mixer_t dvb_mixer
={255,255};
52 extern int vo_mpegpes_fd
;
53 int ao_mpegpes_fd
= -1;
57 static const ao_info_t info
=
62 "MPEG-PES audio output",
72 // to set/get/query special features/parameters
73 static int control(int cmd
,void *arg
){
76 case AOCONTROL_GET_VOLUME
:
77 if(ao_mpegpes_fd
>= 0){
78 ((ao_control_vol_t
*)(arg
))->left
=dvb_mixer
.volume_left
/2.56;
79 ((ao_control_vol_t
*)(arg
))->right
=dvb_mixer
.volume_right
/2.56;
83 case AOCONTROL_SET_VOLUME
:
84 if(ao_mpegpes_fd
>= 0){
85 dvb_mixer
.volume_left
=((ao_control_vol_t
*)(arg
))->left
*2.56;
86 dvb_mixer
.volume_right
=((ao_control_vol_t
*)(arg
))->right
*2.56;
87 if(dvb_mixer
.volume_left
>255) dvb_mixer
.volume_left
=255;
88 if(dvb_mixer
.volume_right
>255) dvb_mixer
.volume_right
=255;
89 // printf("Setting DVB volume: %d ; %d \n",dvb_mixer.volume_left,dvb_mixer.volume_right);
90 if ( (ioctl(vo_mpegpes_fd
,AUDIO_SET_MIXER
, &dvb_mixer
) < 0)){
91 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO MPEGPES] DVB audio set mixer failed: %s.\n",
100 return CONTROL_UNKNOWN
;
104 static int freq_id
=0;
107 static int init_device(int card
)
110 sprintf(ao_file
, "/dev/dvb/adapter%d/audio0", card
);
111 mp_msg(MSGT_VO
,MSGL_INFO
, "Opening %s\n", ao_file
);
112 if((ao_mpegpes_fd
= open(ao_file
,O_RDWR
|O_NONBLOCK
)) < 0)
114 mp_msg(MSGT_VO
, MSGL_ERR
, "DVB AUDIO DEVICE: %s\n", strerror(errno
));
117 if( (ioctl(ao_mpegpes_fd
, AUDIO_SELECT_SOURCE
, AUDIO_SOURCE_MEMORY
) < 0))
119 mp_msg(MSGT_VO
, MSGL_ERR
, "DVB AUDIO SELECT SOURCE: %s\n", strerror(errno
));
122 if((ioctl(ao_mpegpes_fd
, AUDIO_PLAY
) < 0))
124 mp_msg(MSGT_VO
, MSGL_ERR
, "DVB AUDIO PLAY: %s\n", strerror(errno
));
127 if((ioctl(ao_mpegpes_fd
, AUDIO_SET_AV_SYNC
, true) < 0))
129 mp_msg(MSGT_VO
, MSGL_ERR
, "DVB AUDIO SET AV SYNC: %s\n", strerror(errno
));
132 //FIXME: in vo_mpegpes audio was initialized as MUTEd
133 if((ioctl(ao_mpegpes_fd
, AUDIO_SET_MUTE
, false) < 0))
135 mp_msg(MSGT_VO
, MSGL_ERR
, "DVB AUDIO SET MUTE: %s\n", strerror(errno
));
138 return ao_mpegpes_fd
;
140 close(ao_mpegpes_fd
);
146 static int preinit(const char *arg
)
149 char *ao_file
= NULL
;
151 const opt_t subopts
[] = {
152 {"card", OPT_ARG_INT
, &card
, NULL
},
153 {"file", OPT_ARG_MSTRZ
, &ao_file
, NULL
},
157 if(subopt_parse(ao_subdevice
, subopts
) != 0)
159 mp_msg(MSGT_VO
, MSGL_ERR
, "AO_MPEGPES, Unrecognized options\n");
164 //search the first usable card
169 sprintf(file
, "/dev/dvb/adapter%d/audio0", n
);
170 if(access(file
, F_OK
| W_OK
)==0)
177 if((card
< 1) || (card
> 4))
179 mp_msg(MSGT_VO
, MSGL_ERR
, "DVB card number must be between 1 and 4\n");
186 return init_device(card
);
189 return vo_mpegpes_fd
; //video fd
192 ao_mpegpes_fd
= open(ao_file
, O_WRONLY
| O_CREAT
, 0666);
193 if(ao_mpegpes_fd
< 0)
195 mp_msg(MSGT_VO
, MSGL_ERR
, "ao_mpegpes: %s\n", strerror(errno
));
198 return ao_mpegpes_fd
;
201 static int my_ao_write(const unsigned char* data
,int len
){
205 struct pollfd pfd
[NFD
];
207 pfd
[0].fd
= ao_mpegpes_fd
;
208 pfd
[0].events
= POLLOUT
;
212 if(pfd
[0].revents
& POLLOUT
){
213 int ret
= write(ao_mpegpes_fd
, data
, len
);
215 mp_msg(MSGT_VO
, MSGL_ERR
, "ao_mpegpes write: %s\n", strerror(errno
));
226 if(ao_mpegpes_fd
< 0) return 0; // no file
227 write(ao_mpegpes_fd
, data
, len
); // write to file
233 // open & setup audio device
234 // return: 1=success 0=fail
235 static int init(int rate
,int channels
,int format
,int flags
){
236 if(preinit(NULL
)<0) return 0;
239 ao_data
.outburst
=2000;
241 case AF_FORMAT_S16_BE
:
242 case AF_FORMAT_MPEG2
:
243 case AF_FORMAT_AC3_BE
:
244 ao_data
.format
=format
;
246 case AF_FORMAT_AC3_LE
:
247 ao_data
.format
=AF_FORMAT_AC3_BE
;
250 ao_data
.format
=AF_FORMAT_S16_BE
;
254 case 48000: freq_id
=0;break;
255 case 96000: freq_id
=1;break;
256 case 44100: freq_id
=2;break;
257 case 32000: freq_id
=3;break;
259 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO MPEGPES] %d Hz not supported, try to resample.\n", rate
);
261 if(rate
>48000) rate
=96000; else
262 if(rate
>44100) rate
=48000; else
263 if(rate
>32000) rate
=44100; else
267 rate
=48000; freq_id
=0;
271 ao_data
.bps
=rate
*2*2;
272 freq
=ao_data
.samplerate
=rate
;
277 // close audio device
278 static void uninit(int immed
){
279 if (ao_mpegpes_fd
>= 0)
280 close(ao_mpegpes_fd
);
284 // stop playing and empty buffers (for seeking/pause)
285 static void reset(void){
289 // stop playing, keep buffers (for pause)
290 static void audio_pause(void)
292 // for now, just call reset();
296 // resume playing, after audio_pause()
297 static void audio_resume(void)
303 // return: how many bytes can be played without blocking
304 static int get_space(void){
305 float x
=(float)(vo_pts
-ao_data
.brokenpts
)/90000.0;
307 //FIXME: is it correct?
308 if(vo_mpegpes_fd
< 0) return 32000; //not using -vo mpegpes
309 // printf("vo_pts: %5.3f ao_pts: %5.3f\n",vo_pts/90000.0,ao_data.brokenpts/90000.0);
311 y
=freq
*4*x
;y
/=ao_data
.outburst
;y
*=ao_data
.outburst
;
313 // printf("diff: %5.3f -> %d \n",x,y);
317 // plays 'len' bytes of 'data'
318 // it should round it down to outburst*n
319 // return: number of bytes played
320 static int play(void* data
,int len
,int flags
){
321 // printf("\nao_mpegpes: play(%d) freq=%d\n",len,freq_id);
322 if(ao_data
.format
==AF_FORMAT_MPEG2
)
323 send_mpeg_pes_packet (data
, len
, 0x1C0, ao_data
.brokenpts
, 1, my_ao_write
);
325 // if(len>2000) len=2000;
326 // printf("ao_mpegpes: len=%d \n",len);
327 send_mpeg_lpcm_packet(data
, len
, 0xA0, ao_data
.brokenpts
, freq_id
, my_ao_write
);
332 // return: delay in seconds between first and last sample in buffer
333 static float get_delay(void){