2 * Copyright (C) 2002-2004 Balatoni Denes and A'rpi
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.
21 // This is not reentrant because of global static variables, but most of
22 // the plugins are not reentrant either perhaps
36 #include "libaf/af_format.h"
37 #include "stream/stream.h"
44 #define XMMS_PACKETSIZE 65536 // some plugins won't play if this is too small
46 #include "demux_xmms_plugin.h"
49 uint64_t spos
; // stream position in number of output bytes from 00:00:00
53 static pthread_mutex_t xmms_mutex
;
54 static int format
= 0x1; // Raw PCM
55 static char xmms_audiobuffer
[XMMS_PACKETSIZE
];
56 static uint32_t xmms_channels
;
57 static uint32_t xmms_samplerate
;
58 static uint32_t xmms_afmt
;
59 static int xmms_length
;
60 static char *xmms_title
=NULL
;
61 static uint32_t xmms_audiopos
=0;
62 static int xmms_playing
=0;
63 static xmms_priv_t
*xmms_priv
=NULL
;
64 static uint32_t xmms_byterate
;
65 static int64_t xmms_flushto
=-1;
67 // =========== mplayer xmms outputplugin stuff ==============
69 static void disk_close(void) {}
70 static void disk_pause(short p
) {}
71 static void disk_init(void) {}
73 static void disk_flush(int time
) {
74 if (xmms_priv
) xmms_flushto
=time
*((long long) xmms_byterate
)/1000LL;
77 static int disk_free(void) { // vqf plugin sends more than it should
78 return XMMS_PACKETSIZE
- xmms_audiopos
< XMMS_PACKETSIZE
/ 4 ?
79 0 : XMMS_PACKETSIZE
- xmms_audiopos
- XMMS_PACKETSIZE
/ 4;
82 static int disk_playing(void) {
83 return 0; //?? maybe plugins wait on exit until oplugin is not playing?
86 static int disk_get_output_time(void) {
88 return xmms_priv
->spos
*1000LL/((long long)xmms_byterate
);
92 static int disk_open(AFormat fmt
, int rate
, int nch
) {
95 xmms_afmt
=AF_FORMAT_U8
;
98 xmms_afmt
=AF_FORMAT_S8
;
101 xmms_afmt
=AF_FORMAT_U16_LE
;
105 xmms_afmt
=AF_FORMAT_U16_BE
;
107 xmms_afmt
=AF_FORMAT_U16_LE
;
111 xmms_afmt
=AF_FORMAT_U16_BE
;
114 xmms_afmt
=AF_FORMAT_S16_NE
;
117 xmms_afmt
=AF_FORMAT_S16_LE
;
120 xmms_afmt
=AF_FORMAT_S16_BE
;
123 xmms_samplerate
=rate
;
128 static void disk_write(void *ptr
, int length
) {
129 if (!xmms_playing
) return;
130 pthread_mutex_lock(&xmms_mutex
);
131 if (xmms_flushto
!=-1) {
132 xmms_priv
->spos
=xmms_flushto
;
136 xmms_priv
->spos
+= length
;
137 memcpy(&xmms_audiobuffer
[xmms_audiopos
],ptr
,length
);
138 xmms_audiopos
+=length
;
139 pthread_mutex_unlock(&xmms_mutex
);
142 static OutputPlugin xmms_output_plugin
=
146 "MPlayer output interface plugin ", /* Description */
149 NULL
, /* configure */
150 NULL
, /* get_volume */
151 NULL
, /* set_volume */
159 disk_get_output_time
,
160 disk_get_output_time
//we pretend that everything written is played at once
163 // ==================== mplayer xmms inputplugin helper stuff =================
165 static InputPlugin
* input_plugins
[100];
166 static int no_plugins
=0;
168 /* Dummy functions */
169 static InputVisType
input_get_vis_type(void){return 0;}
170 static void input_add_vis_pcm(int time
, AFormat fmt
, int nch
, int length
,
172 static void input_set_info_text(char * text
){}
173 char *xmms_get_gentitle_format(void){ return ""; }
174 /* Dummy functions END*/
176 static void input_set_info(char* title
,int length
, int rate
, int freq
, int nch
)
181 static void init_plugins_from_dir(const char *plugin_dir
){
185 dir
= opendir(plugin_dir
);
188 while ((ent
= readdir(dir
)) != NULL
){
189 char filename
[strlen(plugin_dir
)+strlen(ent
->d_name
)+4];
191 sprintf(filename
, "%s/%s", plugin_dir
, ent
->d_name
);
192 handle
=dlopen(filename
, RTLD_NOW
);
195 gpi
=dlsym(handle
, "get_iplugin_info");
197 InputPlugin
*p
=gpi();
198 mp_msg(MSGT_DEMUX
, MSGL_INFO
, MSGTR_MPDEMUX_XMMS_FoundPlugin
,
199 ent
->d_name
,p
->description
);
201 p
->filename
= strdup(filename
);
202 p
->get_vis_type
= input_get_vis_type
;
203 p
->add_vis_pcm
= input_add_vis_pcm
;
204 p
->set_info
= input_set_info
;
205 p
->set_info_text
= input_set_info_text
;
206 if(p
->init
) p
->init();
207 input_plugins
[no_plugins
++]=p
;
215 static void init_plugins(void) {
220 home
= getenv("HOME");
222 char xmms_home
[strlen(home
) + 15];
223 sprintf(xmms_home
, "%s/.xmms/Plugins", home
);
224 init_plugins_from_dir(xmms_home
);
227 init_plugins_from_dir(XMMS_INPUT_PLUGIN_DIR
);
230 static void cleanup_plugins(void) {
233 mp_msg(MSGT_DEMUX
, MSGL_INFO
, MSGTR_MPDEMUX_XMMS_ClosingPlugin
,
234 input_plugins
[no_plugins
]->filename
);
235 if(input_plugins
[no_plugins
]->cleanup
)
236 input_plugins
[no_plugins
]->cleanup();
237 dlclose(input_plugins
[no_plugins
]->handle
);
241 // ============================ mplayer demuxer stuff ===============
243 static int demux_xmms_open(demuxer_t
* demuxer
) {
244 InputPlugin
* ip
= NULL
;
245 sh_audio_t
* sh_audio
;
250 if (xmms_priv
) return 0; // as I said, it's not reentrant :)
252 for(i
=0;i
<no_plugins
;i
++){
253 if (input_plugins
[i
]->is_our_file(demuxer
->stream
->url
)){
254 ip
=input_plugins
[i
]; break;
257 if(!ip
) return 0; // no plugin to handle this...
259 pthread_mutex_init(&xmms_mutex
,NULL
);
261 xmms_priv
=priv
=malloc(sizeof(xmms_priv_t
));
262 memset(priv
,0,sizeof(xmms_priv_t
));
265 memset(xmms_audiobuffer
,0,XMMS_PACKETSIZE
);
268 sh_audio
= new_sh_audio(demuxer
,0);
269 sh_audio
->wf
= w
= malloc(sizeof(WAVEFORMATEX
));
270 w
->wFormatTag
= sh_audio
->format
= format
;
272 demuxer
->movi_start
= 0;
273 demuxer
->movi_end
= 100;
274 demuxer
->audio
->id
= 0;
275 demuxer
->audio
->sh
= sh_audio
;
277 sh_audio
->ds
= demuxer
->audio
;
279 xmms_output_plugin
.init();
280 ip
->output
= &xmms_output_plugin
;
282 ip
->play_file(demuxer
->stream
->url
);
283 if (ip
->get_song_info
)
284 ip
->get_song_info(demuxer
->stream
->url
,&xmms_title
,&xmms_length
);
285 if (xmms_length
<=0) demuxer
->seekable
=0;
287 mp_msg(MSGT_DEMUX
,MSGL_INFO
,MSGTR_MPDEMUX_XMMS_WaitForStart
,
288 demuxer
->stream
->url
);
289 while (xmms_channels
==0) {
291 if(ip
->get_time()<0) return 0;
293 sh_audio
->sample_format
= xmms_afmt
;
295 case AF_FORMAT_S16_LE
:
296 case AF_FORMAT_S16_BE
:
297 case AF_FORMAT_U16_LE
:
298 case AF_FORMAT_U16_BE
:
299 sh_audio
->samplesize
= 2;
302 sh_audio
->samplesize
= 1;
304 w
->wBitsPerSample
= sh_audio
->samplesize
*8;
305 w
->nChannels
= sh_audio
->channels
= xmms_channels
;
306 w
->nSamplesPerSec
= sh_audio
->samplerate
= xmms_samplerate
;
307 xmms_byterate
= w
->nAvgBytesPerSec
=
308 xmms_samplerate
*sh_audio
->channels
*sh_audio
->samplesize
;
309 w
->nBlockAlign
= sh_audio
->samplesize
*sh_audio
->channels
;
312 return DEMUXER_TYPE_XMMS
;
315 static int demux_xmms_fill_buffer(demuxer_t
* demuxer
, demux_stream_t
*ds
) {
316 sh_audio_t
*sh_audio
= demuxer
->audio
->sh
;
317 xmms_priv_t
*priv
=demuxer
->priv
;
320 if (xmms_length
<=0) demuxer
->seekable
=0;
321 else demuxer
->seekable
=1;
323 while (xmms_audiopos
<XMMS_PACKETSIZE
/2) {
324 if((priv
->ip
->get_time()<0) || !xmms_playing
)
329 pthread_mutex_lock(&xmms_mutex
);
330 dp
= new_demux_packet(XMMS_PACKETSIZE
/2);
331 dp
->pts
= priv
->spos
/ sh_audio
->wf
->nAvgBytesPerSec
;
332 ds
->pos
= priv
->spos
;
334 memcpy(dp
->buffer
,xmms_audiobuffer
,XMMS_PACKETSIZE
/2);
335 memcpy(xmms_audiobuffer
,&xmms_audiobuffer
[XMMS_PACKETSIZE
/2],
336 xmms_audiopos
-XMMS_PACKETSIZE
/2);
337 xmms_audiopos
-=XMMS_PACKETSIZE
/2;
338 pthread_mutex_unlock(&xmms_mutex
);
340 ds_add_packet(ds
,dp
);
345 static void demux_xmms_seek(demuxer_t
*demuxer
,float rel_seek_secs
,
346 float audio_delay
,int flags
){
347 stream_t
* s
= demuxer
->stream
;
348 sh_audio_t
* sh_audio
= demuxer
->audio
->sh
;
349 xmms_priv_t
*priv
=demuxer
->priv
;
352 if(priv
->ip
->get_time()<0) return;
354 pos
= (flags
& SEEK_ABSOLUTE
) ? 0 : priv
->spos
/ sh_audio
->wf
->nAvgBytesPerSec
;
355 if (flags
& SEEK_FACTOR
)
356 pos
+= rel_seek_secs
*xmms_length
;
361 if (pos
>=xmms_length
) pos
=xmms_length
-1;
363 priv
->ip
->seek((pos
<0)?0:pos
);
364 priv
->spos
=pos
* sh_audio
->wf
->nAvgBytesPerSec
;
367 static void demux_close_xmms(demuxer_t
* demuxer
) {
368 xmms_priv_t
*priv
=demuxer
->priv
;
370 xmms_audiopos
=0; // xmp on exit waits until buffer is free enough
372 if (priv
->ip
!= NULL
)
374 free(priv
); xmms_priv
=demuxer
->priv
=NULL
;
379 static int demux_xmms_control(demuxer_t
*demuxer
,int cmd
, void *arg
){
380 demux_stream_t
*d_video
=demuxer
->video
;
381 sh_audio_t
*sh_audio
=demuxer
->audio
->sh
;
382 xmms_priv_t
*priv
=demuxer
->priv
;
385 case DEMUXER_CTRL_GET_TIME_LENGTH
:
386 if (xmms_length
<=0) return DEMUXER_CTRL_DONTKNOW
;
387 *((double *)arg
)=(double)xmms_length
/1000;
388 return DEMUXER_CTRL_GUESS
;
390 case DEMUXER_CTRL_GET_PERCENT_POS
:
392 return DEMUXER_CTRL_DONTKNOW
;
393 *((int *)arg
)=(int)( priv
->spos
/
394 (float)(sh_audio
->wf
->nAvgBytesPerSec
) / xmms_length
);
395 return DEMUXER_CTRL_OK
;
398 return DEMUXER_CTRL_NOTIMPL
;
403 const demuxer_desc_t demuxer_desc_xmms
= {
407 "Balatoni Denes, A'rpi",
408 "requires XMMS plugins",
410 0, // safe autodetect
412 demux_xmms_fill_buffer
,