XineEngine::~XineEngine() { // Wait until the fader thread is done if( s_fader ) { m_stopFader = true; s_fader->resume(); // safety call if the engine is in the pause state s_fader->wait(); } delete s_fader; delete s_outfader; if( PanaConfig::fadeoutOnExit() ) { bool terminateFader = false; fadeOut( PanaConfig::fadeoutLength(), &terminateFader, true ); // true == exiting } if( m_xine ) xine_config_save( m_xine, configPath() ); if( m_stream ) xine_close( m_stream ); if( m_eventQueue ) xine_event_dispose_queue( m_eventQueue ); if( m_stream ) xine_dispose( m_stream ); if( m_audioPort ) xine_close_audio_driver( m_xine, m_audioPort ); if( m_post ) xine_post_dispose( m_xine, m_post ); if( m_xine ) xine_exit( m_xine ); debug() << "xine closed\n"; debug() << "Scope statistics:\n" << " Average list size: " << Log::bufferCount / Log::scopeCallCount << endl << " Buffer failure: " << double(Log::noSuitableBuffer*100) / Log::scopeCallCount << "%\n"; }
static void IDirectFBVideoProvider_Xine_Destruct( IDirectFBVideoProvider *thiz ) { IDirectFBVideoProvider_Xine_data *data = thiz->priv; if (data->xine) { if (data->stream) { xine_stop( data->stream ); xine_close( data->stream ); if (data->queue) xine_event_dispose_queue( data->queue ); xine_dispose( data->stream ); } if (data->post) xine_post_dispose( data->xine, data->post ); if (data->vo) xine_close_video_driver( data->xine, data->vo ); if (data->ao) xine_close_audio_driver( data->xine, data->ao ); if (data->cfg) { xine_config_save( data->xine, data->cfg ); D_FREE( data->cfg ); } xine_exit( data->xine ); } if (data->buffer_thread) { direct_thread_cancel( data->buffer_thread ); direct_thread_join( data->buffer_thread ); direct_thread_destroy( data->buffer_thread ); } if (data->buffer) data->buffer->Release( data->buffer ); if (data->pipe) { unlink( data->pipe ); D_FREE( data->pipe ); } if (data->events) data->events->Release( data->events ); D_FREE( data->mrl ); pthread_mutex_destroy( &data->lock ); DIRECT_DEALLOCATE_INTERFACE( thiz ); }
void music_destroy () { xine_event_dispose_queue (events); xine_dispose (stream); xine_close_video_driver (xine, vo); xine_close_audio_driver (xine, ao); xine_exit (xine); }
void cleanup() { if( m_event_queue ) { xine_event_dispose_queue(m_event_queue); m_event_queue = NULL; } if( m_stream ) { xine_dispose(m_stream); m_stream = NULL; } }
void Xine::collect_info(const std::string &f){ if (quitting) return; pthread_mutex_lock(&stream_mutex); if (!playing || file.path != f){ /* Exceptionally we don't let the loop handle this */ playing = false; if(!validate_stream()){ pthread_mutex_unlock(&stream_mutex); return; } xine_close(stream); /* you never know */ xine_event_dispose_queue(event_queue); event_queue = NULL; if(!xine_open(stream, f.c_str())){ pthread_mutex_unlock(&stream_mutex); return; } const bool has_audio = xine_get_stream_info( stream, XINE_STREAM_INFO_HAS_AUDIO ); const bool audio_handled = xine_get_stream_info( stream, XINE_STREAM_INFO_AUDIO_HANDLED ); if (has_audio && audio_handled && xine_play(stream, 0, 0)){ gather_info_internal(); xine_close(stream); } else{ pthread_mutex_unlock(&stream_mutex); return; } } else{ if(!validate_stream()){ pthread_mutex_unlock(&stream_mutex); return; } gather_info_internal(); } title = _title; album = _album; artist = _artist; cur_time = _cur_time; total_time = _total_time; pthread_mutex_unlock(&stream_mutex); }
bool XineEngine::makeNewStream() { m_currentAudioPlugin = XineCfg::outputPlugin(); m_audioPort = xine_open_audio_driver( m_xine, XineCfg::outputPlugin().local8Bit(), NULL ); if( !m_audioPort ) { //TODO make engine method that is the same but parents the dialog for us KMessageBox::error( 0, i18n("xine was unable to initialize any audio drivers.") ); return false; } m_stream = xine_stream_new( m_xine, m_audioPort, NULL ); if( !m_stream ) { xine_close_audio_driver( m_xine, m_audioPort ); m_audioPort = NULL; KMessageBox::error( 0, i18n("Pana could not create a new xine stream.") ); return false; } if( m_eventQueue ) xine_event_dispose_queue( m_eventQueue ); xine_event_create_listener_thread( m_eventQueue = xine_event_new_queue( m_stream ), &XineEngine::XineEventListener, (void*)this ); #ifndef XINE_SAFE_MODE //implemented in xine-scope.h m_post = scope_plugin_new( m_xine, m_audioPort ); xine_set_param( m_stream, XINE_PARAM_METRONOM_PREBUFFER, 6000 ); xine_set_param( m_stream, XINE_PARAM_IGNORE_VIDEO, 1 ); #endif #ifdef XINE_PARAM_EARLY_FINISHED_EVENT if ( xine_check_version(1,1,1) && !(m_xfadeLength > 0) ) { // enable gapless playback debug() << "gapless playback enabled." << endl; //xine_set_param(m_stream, XINE_PARAM_EARLY_FINISHED_EVENT, 1 ); } #endif return true; }
XineEngine::~XineEngine() { // Wait until the fader thread is done if( s_fader ) { m_stopFader = true; s_fader->wait(); delete s_fader; } // NOTE The fadeout gets stuck when the EQ is active, so we skip it then if( !m_equalizerEnabled && m_stream && state() == Engine::Playing ) { const int volume = xine_get_param( m_stream, XINE_PARAM_AUDIO_AMP_LEVEL ); const double D = 300000 * std::pow( (double)volume, -0.4951 ); debug() << "Sleeping: " << D << ", " << volume << endl; for( int v = volume - 1; v >= 1; v-- ) { xine_set_param( m_stream, XINE_PARAM_AUDIO_AMP_LEVEL, v ); const int sleep = int(D * (-log10( v + 1 ) + 2)); ::usleep( sleep ); } xine_stop( m_stream ); } if( m_xine ) xine_config_save( m_xine, configPath() ); if( m_stream ) xine_close( m_stream ); if( m_eventQueue ) xine_event_dispose_queue( m_eventQueue ); if( m_stream ) xine_dispose( m_stream ); if( m_audioPort ) xine_close_audio_driver( m_xine, m_audioPort ); if( m_post ) xine_post_dispose( m_xine, m_post ); if( m_xine ) xine_exit( m_xine ); debug() << "xine closed\n"; debug() << "Scope statistics:\n" << " Average list size: " << Log::bufferCount / Log::scopeCallCount << endl << " Buffer failure: " << double(Log::noSuitableBuffer*100) / Log::scopeCallCount << "%\n"; }
void engine_shutdown ( void ) { // Stop playing and close down the stream xine_stop( stream ); xine_stop( meta_stream ); xine_event_dispose_queue(queue); xine_close(stream); xine_close(meta_stream); xine_dispose(stream); xine_dispose(meta_stream); // Now shut down cleanly xine_close_audio_driver ( engine, ap ); // Now shut down cleanly xine_exit ( engine ); }
Xine::~Xine(){ pthread_mutex_lock(&stream_mutex); quitting = true; pthread_cond_broadcast(&stream_switch); pthread_mutex_unlock(&stream_mutex); if (!initted) return; pthread_join(thread_loop, NULL); pthread_mutex_lock(&stream_mutex); if(stream){ xine_close(stream); xine_event_dispose_queue(event_queue); event_queue = NULL; xine_dispose(stream); stream = NULL; } if (ao_port) xine_close_audio_driver(xine, ao_port); ao_port = NULL; xine_exit(xine); /* booo bye */ }
eServiceXine::~eServiceXine() { if (m_state == stRunning) stop(); eDebug("close stream"); if (stream) xine_close(stream); eDebug("dispose queue"); if (event_queue) xine_event_dispose_queue(event_queue); eDebug("dispose stream"); if (stream) xine_dispose(stream); eDebug("dispose ao_port"); if (ao_port) xine_close_audio_driver(xine, ao_port); eDebug("dispose vo port"); if (vo_port) xine_close_video_driver(xine, vo_port); eDebug("done."); }
bool Xine::make_new_stream(){ if (stream) xine_dispose(stream); std::string ao_driver = "auto"; GlobalOptions * go = S_GlobalOptions::get_instance(); global_audio_device gad = go->get_audio_device_audio(); if (gad.dev_output != ""){ ao_driver = gad.dev_output; } if (ao_port) xine_close_audio_driver(xine, ao_port); /* fprintf(stderr, "Audio driver: %s (%d)\n", ao_driver.c_str(), gad.pos); */ ao_port = xine_open_audio_driver(xine, ao_driver.c_str(), NULL); if (ao_port == NULL){ DialogWaitPrint pdialog(4000); pdialog.add_line(dgettext("mms-audio-xine", "Audio device unavailable: ") + ao_driver); pdialog.print(); return false; } /* Xine uses its own config file for a lot of stuff */ xine_cfg_entry_t config; /* for some reason this doesn't work for someone if (!xine_config_lookup_entry(xine, "input.cdda_device", &config)) { fprintf(stderr, "Xine: Can't set cdda device\n"); } else{ std::string str = S_Cd::get_instance()->get_device(); config.str_value = const_cast<char*>(str.c_str()); xine_config_update_entry(xine, &config); } */ /* Disable CDDB, we have our own CDDB library */ if (xine_config_lookup_entry(xine, "media.audio_cd.use_cddb", &config)){ config.num_value = 0; xine_config_update_entry(xine, &config); } stream = xine_stream_new(xine, ao_port, NULL); if (stream == NULL){ xine_close_audio_driver(xine, ao_port); ao_port = NULL; return false; } /* xine_set_param(stream, XINE_PARAM_VERBOSITY, XINE_VERBOSITY_DEBUG); */ if (event_queue) xine_event_dispose_queue(event_queue); xine_set_param( stream, XINE_PARAM_METRONOM_PREBUFFER, 6000 ); xine_set_param( stream, XINE_PARAM_IGNORE_VIDEO, 1 ); #ifdef XINE_PARAM_EARLY_FINISHED_EVENT #ifdef XINE_PARAM_GAPLESS_SWITCH if (xine_check_version(1,1,1)) xine_set_param(stream, XINE_PARAM_EARLY_FINISHED_EVENT, 1); #ifdef XINE_PARAM_DELAY_FINISHED_EVENT xine_set_param(stream, XINE_PARAM_DELAY_FINISHED_EVENT, 0); #endif #endif #endif event_queue = xine_event_new_queue(stream); mixer_cap = false; is_muted = xine_get_param(stream, XINE_PARAM_AUDIO_MUTE); if (is_muted == -1){ is_muted = xine_get_param(stream, XINE_PARAM_AUDIO_AMP_MUTE); mixer_cap = true; } xine_event_create_listener_thread(event_queue, &Xine::event_listener, reinterpret_cast<void*>(this)); return true; }
void Xine::run(){ /* this is the main thread */ playing = false; seamless = false; pthread_mutex_lock(&stream_mutex); struct timespec ts = time_helper::compute_interval(5000); Audio_s *audio_state = S_Audio_s::get_instance(); volume = 0; if(validate_stream()) volume = xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME); old_volume = volume; while(!quitting){ xine_request = _XINE_REQUEST_NONE; int ret = pthread_cond_timedwait(&stream_switch, &stream_mutex, &ts); if (!running || quitting){ ts = time_helper::compute_interval(5000); continue; } if (ret != ETIMEDOUT && xine_request == _XINE_REQUEST_NONE) continue; /* we're not done waiting */ /* if (xine_request != _XINE_REQUEST_NONE) fprintf (stderr, "Loop received event request (%d)\n", xine_request); */ switch(xine_request){ case _XINE_REQUEST_PLAY_AT: case _XINE_REQUEST_PLAY:{ retry_track = false; if(!validate_stream()) break; #ifdef XINE_PARAM_EARLY_FINISHED_EVENT if (seamless && xine_check_version(1,1,1) && oldfile.type != "web" && file.type != "web"){ xine_set_param(stream, XINE_PARAM_GAPLESS_SWITCH, 1); } // else{ // xine_close(stream); // } seamless = false; #endif oldfile = file; /* fprintf(stderr, "file.path %s\n", file.path.c_str()); */ std::string _str = file.path; if (file.type == "media-track"){ std::string _path = "cdda:/" + cd_device + "/"; _str = regex_tools::regex_replace(_str, _path.c_str(), "^cdda:/", false, false); /* fprintf(stderr, "%s\n", _str.c_str()); */ } else { vector<string> urls = PlaylistParser::resolve_playlist(_str); if (!urls.empty()) _str = urls[0]; /* TODO: Handle multiple playlist entries here */ } if(!xine_open(stream, _str.c_str())){ #ifdef XINE_PARAM_GAPLESS_SWITCH if (xine_check_version(1,1,1)) xine_set_param(stream, XINE_PARAM_GAPLESS_SWITCH, 0); #endif break; } int len = 0; off_t play_at = 0; const bool has_audio = xine_get_stream_info( stream, XINE_STREAM_INFO_HAS_AUDIO ); const bool audio_handled = xine_get_stream_info( stream, XINE_STREAM_INFO_AUDIO_HANDLED ); if (xine_request == _XINE_REQUEST_PLAY_AT){ xine_get_pos_length(stream, 0, 0, &len); play_at = len > 0 ? static_cast<double>(cur_time*65535)/(len/1000) : 0; } else cur_time = 0; _cur_time = cur_time; total_time = 0; _total_time = 0; if ((has_audio || file.type == "web") && audio_handled && xine_play(stream, play_at, cur_time * 1000)){ playing = true; //gather_info_internal(); audio_state->set_playing(true); buffering_state = 0; } else{ playing = false; audio_state->set_playing(false); xine_close(stream); } audio_state->get_audio()->update_playlist_view(); #ifdef XINE_PARAM_EARLY_FINISHED_EVENT #ifdef XINE_PARAM_GAPLESS_SWITCH if (xine_check_version(1,1,1)){ if (!audio_state->get_audio()->next_helper(false).path.empty()){ xine_set_param(stream, XINE_PARAM_EARLY_FINISHED_EVENT, 1); /* fprintf(stderr, "Not last track\n"); */ #ifdef XINE_PARAM_DELAY_FINISHED_EVENT xine_set_param(stream, XINE_PARAM_DELAY_FINISHED_EVENT, 0); #endif } else { /* If we don't disable XINE_PARAM_DELAY_FINISHED_EVENT for the last track in the playlist, * xine won't play the last couple of seconds of it */ xine_set_param(stream, XINE_PARAM_EARLY_FINISHED_EVENT, 0); /* fprintf(stderr, "Last track\n"); */ } } #endif #endif if (start_paused){ start_paused = false; audio_state->set_pause(true); } else audio_state->set_pause(false); break; } case _XINE_REQUEST_STOP: case _XINE_REQUEST_RELEASE_DEVICE: retry_track = false; seamless = false; if(stream){ xine_close(stream); xine_event_dispose_queue(event_queue); event_queue = NULL; xine_dispose(stream); stream = NULL; } playing = false; audio_state->set_playing(false); if (xine_request == _XINE_REQUEST_RELEASE_DEVICE){ xine_close_audio_driver(xine, ao_port); ao_port = NULL; } break; case _XINE_REQUEST_PAUSE: if(!validate_stream()||!playing) break; if(xine_get_param(stream, XINE_PARAM_SPEED) != XINE_SPEED_PAUSE) { xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE); audio_state->set_pause(true); } else { xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL); audio_state->set_pause(false); } break; case _XINE_REQUEST_FF:{ if(!playing || !validate_stream()) break; gather_info_internal(); if (_cur_time + 5 > _total_time) break; _cur_time +=5; off_t pos = _total_time > 0 ? static_cast<double>(_cur_time*65535)/_total_time : 0; xine_play(stream, pos, _cur_time*1000); audio_state->set_pause(false); break; } case _XINE_REQUEST_FB:{ if(!playing || !validate_stream()) break; gather_info_internal(); if (static_cast<int>(_cur_time) - 5 < 0) break; _cur_time -=5; off_t pos = _total_time > 0 ? static_cast<double>(_cur_time*65535)/_total_time : 0; xine_play(stream, pos, _cur_time*1000); audio_state->set_pause(false); break; } default: break; } if (ret == ETIMEDOUT && playing) gather_info_internal(); if (playing) ts = time_helper::compute_interval(500); else ts = time_helper::compute_interval(5000); } if(stream){ xine_close(stream); xine_event_dispose_queue(event_queue); event_queue = NULL; xine_dispose(stream); stream = NULL; } playing = false; if (ao_port) xine_close_audio_driver(xine, ao_port); ao_port = NULL; pthread_mutex_unlock(&stream_mutex); /* bye */ }
/* this is a slave controller thread for the xine module - libxine loves * to deadlock, internally stall and otherwise have unpredictable behavior * if we use the main process thread for many things - so a lot will be * farmed off to this slave. its job is to handle opening, closing, file * opening, recoder init etc. and all sorts of things can that often block. * anything this thread needs to return, it will return via the event pipe. */ static void * _em_slave(void *par) { Emotion_Xine_Video *ev; void *buf[2]; int len; ev = (Emotion_Xine_Video *)par; while ((len = read(ev->fd_slave_read, buf, sizeof(buf))) > 0) { if (len == sizeof(buf)) { Emotion_Xine_Event *eev; ev = buf[0]; eev = buf[1]; switch (eev->mtype) { case 0: /* noop */ break; case 1: /* init */ { ev->decoder = xine_new(); xine_init(ev->decoder); xine_register_plugins(ev->decoder, emotion_xine_plugin_info); if (1) { xine_cfg_entry_t cf; if (xine_config_lookup_entry(ev->decoder, "input.dvd_use_readahead", &cf)) { cf.num_value = 1; // 0 or 1 xine_config_update_entry(ev->decoder, &cf); } } DBG("OPEN VIDEO PLUGIN..."); if (!ev->opt_no_video) ev->video = xine_open_video_driver(ev->decoder, "emotion", XINE_VISUAL_TYPE_NONE, ev); DBG("RESULT: xine_open_video_driver() = %p", ev->video); // Let xine autodetect the best audio output driver if (!ev->opt_no_audio) ev->audio = xine_open_audio_driver(ev->decoder, NULL, ev); // ev->audio = xine_open_audio_driver(ev->decoder, "oss", ev); // dont use alsa - alsa has oss emulation. // ev->audio = xine_open_audio_driver(ev->decoder, "alsa", ev); // ev->audio = xine_open_audio_driver(ev->decoder, "arts", ev); // ev->audio = xine_open_audio_driver(ev->decoder, "esd", ev); ev->stream = xine_stream_new(ev->decoder, ev->audio, ev->video); ev->queue = xine_event_new_queue(ev->stream); xine_event_create_listener_thread(ev->queue, _em_event, ev); ev->opening = 0; ev->play_ok = 1; _em_module_event(ev, 1); /* event - open done */ } break; case 3: /* shutdown */ { _em_module_event(ev, 3); DBG("shutdown stop"); xine_stop(ev->stream); // pthread_mutex_lock(&(ev->get_pos_len_mutex)); if (!ev->get_pos_thread_deleted) { DBG("closing get_pos thread, %p", ev); pthread_mutex_lock(&(ev->get_pos_len_mutex)); pthread_cond_broadcast(&(ev->get_pos_len_cond)); pthread_mutex_unlock(&(ev->get_pos_len_mutex)); while (ev->get_poslen); } DBG("dispose %p", ev); xine_dispose(ev->stream); DBG("dispose evq %p", ev); xine_event_dispose_queue(ev->queue); DBG("close video drv %p", ev); if (ev->video) xine_close_video_driver(ev->decoder, ev->video); DBG("wait for vo to go"); while (ev->have_vo); DBG("vo gone"); DBG("close audio drv %p", ev); if (ev->audio) xine_close_audio_driver(ev->decoder, ev->audio); DBG("xine exit %p", ev); xine_exit(ev->decoder); DBG("DONE %p", ev); close(ev->fd_write); close(ev->fd_read); close(ev->fd_ev_write); close(ev->fd_ev_read); close(ev->fd_slave_write); close(ev->fd_slave_read); ev->closing = 0; if (eev->xine_event) free(eev->xine_event); free(eev); free(ev); return NULL; } break; case 2: /* file open */ { int pos_stream = 0; int pos_time = 0; int length_time = 0; uint32_t v; char *file; file = eev->xine_event; DBG("OPEN STREAM %s", file); if (xine_open(ev->stream, file)) { if (xine_get_pos_length(ev->stream, &pos_stream, &pos_time, &length_time)) { if (length_time == 0) { ev->pos = (double)pos_stream / 65535; ev->len = 1.0; ev->no_time = 1; } else { ev->pos = 0.0; ev->len = (double)length_time / 1000.0; } } else { ev->pos = 0.0; ev->len = 1.0; } v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_FRAME_DURATION); if (v > 0) ev->fps = 90000.0 / (double)v; v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_WIDTH); ev->w = v; v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_HEIGHT); ev->h = v; v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_RATIO); ev->ratio = (double)v / 10000.0; ev->just_loaded = 1; ev->get_poslen = 0; xine_set_param(ev->stream, XINE_PARAM_AUDIO_VOLUME, ev->volume * 100); } _em_module_event(ev, 2); /* event - open done */ } break; case 11: /* file close */ { DBG("done %p", ev); em_frame_done(ev); DBG("stop %p", ev); xine_stop(ev->stream); DBG("close %p", ev); xine_close(ev->stream); DBG("close done %p", ev); _em_module_event(ev, 11); } break; case 4: /* play */ { double pos; int pos_stream, pos_time, length_time; pos = *((double *)eev->xine_event); if ((xine_get_param(ev->stream, XINE_PARAM_SPEED) == XINE_SPEED_PAUSE) && (pos == ev->pos) && (!ev->just_loaded)) { xine_set_param(ev->stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL); } else { if (ev->no_time) xine_play(ev->stream, pos * 65535, 0); else xine_play(ev->stream, 0, pos * 1000); } ev->just_loaded = 0; if (xine_get_pos_length(ev->stream, &pos_stream, &pos_time, &length_time)) { if (length_time == 0) { ev->pos = (double)pos_stream / 65535; ev->len = 1.0; ev->no_time = 1; } else { ev->pos = (double)pos_time / 1000.0; ev->len = (double)length_time / 1000.0; } } _em_module_event(ev, 4); } break; case 5: /* stop */ { xine_set_param(ev->stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE); _em_module_event(ev, 5); } break; case 6: /* seek */ { double pos; pos = *((double *)eev->xine_event); if (ev->no_time) xine_play(ev->stream, pos * 65535, 0); else xine_play(ev->stream, 0, pos * 1000); if (!ev->play) xine_set_param(ev->stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE); _em_module_event(ev, 6); } break; case 7: /* eject */ { xine_eject(ev->stream); _em_module_event(ev, 7); } break; case 8: /* spu mute */ { xine_set_param(ev->stream, XINE_PARAM_IGNORE_SPU, ev->spu_mute); _em_module_event(ev, 8); } break; case 9: /* channel */ { xine_set_param(ev->stream, XINE_PARAM_SPU_CHANNEL, ev->spu_channel); _em_module_event(ev, 9); } break; case 10: /* vol */ { xine_set_param(ev->stream, XINE_PARAM_AUDIO_VOLUME, ev->volume * 100); _em_module_event(ev, 10); } break; case 12: /* audio mute */ { xine_set_param(ev->stream, XINE_PARAM_AUDIO_MUTE, ev->audio_mute); } break; case 13: /* audio mute */ { xine_set_param(ev->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, ev->audio_channel); } break; case 14: /* audio mute */ { xine_set_param(ev->stream, XINE_PARAM_VIDEO_CHANNEL, ev->video_channel); } break; default: break; } if (eev->xine_event) free(eev->xine_event); free(eev); } } return NULL; }