1 // This is not reentrant because of global static variables, but most of
2 // the plugins are not reentrant either perhaps
16 #include "libaf/af_format.h"
24 #define XMMS_PACKETSIZE 65536 // some plugins won't play if this is too small
26 #include "demux_xmms_plugin.h"
29 uint64_t spos
; // stream position in number of output bytes from 00:00:00
33 static pthread_mutex_t xmms_mutex
;
34 static int format
= 0x1; // Raw PCM
35 static char xmms_audiobuffer
[XMMS_PACKETSIZE
];
36 static uint32_t xmms_channels
;
37 static uint32_t xmms_samplerate
;
38 static uint32_t xmms_afmt
;
39 static int xmms_length
;
40 static char *xmms_title
=NULL
;
41 static uint32_t xmms_audiopos
=0;
42 static int xmms_playing
=0;
43 static xmms_priv_t
*xmms_priv
=NULL
;
44 static uint32_t xmms_byterate
;
45 static int64_t xmms_flushto
=-1;
47 // =========== mplayer xmms outputplugin stuff ==============
49 static void disk_close(void) {}
50 static void disk_pause(short p
) {}
51 static void disk_init(void) {}
53 static void disk_flush(int time
) {
54 if (xmms_priv
) xmms_flushto
=time
*((long long) xmms_byterate
)/1000LL;
57 static int disk_free(void) { // vqf plugin sends more than it should
58 return (XMMS_PACKETSIZE
-xmms_audiopos
<XMMS_PACKETSIZE
/4 ? 0:XMMS_PACKETSIZE
-xmms_audiopos
-XMMS_PACKETSIZE
/4);
61 static int disk_playing(void) {
62 return 0; //?? maybe plugins wait on exit until oplugin is not playing?
65 static int disk_get_output_time(void) {
67 return xmms_priv
->spos
*1000LL/((long long)xmms_byterate
);
71 static int disk_open(AFormat fmt
, int rate
, int nch
) {
74 xmms_afmt
=AF_FORMAT_U8
;
77 xmms_afmt
=AF_FORMAT_S8
;
80 xmms_afmt
=AF_FORMAT_U16_LE
;
84 xmms_afmt
=AF_FORMAT_U16_BE
;
86 xmms_afmt
=AF_FORMAT_U16_LE
;
90 xmms_afmt
=AF_FORMAT_U16_BE
;
93 xmms_afmt
=AF_FORMAT_S16_NE
;
96 xmms_afmt
=AF_FORMAT_S16_LE
;
99 xmms_afmt
=AF_FORMAT_S16_BE
;
102 xmms_samplerate
=rate
;
107 static void disk_write(void *ptr
, int length
) {
108 if (!xmms_playing
) return;
109 pthread_mutex_lock(&xmms_mutex
);
110 if (xmms_flushto
!=-1) {
111 xmms_priv
->spos
=xmms_flushto
;
115 xmms_priv
->spos
+= length
;
116 memcpy(&xmms_audiobuffer
[xmms_audiopos
],ptr
,length
);
117 xmms_audiopos
+=length
;
118 pthread_mutex_unlock(&xmms_mutex
);
121 static OutputPlugin xmms_output_plugin
=
125 "MPlayer output interface plugin ", /* Description */
128 NULL
, /* configure */
129 NULL
, /* get_volume */
130 NULL
, /* set_volume */
138 disk_get_output_time
,
139 disk_get_output_time
//we pretend that everything written is played at once
142 // ==================== mplayer xmms inputplugin helper stuff =================
144 static InputPlugin
* input_plugins
[100];
145 static int no_plugins
=0;
147 /* Dummy functions */
148 static InputVisType
input_get_vis_type(){return 0;}
149 static void input_add_vis_pcm(int time
, AFormat fmt
, int nch
, int length
, void *ptr
){}
150 static void input_set_info_text(char * text
){}
151 char *xmms_get_gentitle_format(){ return ""; }
152 /* Dummy functions END*/
154 static void input_set_info(char* title
,int length
, int rate
, int freq
, int nch
){
158 static void init_plugins(){
164 dir
= opendir(XMMS_INPUT_PLUGIN_DIR
);
167 while ((ent
= readdir(dir
)) != NULL
){
168 char filename
[strlen(XMMS_INPUT_PLUGIN_DIR
)+strlen(ent
->d_name
)+4];
170 sprintf(filename
,XMMS_INPUT_PLUGIN_DIR
"/%s",ent
->d_name
);
171 handle
=dlopen(filename
, RTLD_NOW
);
174 gpi
=dlsym(handle
, "get_iplugin_info");
176 InputPlugin
*p
=gpi();
177 mp_msg(MSGT_DEMUX
, MSGL_INFO
, MSGTR_MPDEMUX_XMMS_FoundPlugin
,ent
->d_name
,p
->description
);
179 p
->filename
= strdup(filename
);
180 p
->get_vis_type
= input_get_vis_type
;
181 p
->add_vis_pcm
= input_add_vis_pcm
;
182 p
->set_info
= input_set_info
;
183 p
->set_info_text
= input_set_info_text
;
184 if(p
->init
) p
->init();
185 input_plugins
[no_plugins
++]=p
;
193 static void cleanup_plugins(){
196 mp_msg(MSGT_DEMUX
, MSGL_INFO
, MSGTR_MPDEMUX_XMMS_ClosingPlugin
,input_plugins
[no_plugins
]->filename
);
197 if(input_plugins
[no_plugins
]->cleanup
)
198 input_plugins
[no_plugins
]->cleanup();
199 dlclose(input_plugins
[no_plugins
]->handle
);
203 // ============================ mplayer demuxer stuff ===============
205 static int demux_xmms_open(demuxer_t
* demuxer
) {
206 InputPlugin
* ip
= NULL
;
207 sh_audio_t
* sh_audio
;
212 if (xmms_priv
) return 0; // as I said, it's not reentrant :)
214 for(i
=0;i
<no_plugins
;i
++){
215 if (input_plugins
[i
]->is_our_file(demuxer
->stream
->url
)){
216 ip
=input_plugins
[i
]; break;
219 if(!ip
) return 0; // no plugin to handle this...
221 pthread_mutex_init(&xmms_mutex
,NULL
);
223 xmms_priv
=priv
=malloc(sizeof(xmms_priv_t
));
224 memset(priv
,0,sizeof(xmms_priv_t
));
227 memset(xmms_audiobuffer
,0,XMMS_PACKETSIZE
);
230 sh_audio
= new_sh_audio(demuxer
,0);
231 sh_audio
->wf
= w
= malloc(sizeof(WAVEFORMATEX
));
232 w
->wFormatTag
= sh_audio
->format
= format
;
234 demuxer
->movi_start
= 0;
235 demuxer
->movi_end
= 100;
236 demuxer
->audio
->id
= 0;
237 demuxer
->audio
->sh
= sh_audio
;
239 sh_audio
->ds
= demuxer
->audio
;
241 xmms_output_plugin
.init();
242 ip
->output
= &xmms_output_plugin
;
244 ip
->play_file(demuxer
->stream
->url
);
245 if (ip
->get_song_info
) ip
->get_song_info(demuxer
->stream
->url
,&xmms_title
,&xmms_length
);
246 if (xmms_length
<=0) demuxer
->seekable
=0;
248 mp_msg(MSGT_DEMUX
,MSGL_INFO
,"Waiting for the XMMS plugin to start playback of '%s'...\n",demuxer
->stream
->url
);
249 while (xmms_channels
==0) {
251 if(ip
->get_time()<0) return 0;
253 sh_audio
->sample_format
= xmms_afmt
;
255 case AF_FORMAT_S16_LE
:
256 case AF_FORMAT_S16_BE
:
257 case AF_FORMAT_U16_LE
:
258 case AF_FORMAT_U16_BE
:
259 sh_audio
->samplesize
= 2;
262 sh_audio
->samplesize
= 1;
264 w
->wBitsPerSample
= sh_audio
->samplesize
*8;
265 w
->nChannels
= sh_audio
->channels
= xmms_channels
;
266 w
->nSamplesPerSec
= sh_audio
->samplerate
= xmms_samplerate
;
267 xmms_byterate
= w
->nAvgBytesPerSec
= xmms_samplerate
*sh_audio
->channels
*sh_audio
->samplesize
;
268 w
->nBlockAlign
= sh_audio
->samplesize
*sh_audio
->channels
;
271 return DEMUXER_TYPE_XMMS
;
274 static int demux_xmms_fill_buffer(demuxer_t
* demuxer
, demux_stream_t
*ds
) {
275 sh_audio_t
*sh_audio
= demuxer
->audio
->sh
;
276 xmms_priv_t
*priv
=demuxer
->priv
;
279 if (xmms_length
<=0) demuxer
->seekable
=0;
280 else demuxer
->seekable
=1;
282 while (xmms_audiopos
<XMMS_PACKETSIZE
/2) {
283 if((priv
->ip
->get_time()<0) || !xmms_playing
)
288 pthread_mutex_lock(&xmms_mutex
);
289 dp
= new_demux_packet(XMMS_PACKETSIZE
/2);
290 dp
->pts
= priv
->spos
/ sh_audio
->wf
->nAvgBytesPerSec
;
291 ds
->pos
= priv
->spos
;
293 memcpy(dp
->buffer
,xmms_audiobuffer
,XMMS_PACKETSIZE
/2);
294 memcpy(xmms_audiobuffer
,&xmms_audiobuffer
[XMMS_PACKETSIZE
/2],xmms_audiopos
-XMMS_PACKETSIZE
/2);
295 xmms_audiopos
-=XMMS_PACKETSIZE
/2;
296 pthread_mutex_unlock(&xmms_mutex
);
298 ds_add_packet(ds
,dp
);
303 static void demux_xmms_seek(demuxer_t
*demuxer
,float rel_seek_secs
,float audio_delay
,int flags
){
304 stream_t
* s
= demuxer
->stream
;
305 sh_audio_t
* sh_audio
= demuxer
->audio
->sh
;
306 xmms_priv_t
*priv
=demuxer
->priv
;
309 if(priv
->ip
->get_time()<0) return;
311 pos
= (flags
& 1) ? 0 : priv
->spos
/ sh_audio
->wf
->nAvgBytesPerSec
;
313 pos
+= rel_seek_secs
*xmms_length
;
318 if (pos
>=xmms_length
) pos
=xmms_length
-1;
320 priv
->ip
->seek((pos
<0)?0:pos
);
321 priv
->spos
=pos
* sh_audio
->wf
->nAvgBytesPerSec
;
324 static void demux_close_xmms(demuxer_t
* demuxer
) {
325 xmms_priv_t
*priv
=demuxer
->priv
;
327 xmms_audiopos
=0; // xmp on exit waits until buffer is free enough
329 if (priv
->ip
!= NULL
)
331 free(priv
); xmms_priv
=demuxer
->priv
=NULL
;
336 static int demux_xmms_control(demuxer_t
*demuxer
,int cmd
, void *arg
){
337 demux_stream_t
*d_video
=demuxer
->video
;
338 sh_audio_t
*sh_audio
=demuxer
->audio
->sh
;
339 xmms_priv_t
*priv
=demuxer
->priv
;
342 case DEMUXER_CTRL_GET_TIME_LENGTH
:
343 if (xmms_length
<=0) return DEMUXER_CTRL_DONTKNOW
;
344 *((double *)arg
)=(double)xmms_length
/1000;
345 return DEMUXER_CTRL_GUESS
;
347 case DEMUXER_CTRL_GET_PERCENT_POS
:
349 return DEMUXER_CTRL_DONTKNOW
;
350 *((int *)arg
)=(int)( priv
->spos
/ (float)(sh_audio
->wf
->nAvgBytesPerSec
) / xmms_length
);
351 return DEMUXER_CTRL_OK
;
354 return DEMUXER_CTRL_NOTIMPL
;
359 demuxer_desc_t demuxer_desc_xmms
= {
364 "requires XMMS plugins",
366 0, // safe autodetect
368 demux_xmms_fill_buffer
,