static void ParseRequest( services_discovery_t *p_sd ) { services_discovery_sys_t *p_sys = p_sd->p_sys; char *psz_request = p_sys->psz_request; int i; char *psz_tok = strchr( psz_request, ':' ); if( !psz_tok ) return; *psz_tok = '\0'; if( !strcmp( psz_request, "ADD" ) ) { psz_request = psz_tok + 1; for( i = 0; i<p_sys->i_urls; i++ ) if( !strcmp(p_sys->ppsz_urls[i],psz_request) ) break; if( i == p_sys->i_urls ) { INSERT_ELEM( p_sys->ppsz_urls, p_sys->i_urls, p_sys->i_urls, strdup( psz_request ) ); input_item_t *p_input; p_input = input_item_New( p_sd, psz_request, psz_request ); input_item_AddOption( p_input, "demux=podcast", VLC_INPUT_OPTION_TRUSTED ); INSERT_ELEM( p_sys->pp_items, p_sys->i_items, p_sys->i_items, p_input ); services_discovery_AddItem( p_sd, p_input, NULL /* no cat */ ); INSERT_ELEM( p_sys->pp_input, p_sys->i_input, p_sys->i_input, input_CreateAndStart( p_sd, p_input, NULL ) ); SaveUrls( p_sd ); } } else if ( !strcmp( psz_request, "RM" ) ) { psz_request = psz_tok + 1; for( i = 0; i<p_sys->i_urls; i++ ) if( !strcmp(p_sys->ppsz_urls[i],psz_request) ) break; if( i != p_sys->i_urls ) { services_discovery_RemoveItem( p_sd, p_sys->pp_items[i] ); vlc_gc_decref( p_sys->pp_items[i] ); REMOVE_ELEM( p_sys->ppsz_urls, p_sys->i_urls, i ); REMOVE_ELEM( p_sys->pp_items, p_sys->i_items, i ); } SaveUrls( p_sd ); } free( p_sys->psz_request ); p_sys->psz_request = NULL; }
/** * This function does the preparsing and issues the art fetching requests */ static void *Thread( void *data ) { playlist_preparser_t *p_preparser = data; playlist_t *p_playlist = p_preparser->p_playlist; for( ;; ) { input_item_t *p_current; /* */ vlc_mutex_lock( &p_preparser->lock ); if( p_preparser->i_waiting > 0 ) { p_current = p_preparser->pp_waiting[0]; REMOVE_ELEM( p_preparser->pp_waiting, p_preparser->i_waiting, 0 ); } else { p_current = NULL; p_preparser->b_live = false; } vlc_mutex_unlock( &p_preparser->lock ); if( !p_current ) break; Preparse( p_playlist, p_current ); Art( p_preparser, p_current ); } return NULL; }
void playlist_preparser_Delete( playlist_preparser_t *p_preparser ) { vlc_mutex_lock( &p_preparser->lock ); /* Remove pending item to speed up preparser thread exit */ while( p_preparser->i_waiting > 0 ) { preparser_entry_t *p_entry = p_preparser->pp_waiting[0]; vlc_gc_decref( p_entry->p_item ); free( p_entry ); REMOVE_ELEM( p_preparser->pp_waiting, p_preparser->i_waiting, 0 ); } vlc_sem_post( &p_preparser->item_done ); while( p_preparser->b_live ) vlc_cond_wait( &p_preparser->wait, &p_preparser->lock ); vlc_mutex_unlock( &p_preparser->lock ); /* Destroy the item preparser */ vlc_sem_destroy( &p_preparser->item_done ); vlc_cond_destroy( &p_preparser->wait ); vlc_mutex_destroy( &p_preparser->lock ); if( p_preparser->p_fetcher != NULL ) playlist_fetcher_Delete( p_preparser->p_fetcher ); free( p_preparser ); }
/* Remove a SAP Announce */ static int announce_SAPAnnounceDel( sap_handler_t *p_sap, session_descriptor_t *p_session ) { int i; vlc_mutex_lock( &p_sap->object_lock ); msg_Dbg( p_sap,"removing SAP announce %p",p_session->p_sap); /* Dequeue the announce */ for( i = 0; i< p_sap->i_sessions; i++) { if( p_session->p_sap == p_sap->pp_sessions[i] ) { REMOVE_ELEM( p_sap->pp_sessions, p_sap->i_sessions, i ); break; } } /* XXX: Dequeue the address too if it is not used anymore * TODO: - address refcount - send a SAP deletion packet */ msg_Dbg( p_sap,"%i announces remaining", p_sap->i_sessions ); vlc_mutex_unlock( &p_sap->object_lock ); return VLC_SUCCESS; }
/** * This function does the preparsing and issues the art fetching requests */ static void *Thread( void *data ) { playlist_preparser_t *p_preparser = data; vlc_object_t *obj = p_preparser->object; for( ;; ) { input_item_t *p_current; /* */ vlc_mutex_lock( &p_preparser->lock ); if( p_preparser->i_waiting > 0 ) { p_current = p_preparser->pp_waiting[0]; REMOVE_ELEM( p_preparser->pp_waiting, p_preparser->i_waiting, 0 ); } else { p_current = NULL; p_preparser->b_live = false; vlc_cond_signal( &p_preparser->wait ); } vlc_mutex_unlock( &p_preparser->lock ); if( !p_current ) break; Preparse( obj, p_current ); Art( p_preparser, p_current ); vlc_gc_decref(p_current); } return NULL; }
/** * Moves an array of items * * This function must be entered with the playlist lock * * \param p_playlist the playlist * \param i_items the number of indexes to move * \param pp_items the array of indexes to move * \param p_node the target node * \param i_newpos the target position under this node * \return VLC_SUCCESS or an error */ int playlist_TreeMoveMany( playlist_t *p_playlist, int i_items, playlist_item_t **pp_items, playlist_item_t *p_node, int i_newpos ) { PL_ASSERT_LOCKED; if ( p_node->i_children == -1 ) return VLC_EGENERIC; int i; for( i = 0; i < i_items; i++ ) { playlist_item_t *p_item = pp_items[i]; int i_index = ItemIndex( p_item ); playlist_item_t *p_parent = p_item->p_parent; REMOVE_ELEM( p_parent->pp_children, p_parent->i_children, i_index ); if ( p_parent == p_node && i_index < i_newpos ) i_newpos--; } for( i = i_items - 1; i >= 0; i-- ) { playlist_item_t *p_item = pp_items[i]; INSERT_ELEM( p_node->pp_children, p_node->i_children, i_newpos, p_item ); p_item->p_parent = p_node; } pl_priv( p_playlist )->b_reset_currently_playing = true; vlc_cond_signal( &pl_priv( p_playlist )->signal ); return VLC_SUCCESS; }
static void DelCallback( vlc_object_t *p_this, const char *psz_name, callback_entry_t entry, vlc_callback_type_t i_type ) { int i_entry; variable_t *p_var; #ifndef NDEBUG bool b_found_similar = false; #endif assert( p_this ); vlc_object_internals_t *p_priv = vlc_internals( p_this ); p_var = Lookup( p_this, psz_name ); if( p_var == NULL ) { vlc_mutex_unlock( &p_priv->var_lock ); msg_Err( p_this, "cannot delete callback %p from nonexistent " "variable '%s'", entry.p_callback, psz_name ); return; } WaitUnused( p_this, p_var ); callback_table_t *p_table; if (i_type == vlc_value_callback) p_table = &p_var->value_callbacks; else p_table = &p_var->list_callbacks; for( i_entry = p_table->i_entries ; i_entry-- ; ) { if( p_table->p_entries[i_entry].p_callback == entry.p_callback && p_table->p_entries[i_entry].p_data == entry.p_data ) { break; } #ifndef NDEBUG else if( p_table->p_entries[i_entry].p_callback == entry.p_callback ) b_found_similar = true; #endif } if( i_entry < 0 ) { #ifndef NDEBUG if( b_found_similar ) fprintf( stderr, "Calling var_DelCallback for '%s' with the same " "function but not the same data.", psz_name ); vlc_assert_unreachable(); #endif vlc_mutex_unlock( &p_priv->var_lock ); return; } REMOVE_ELEM( p_table->p_entries, p_table->i_entries, i_entry ); vlc_mutex_unlock( &p_priv->var_lock ); }
/***************************************************************************** * Run: Thread entry-point ****************************************************************************/ static void* Run( void *data ) { services_discovery_t *p_sd = ( services_discovery_t * )data; services_discovery_sys_t *p_sys = p_sd->p_sys; lua_State *L = p_sys->L; int cancel = vlc_savecancel(); lua_getglobal( L, "main" ); if( !lua_isfunction( L, lua_gettop( L ) ) || lua_pcall( L, 0, 1, 0 ) ) { msg_Err( p_sd, "Error while running script %s, " "function main(): %s", p_sys->psz_filename, lua_tostring( L, lua_gettop( L ) ) ); lua_pop( L, 1 ); vlc_restorecancel( cancel ); return NULL; } msg_Dbg( p_sd, "LuaSD script loaded: %s", p_sys->psz_filename ); /* Force garbage collection, because the core will keep the SD * open, but lua will never gc until lua_close(). */ lua_gc( L, LUA_GCCOLLECT, 0 ); vlc_restorecancel( cancel ); /* Main loop to handle search requests */ vlc_mutex_lock( &p_sys->lock ); mutex_cleanup_push( &p_sys->lock ); for( ;; ) { /* Wait for a request */ if( !p_sys->i_query ) { vlc_cond_wait( &p_sys->cond, &p_sys->lock ); continue; } /* Execute one query (protected against cancellation) */ char *psz_query = p_sys->ppsz_query[p_sys->i_query - 1]; REMOVE_ELEM( p_sys->ppsz_query, p_sys->i_query, p_sys->i_query - 1 ); vlc_mutex_unlock( &p_sys->lock ); cancel = vlc_savecancel(); DoSearch( p_sd, psz_query ); free( psz_query ); /* Force garbage collection, because the core will keep the SD * open, but lua will never gc until lua_close(). */ lua_gc( L, LUA_GCCOLLECT, 0 ); vlc_restorecancel( cancel ); vlc_mutex_lock( &p_sys->lock ); } vlc_cleanup_run(); return NULL; }
/** * Remove a callback from a variable * * pf_callback and p_data have to be given again, because different objects * might have registered the same callback function. */ int var_DelCallback( vlc_object_t *p_this, const char *psz_name, vlc_callback_t pf_callback, void *p_data ) { int i_entry; variable_t *p_var; #ifndef NDEBUG bool b_found_similar = false; #endif assert( p_this ); vlc_object_internals_t *p_priv = vlc_internals( p_this ); vlc_mutex_lock( &p_priv->var_lock ); p_var = Lookup( p_this, psz_name ); if( p_var == NULL ) { vlc_mutex_unlock( &p_priv->var_lock ); return VLC_ENOVAR; } WaitUnused( p_this, p_var ); for( i_entry = p_var->i_entries ; i_entry-- ; ) { if( p_var->p_entries[i_entry].pf_callback == pf_callback && p_var->p_entries[i_entry].p_data == p_data ) { break; } #ifndef NDEBUG else if( p_var->p_entries[i_entry].pf_callback == pf_callback ) b_found_similar = true; #endif } if( i_entry < 0 ) { #ifndef NDEBUG if( b_found_similar ) fprintf( stderr, "Calling var_DelCallback for '%s' with the same " "function but not the same data.", psz_name ); assert( 0 ); #endif vlc_mutex_unlock( &p_priv->var_lock ); return VLC_EGENERIC; } REMOVE_ELEM( p_var->p_entries, p_var->i_entries, i_entry ); vlc_mutex_unlock( &p_priv->var_lock ); return VLC_SUCCESS; }
/** * Moves an item * * This function must be entered with the playlist lock * * \param p_playlist the playlist * \param p_item the item to move * \param p_node the new parent of the item * \param i_newpos the new position under this new parent * \param i_view the view in which the move must be done or ALL_VIEWS * \return VLC_SUCCESS or an error */ int playlist_TreeMove( playlist_t * p_playlist, playlist_item_t *p_item, playlist_item_t *p_node, int i_newpos, int i_view ) { int i; playlist_item_t *p_detach = NULL; struct item_parent_t *p_parent; if( p_node->i_children == -1 ) return VLC_EGENERIC; /* Detach from the parent */ for( i = 0 ; i< p_item->i_parents; i++ ) { if( p_item->pp_parents[i]->i_view == i_view ) { int j; p_detach = p_item->pp_parents[i]->p_parent; for( j = 0; j < p_detach->i_children; j++ ) { if( p_detach->pp_children[j] == p_item ) break; } REMOVE_ELEM( p_detach->pp_children, p_detach->i_children, j ); p_detach->i_serial++; free( p_item->pp_parents[i] ); REMOVE_ELEM( p_item->pp_parents, p_item->i_parents, i ); i--; } } /* Attach to new parent */ INSERT_ELEM( p_node->pp_children, p_node->i_children, i_newpos, p_item ); p_parent = malloc( sizeof( struct item_parent_t ) ); p_parent->p_parent = p_node; p_parent->i_view = i_view; INSERT_ELEM( p_item->pp_parents, p_item->i_parents, p_item->i_parents, p_parent ); p_node->i_serial++; p_item->i_serial++; return VLC_SUCCESS; }
/** Update a counter element with new values * \param p_counter the counter to update * \param val the vlc_value union containing the new value to aggregate. For * more information on how data is aggregated, \see stats_Create * \param val_new a pointer that will be filled with new data */ void stats_Update( counter_t *p_counter, uint64_t val, uint64_t *new_val ) { if( !p_counter ) return; switch( p_counter->i_compute_type ) { case STATS_DERIVATIVE: { counter_sample_t *p_new, *p_old; mtime_t now = mdate(); if( now - p_counter->last_update < CLOCK_FREQ ) return; p_counter->last_update = now; /* Insert the new one at the beginning */ p_new = (counter_sample_t*)malloc( sizeof( counter_sample_t ) ); if (unlikely(p_new == NULL)) return; /* NOTE: Losing sample here */ p_new->value = val; p_new->date = p_counter->last_update; INSERT_ELEM( p_counter->pp_samples, p_counter->i_samples, 0, p_new ); if( p_counter->i_samples == 3 ) { p_old = p_counter->pp_samples[2]; REMOVE_ELEM( p_counter->pp_samples, p_counter->i_samples, 2 ); free( p_old ); } break; } case STATS_COUNTER: if( p_counter->i_samples == 0 ) { counter_sample_t *p_new = (counter_sample_t*)malloc( sizeof( counter_sample_t ) ); if (unlikely(p_new == NULL)) return; /* NOTE: Losing sample here */ p_new->value = 0; INSERT_ELEM( p_counter->pp_samples, p_counter->i_samples, p_counter->i_samples, p_new ); } if( p_counter->i_samples == 1 ) { p_counter->pp_samples[0]->value += val; if( new_val ) *new_val = p_counter->pp_samples[0]->value; } break; } }
/** * @brief Remove items until everything fits in storage. * @note items will be randomly selected for removal. * @param[in] base Pointer to the base */ void CAP_RemoveItemsExceedingCapacity (base_t *base) { int i; int objIdx[MAX_OBJDEFS]; /**< Will contain idx of items that can be removed */ int num, cnt; if (CAP_GetFreeCapacity(base, CAP_ITEMS) >= 0) return; for (i = 0, num = 0; i < cgi->csi->numODs; i++) { const objDef_t *obj = INVSH_GetItemByIDX(i); if (!B_ItemIsStoredInBaseStorage(obj)) continue; /* Don't count item that we don't have in base */ if (B_ItemInBase(obj, base) <= 0) continue; objIdx[num++] = i; } cnt = E_CountHired(base, EMPL_ROBOT); /* UGV takes room in storage capacity: we store them with a value MAX_OBJDEFS that can't be used by objIdx */ for (i = 0; i < cnt; i++) { objIdx[num++] = MAX_OBJDEFS; } while (num && CAP_GetFreeCapacity(base, CAP_ITEMS) < 0) { /* Select the item to remove */ const int randNumber = rand() % num; if (objIdx[randNumber] >= MAX_OBJDEFS) { /* A UGV is destroyed: get first one */ Employee* employee = E_GetHiredRobot(base, 0); /* There should be at least a UGV */ assert(employee); E_DeleteEmployee(employee); } else { /* items are destroyed. We guess that all items of a given type are stored in the same location * => destroy all items of this type */ const int idx = objIdx[randNumber]; const objDef_t *od = INVSH_GetItemByIDX(idx); B_UpdateStorageAndCapacity(base, od, -B_ItemInBase(od, base), false); } REMOVE_ELEM(objIdx, randNumber, num); /* Make sure that we don't have an infinite loop */ if (num <= 0) break; } Com_DPrintf(DEBUG_CLIENT, "B_RemoveItemsExceedingCapacity: Remains %i in storage for a maximum of %i\n", CAP_GetCurrent(base, CAP_ITEMS), CAP_GetMax(base, CAP_ITEMS)); }
void stats_CounterClean( counter_t *p_c ) { if( p_c ) { int i = p_c->i_samples - 1 ; while( i >= 0 ) { counter_sample_t *p_s = p_c->pp_samples[i]; REMOVE_ELEM( p_c->pp_samples, p_c->i_samples, i ); free( p_s ); i--; } free( p_c ); } }
/** * Destroy the SAP handler * \param p_this the SAP Handler to destroy * \return nothing */ void announce_SAPHandlerDestroy( sap_handler_t *p_sap ) { int i; vlc_mutex_destroy( &p_sap->object_lock ); /* Free the remaining sessions */ for( i = 0 ; i< p_sap->i_sessions ; i++) { sap_session_t *p_session = p_sap->pp_sessions[i]; FREE( p_session->psz_sdp ); FREE( p_session->psz_data ); REMOVE_ELEM( p_sap->pp_sessions, p_sap->i_sessions , i ); FREE( p_session ); } /* Free the remaining addresses */ for( i = 0 ; i< p_sap->i_addresses ; i++) { sap_address_t *p_address = p_sap->pp_addresses[i]; FREE( p_address->psz_address ); if( p_address->i_rfd > -1 ) { net_Close( p_address->i_rfd ); } if( p_address->i_wfd > -1 && p_sap->b_control ) { net_Close( p_address->i_wfd ); } REMOVE_ELEM( p_sap->pp_addresses, p_sap->i_addresses, i ); FREE( p_address ); } /* Free the structure */ vlc_object_destroy( p_sap ); }
/***************************************************************************** * Run: main thread *****************************************************************************/ static void *Run( void *data ) { services_discovery_t *p_sd = data; services_discovery_sys_t *p_sys = p_sd->p_sys; vlc_mutex_lock( &p_sys->lock ); mutex_cleanup_push( &p_sys->lock ); for( ;; ) { while( !p_sys->b_update ) vlc_cond_wait( &p_sys->wait, &p_sys->lock ); int canc = vlc_savecancel (); msg_Dbg( p_sd, "Update required" ); if( p_sys->update_type == UPDATE_URLS ) { char* psz_urls = var_GetNonEmptyString( p_sd, "podcast-urls" ); ParseUrls( p_sd, psz_urls ); free( psz_urls ); } else if( p_sys->update_type == UPDATE_REQUEST ) { ParseRequest( p_sd ); } p_sys->b_update = false; for( int i = 0; i < p_sd->p_sys->i_input; i++ ) { input_thread_t *p_input = p_sd->p_sys->pp_input[i]; if( p_input->b_eof || p_input->b_error ) { input_Stop( p_input, false ); vlc_thread_join( p_input ); vlc_object_release( p_input ); p_sd->p_sys->pp_input[i] = NULL; REMOVE_ELEM( p_sys->pp_input, p_sys->i_input, i ); i--; } } vlc_restorecancel (canc); } vlc_cleanup_pop(); assert(0); /* dead code */ }
/***************************************************************************** * Run: main thread *****************************************************************************/ VLC_NORETURN static void *Run( void *data ) { services_discovery_t *p_sd = data; services_discovery_sys_t *p_sys = p_sd->p_sys; vlc_mutex_lock( &p_sys->lock ); mutex_cleanup_push( &p_sys->lock ); for( ;; ) { while( !p_sys->b_update ) vlc_cond_wait( &p_sys->wait, &p_sys->lock ); int canc = vlc_savecancel (); msg_Dbg( p_sd, "Update required" ); if( p_sys->update_type == UPDATE_URLS ) { char *psz_urls = var_GetNonEmptyString( p_sd->p_parent, "podcast-urls" ); ParseUrls( p_sd, psz_urls ); free( psz_urls ); } else if( p_sys->update_type == UPDATE_REQUEST ) ParseRequest( p_sd ); p_sys->b_update = false; for( int i = 0; i < p_sd->p_sys->i_input; i++ ) { input_thread_t *p_input = p_sd->p_sys->pp_input[i]; int state = var_GetInteger( p_input, "state" ); if( state == END_S || state == ERROR_S ) { input_Stop( p_input ); input_Close( p_input ); p_sd->p_sys->pp_input[i] = NULL; REMOVE_ELEM( p_sys->pp_input, p_sys->i_input, i ); i--; } } vlc_restorecancel (canc); } vlc_cleanup_pop(); vlc_assert_unreachable(); /* dead code */ }
/** * Deletes an item from the children of a node * * \param p_playlist the playlist * \param p_item the item to remove * \param p_parent the parent node * \return VLC_SUCCESS or an error */ int playlist_NodeRemoveItem( playlist_t *p_playlist, playlist_item_t *p_item, playlist_item_t *p_parent ) { PL_ASSERT_LOCKED; (void)p_playlist; for(int i= 0; i< p_parent->i_children ; i++ ) { if( p_parent->pp_children[i] == p_item ) { REMOVE_ELEM( p_parent->pp_children, p_parent->i_children, i ); } } return VLC_SUCCESS; }
/** * Unsubscribe from a message queue. */ void __msg_Unsubscribe( vlc_object_t *p_this, msg_subscription_t *p_sub ) { libvlc_priv_t *priv = libvlc_priv (p_this->p_libvlc); LOCK_BANK; vlc_mutex_lock( &QUEUE.lock ); for( int j = 0 ; j< QUEUE.i_sub ; j++ ) { if( QUEUE.pp_sub[j] == p_sub ) { REMOVE_ELEM( QUEUE.pp_sub, QUEUE.i_sub, j ); free( p_sub ); } } vlc_mutex_unlock( &QUEUE.lock ); UNLOCK_BANK; }
void playlist_preparser_Delete( playlist_preparser_t *p_preparser ) { vlc_mutex_lock( &p_preparser->lock ); /* Remove pending item to speed up preparser thread exit */ while( p_preparser->i_waiting > 0 ) { vlc_gc_decref( p_preparser->pp_waiting[0] ); REMOVE_ELEM( p_preparser->pp_waiting, p_preparser->i_waiting, 0 ); } while( p_preparser->b_live ) vlc_cond_wait( &p_preparser->wait, &p_preparser->lock ); vlc_mutex_unlock( &p_preparser->lock ); /* Destroy the item preparser */ vlc_cond_destroy( &p_preparser->wait ); vlc_mutex_destroy( &p_preparser->lock ); free( p_preparser ); }
/** * Transform an item to a node * * This function must be entered without the playlist lock * * \param p_playlist the playlist object * \param p_item the item to transform * \return nothing */ int playlist_ItemToNode( playlist_t *p_playlist,playlist_item_t *p_item ) { int i = 0; if( p_item->i_children == -1 ) { p_item->i_children = 0; } /* Remove it from the array of available items */ for( i = 0 ; i < p_playlist->i_size ; i++ ) { if( p_item == p_playlist->pp_items[i] ) { REMOVE_ELEM( p_playlist->pp_items, p_playlist->i_size, i ); } } var_SetInteger( p_playlist, "item-change", p_item->input.i_id ); return VLC_SUCCESS; }
/** * Moves an item * * This function must be entered with the playlist lock * * \param p_playlist the playlist * \param p_item the item to move * \param p_node the new parent of the item * \param i_newpos the new position under this new parent * \return VLC_SUCCESS or an error */ int playlist_TreeMove( playlist_t * p_playlist, playlist_item_t *p_item, playlist_item_t *p_node, int i_newpos ) { PL_ASSERT_LOCKED; if( p_node->i_children == -1 ) return VLC_EGENERIC; playlist_item_t *p_detach = p_item->p_parent; int i_index = ItemIndex( p_item ); REMOVE_ELEM( p_detach->pp_children, p_detach->i_children, i_index ); if( p_detach == p_node && i_index < i_newpos ) i_newpos--; INSERT_ELEM( p_node->pp_children, p_node->i_children, i_newpos, p_item ); p_item->p_parent = p_node; pl_priv( p_playlist )->b_reset_currently_playing = true; vlc_cond_signal( &pl_priv( p_playlist )->signal ); return VLC_SUCCESS; }
/** * delete an item from a playlist. * * \param p_playlist the playlist to remove from. * \param i_pos the position of the item to remove * \return returns 0 */ int playlist_Delete( playlist_t * p_playlist, int i_pos ) { vlc_value_t val; /* if i_pos is the current played item, playlist should stop playing it */ if( ( p_playlist->i_status == PLAYLIST_RUNNING) && (p_playlist->i_index == i_pos) ) { playlist_Command( p_playlist, PLAYLIST_STOP, 0 ); } vlc_mutex_lock( &p_playlist->object_lock ); if( i_pos >= 0 && i_pos < p_playlist->i_size ) { playlist_item_t *p_item = p_playlist->pp_items[i_pos]; msg_Dbg( p_playlist, "deleting playlist item `%s'", p_item->input.psz_name ); playlist_ItemDelete( p_item ); if( i_pos <= p_playlist->i_index ) { p_playlist->i_index--; } /* Renumber the playlist */ REMOVE_ELEM( p_playlist->pp_items, p_playlist->i_size, i_pos ); if( p_playlist->i_enabled > 0 ) p_playlist->i_enabled--; } vlc_mutex_unlock( &p_playlist->object_lock ); val.b_bool = VLC_TRUE; var_Set( p_playlist, "intf-change", val ); return 0; }
void RtspDelId( rtsp_stream_t *rtsp, rtsp_stream_id_t *id ) { vlc_mutex_lock( &rtsp->lock ); for( int i = 0; i < rtsp->sessionc; i++ ) { rtsp_session_t *ses = rtsp->sessionv[i]; for( int j = 0; j < ses->trackc; j++ ) { if( ses->trackv[j].id == id->sout_id ) { rtsp_strack_t *tr = ses->trackv + j; net_Close( tr->fd ); REMOVE_ELEM( ses->trackv, ses->trackc, j ); } } } vlc_mutex_unlock( &rtsp->lock ); httpd_UrlDelete( id->url ); free( id ); }
int input_item_DelInfo( input_item_t *p_i, const char *psz_cat, const char *psz_name ) { vlc_mutex_lock( &p_i->lock ); int i_cat; info_category_t *p_cat = InputItemFindCat( p_i, &i_cat, psz_cat ); if( !p_cat ) { vlc_mutex_unlock( &p_i->lock ); return VLC_EGENERIC; } if( psz_name ) { /* Remove a specific info */ int i_ret = info_category_DeleteInfo( p_cat, psz_name ); if( i_ret ) { vlc_mutex_unlock( &p_i->lock ); return VLC_EGENERIC; } } else { /* Remove the complete categorie */ info_category_Delete( p_cat ); REMOVE_ELEM( p_i->pp_categories, p_i->i_categories, i_cat ); } vlc_mutex_unlock( &p_i->lock ); vlc_event_t event; event.type = vlc_InputItemInfoChanged; vlc_event_send( &p_i->event_manager, &event ); return VLC_SUCCESS; }
/** * Remove a callback from a variable * * pf_callback and p_data have to be given again, because different objects * might have registered the same callback function. */ int __var_DelCallback( vlc_object_t *p_this, const char *psz_name, vlc_callback_t pf_callback, void *p_data ) { int i_entry, i_var; variable_t *p_var; vlc_mutex_lock( &p_this->var_lock ); i_var = GetUnused( p_this, psz_name ); if( i_var < 0 ) { vlc_mutex_unlock( &p_this->var_lock ); return i_var; } p_var = &p_this->p_vars[i_var]; for( i_entry = p_var->i_entries ; i_entry-- ; ) { if( p_var->p_entries[i_entry].pf_callback == pf_callback && p_var->p_entries[i_entry].p_data == p_data ) { break; } } if( i_entry < 0 ) { vlc_mutex_unlock( &p_this->var_lock ); return VLC_EGENERIC; } REMOVE_ELEM( p_var->p_entries, p_var->i_entries, i_entry ); vlc_mutex_unlock( &p_this->var_lock ); return VLC_SUCCESS; }
/** * This function does the preparsing and issues the art fetching requests */ static void *Thread( void *data ) { playlist_preparser_t *p_preparser = data; for( ;; ) { input_item_t *p_current; input_item_meta_request_option_t i_options; /* */ vlc_mutex_lock( &p_preparser->lock ); if( p_preparser->i_waiting > 0 ) { preparser_entry_t *p_entry = p_preparser->pp_waiting[0]; p_current = p_entry->p_item; i_options = p_entry->i_options; free( p_entry ); REMOVE_ELEM( p_preparser->pp_waiting, p_preparser->i_waiting, 0 ); } else { p_current = NULL; p_preparser->b_live = false; vlc_cond_signal( &p_preparser->wait ); } vlc_mutex_unlock( &p_preparser->lock ); if( !p_current ) break; Preparse( p_preparser, p_current, i_options ); Art( p_preparser, p_current ); vlc_gc_decref(p_current); } return NULL; }
/** **************************************************************************** * Destroy a vlc object * * This function destroys an object that has been previously allocated with * vlc_object_create. The object's refcount must be zero and it must not be * attached to other objects in any way. *****************************************************************************/ void __vlc_object_destroy( vlc_object_t *p_this ) { int i_delay = 0; if( p_this->i_children ) { msg_Err( p_this, "cannot delete object (%i, %s) with children" , p_this->i_object_id, p_this->psz_object_name ); return; } if( p_this->p_parent ) { msg_Err( p_this, "cannot delete object (%i, %s) with a parent", p_this->i_object_id, p_this->psz_object_name ); return; } while( p_this->i_refcount ) { i_delay++; /* Don't warn immediately ... 100ms seems OK */ if( i_delay == 2 ) { msg_Warn( p_this, "refcount is %i, delaying before deletion", p_this->i_refcount ); } else if( i_delay == 12 ) { msg_Err( p_this, "refcount is %i, I have a bad feeling about this", p_this->i_refcount ); } else if( i_delay == 42 ) { msg_Err( p_this, "we waited too long, cancelling destruction" ); return; } msleep( 100000 ); } /* Destroy the associated variables, starting from the end so that * no memmove calls have to be done. */ while( p_this->i_vars ) { var_Destroy( p_this, p_this->p_vars[p_this->i_vars - 1].psz_name ); } free( p_this->p_vars ); vlc_mutex_destroy( &p_this->var_lock ); if( p_this->i_object_type == VLC_OBJECT_ROOT ) { /* We are the root object ... no need to lock. */ free( p_this->p_libvlc->pp_objects ); p_this->p_libvlc->pp_objects = NULL; p_this->p_libvlc->i_objects--; vlc_mutex_destroy( &structure_lock ); } else { int i_index; vlc_mutex_lock( &structure_lock ); /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's * useless to try and recover anything if pp_objects gets smashed. */ i_index = FindIndex( p_this, p_this->p_libvlc->pp_objects, p_this->p_libvlc->i_objects ); REMOVE_ELEM( p_this->p_libvlc->pp_objects, p_this->p_libvlc->i_objects, i_index ); vlc_mutex_unlock( &structure_lock ); } vlc_mutex_destroy( &p_this->object_lock ); vlc_cond_destroy( &p_this->object_wait ); free( p_this ); }
/** * Deletes an item from a playlist. * * This function must be entered without the playlist lock * * \param p_playlist the playlist to remove from. * \param i_id the identifier of the item to delete * \return returns VLC_SUCCESS or an error */ int playlist_Delete( playlist_t * p_playlist, int i_id ) { int i, i_top, i_bottom; int i_pos; vlc_bool_t b_flag = VLC_FALSE; playlist_item_t *p_item = playlist_ItemGetById( p_playlist, i_id ); if( p_item == NULL ) { return VLC_EGENERIC; } if( p_item->i_children > -1 ) { return playlist_NodeDelete( p_playlist, p_item, VLC_TRUE, VLC_FALSE ); } var_SetInteger( p_playlist, "item-deleted", i_id ); i_bottom = 0; i_top = p_playlist->i_all_size - 1; i = i_top / 2; while( p_playlist->pp_all_items[i]->input.i_id != i_id && i_top > i_bottom ) { if( p_playlist->pp_all_items[i]->input.i_id < i_id ) { i_bottom = i + 1; } else { i_top = i - 1; } i = i_bottom + ( i_top - i_bottom ) / 2; } if( p_playlist->pp_all_items[i]->input.i_id == i_id ) { REMOVE_ELEM( p_playlist->pp_all_items, p_playlist->i_all_size, i ); } /* Check if it is the current item */ if( p_playlist->status.p_item == p_item ) { /* Hack we don't call playlist_Control for lock reasons */ p_playlist->status.i_status = PLAYLIST_STOPPED; p_playlist->request.b_request = VLC_TRUE; p_playlist->request.p_item = NULL; msg_Info( p_playlist, "stopping playback" ); b_flag = VLC_TRUE; } /* Get position and update index if needed */ i_pos = playlist_GetPositionById( p_playlist, i_id ); if( i_pos >= 0 && i_pos <= p_playlist->i_index ) { p_playlist->i_index--; } msg_Dbg( p_playlist, "deleting playlist item `%s'", p_item->input.psz_name ); /* Remove the item from all its parent nodes */ for ( i= 0 ; i < p_item->i_parents ; i++ ) { playlist_NodeRemoveItem( p_playlist, p_item, p_item->pp_parents[i]->p_parent ); if( p_item->pp_parents[i]->i_view == VIEW_ALL ) { p_playlist->i_size--; } } /* TODO : Update views */ if( b_flag == VLC_FALSE ) playlist_ItemDelete( p_item ); else p_item->i_flags |= PLAYLIST_REMOVE_FLAG; return VLC_SUCCESS; }
/** RTSP requests handler * @param id selected track for non-aggregate URLs, * NULL for aggregate URLs */ static int RtspHandler( rtsp_stream_t *rtsp, rtsp_stream_id_t *id, httpd_client_t *cl, httpd_message_t *answer, const httpd_message_t *query ) { sout_stream_t *p_stream = rtsp->owner; char psz_sesbuf[17]; const char *psz_session = NULL, *psz; char control[sizeof("rtsp://[]:12345") + NI_MAXNUMERICHOST + strlen( rtsp->psz_path )]; time_t now; time (&now); if( answer == NULL || query == NULL || cl == NULL ) return VLC_SUCCESS; else { /* Build self-referential control URL */ char ip[NI_MAXNUMERICHOST], *ptr; httpd_ServerIP( cl, ip ); ptr = strchr( ip, '%' ); if( ptr != NULL ) *ptr = '\0'; if( strchr( ip, ':' ) != NULL ) sprintf( control, "rtsp://[%s]:%u%s", ip, rtsp->port, rtsp->psz_path ); else sprintf( control, "rtsp://%s:%u%s", ip, rtsp->port, rtsp->psz_path ); } /* */ answer->i_proto = HTTPD_PROTO_RTSP; answer->i_version= 0; answer->i_type = HTTPD_MSG_ANSWER; answer->i_body = 0; answer->p_body = NULL; httpd_MsgAdd( answer, "Server", "%s", PACKAGE_STRING ); /* Date: is always allowed, and sometimes mandatory with RTSP/2.0. */ struct tm ut; if (gmtime_r (&now, &ut) != NULL) { /* RFC1123 format, GMT is mandatory */ static const char wdays[7][4] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static const char mons[12][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; httpd_MsgAdd (answer, "Date", "%s, %02u %s %04u %02u:%02u:%02u GMT", wdays[ut.tm_wday], ut.tm_mday, mons[ut.tm_mon], 1900 + ut.tm_year, ut.tm_hour, ut.tm_min, ut.tm_sec); } if( query->i_proto != HTTPD_PROTO_RTSP ) { answer->i_status = 505; } else if( httpd_MsgGet( query, "Require" ) != NULL ) { answer->i_status = 551; httpd_MsgAdd( answer, "Unsupported", "%s", httpd_MsgGet( query, "Require" ) ); } else switch( query->i_type ) { case HTTPD_MSG_DESCRIBE: { /* Aggregate-only */ if( id != NULL ) { answer->i_status = 460; break; } answer->i_status = 200; httpd_MsgAdd( answer, "Content-Type", "%s", "application/sdp" ); httpd_MsgAdd( answer, "Content-Base", "%s", control ); answer->p_body = (uint8_t *)SDPGenerate( rtsp->owner, control ); if( answer->p_body != NULL ) answer->i_body = strlen( (char *)answer->p_body ); else answer->i_status = 500; break; } case HTTPD_MSG_SETUP: /* Non-aggregate-only */ if( id == NULL ) { answer->i_status = 459; break; } psz_session = httpd_MsgGet( query, "Session" ); answer->i_status = 461; for( const char *tpt = httpd_MsgGet( query, "Transport" ); tpt != NULL; tpt = transport_next( tpt ) ) { bool b_multicast = true, b_unsupp = false; unsigned loport = 5004, hiport = 5005; /* from RFC3551 */ /* Check transport protocol. */ /* Currently, we only support RTP/AVP over UDP */ if( strncmp( tpt, "RTP/AVP", 7 ) ) continue; tpt += 7; if( strncmp( tpt, "/UDP", 4 ) == 0 ) tpt += 4; if( strchr( ";,", *tpt ) == NULL ) continue; /* Parse transport options */ for( const char *opt = parameter_next( tpt ); opt != NULL; opt = parameter_next( opt ) ) { if( strncmp( opt, "multicast", 9 ) == 0) b_multicast = true; else if( strncmp( opt, "unicast", 7 ) == 0 ) b_multicast = false; else if( sscanf( opt, "client_port=%u-%u", &loport, &hiport ) == 2 ) ; else if( strncmp( opt, "mode=", 5 ) == 0 ) { if( strncasecmp( opt + 5, "play", 4 ) && strncasecmp( opt + 5, "\"PLAY\"", 6 ) ) { /* Not playing?! */ b_unsupp = true; break; } } else if( strncmp( opt,"destination=", 12 ) == 0 ) { answer->i_status = 403; b_unsupp = true; } else { /* * Every other option is unsupported: * * "source" and "append" are invalid (server-only); * "ssrc" also (as clarified per RFC2326bis). * * For multicast, "port", "layers", "ttl" are set by the * stream output configuration. * * For unicast, we want to decide "server_port" values. * * "interleaved" is not implemented. */ b_unsupp = true; break; } } if( b_unsupp ) continue; if( b_multicast ) { const char *dst = id->dst; if( dst == NULL ) continue; if( psz_session == NULL ) { /* Create a dummy session ID */ snprintf( psz_sesbuf, sizeof( psz_sesbuf ), "%d", rand() ); psz_session = psz_sesbuf; } answer->i_status = 200; httpd_MsgAdd( answer, "Transport", "RTP/AVP/UDP;destination=%s;port=%u-%u;" "ttl=%d;mode=play", dst, id->loport, id->hiport, ( id->ttl > 0 ) ? id->ttl : 1 ); } else { char ip[NI_MAXNUMERICHOST], src[NI_MAXNUMERICHOST]; rtsp_session_t *ses = NULL; rtsp_strack_t track = { id->sout_id, -1, false }; int sport; if( httpd_ClientIP( cl, ip ) == NULL ) { answer->i_status = 500; continue; } track.fd = net_ConnectDgram( p_stream, ip, loport, -1, IPPROTO_UDP ); if( track.fd == -1 ) { msg_Err( p_stream, "cannot create RTP socket for %s port %u", ip, loport ); answer->i_status = 500; continue; } net_GetSockAddress( track.fd, src, &sport ); vlc_mutex_lock( &rtsp->lock ); if( psz_session == NULL ) { ses = RtspClientNew( rtsp ); snprintf( psz_sesbuf, sizeof( psz_sesbuf ), "%"PRIx64, ses->id ); psz_session = psz_sesbuf; } else { /* FIXME: we probably need to remove an access out, * if there is already one for the same ID */ ses = RtspClientGet( rtsp, psz_session ); if( ses == NULL ) { answer->i_status = 454; vlc_mutex_unlock( &rtsp->lock ); continue; } } INSERT_ELEM( ses->trackv, ses->trackc, ses->trackc, track ); vlc_mutex_unlock( &rtsp->lock ); httpd_ServerIP( cl, ip ); if( strcmp( src, ip ) ) { /* Specify source IP if it is different from the RTSP * control connection server address */ char *ptr = strchr( src, '%' ); if( ptr != NULL ) *ptr = '\0'; /* remove scope ID */ httpd_MsgAdd( answer, "Transport", "RTP/AVP/UDP;unicast;source=%s;" "client_port=%u-%u;server_port=%u-%u;" "ssrc=%08X;mode=play", src, loport, loport + 1, sport, sport + 1, id->ssrc ); } else { httpd_MsgAdd( answer, "Transport", "RTP/AVP/UDP;unicast;" "client_port=%u-%u;server_port=%u-%u;" "ssrc=%08X;mode=play", loport, loport + 1, sport, sport + 1, id->ssrc ); } answer->i_status = 200; } break; } break; case HTTPD_MSG_PLAY: { rtsp_session_t *ses; answer->i_status = 200; psz_session = httpd_MsgGet( query, "Session" ); const char *range = httpd_MsgGet (query, "Range"); if (range && strncmp (range, "npt=", 4)) { answer->i_status = 501; break; } vlc_mutex_lock( &rtsp->lock ); ses = RtspClientGet( rtsp, psz_session ); if( ses != NULL ) { /* FIXME: we really need to limit the number of tracks... */ char info[ses->trackc * ( strlen( control ) + sizeof("url=/trackID=123;seq=65535, ") ) + 1]; size_t infolen = 0; for( int i = 0; i < ses->trackc; i++ ) { rtsp_strack_t *tr = ses->trackv + i; if( ( id == NULL ) || ( tr->id == id->sout_id ) ) { if( !tr->playing ) { tr->playing = true; rtp_add_sink( tr->id, tr->fd, false ); } infolen += sprintf( info + infolen, "url=%s/trackID=%u;seq=%u, ", control, rtp_get_num( tr->id ), rtp_get_seq( tr->id ) ); } } if( infolen > 0 ) { info[infolen - 2] = '\0'; /* remove trailing ", " */ httpd_MsgAdd( answer, "RTP-Info", "%s", info ); } } vlc_mutex_unlock( &rtsp->lock ); if( httpd_MsgGet( query, "Scale" ) != NULL ) httpd_MsgAdd( answer, "Scale", "1." ); break; } case HTTPD_MSG_PAUSE: answer->i_status = 405; httpd_MsgAdd( answer, "Allow", "%s, TEARDOWN, PLAY, GET_PARAMETER", ( id != NULL ) ? "SETUP" : "DESCRIBE" ); break; case HTTPD_MSG_GETPARAMETER: if( query->i_body > 0 ) { answer->i_status = 451; break; } psz_session = httpd_MsgGet( query, "Session" ); answer->i_status = 200; break; case HTTPD_MSG_TEARDOWN: { rtsp_session_t *ses; answer->i_status = 200; psz_session = httpd_MsgGet( query, "Session" ); vlc_mutex_lock( &rtsp->lock ); ses = RtspClientGet( rtsp, psz_session ); if( ses != NULL ) { if( id == NULL ) /* Delete the entire session */ RtspClientDel( rtsp, ses ); else /* Delete one track from the session */ for( int i = 0; i < ses->trackc; i++ ) { if( ses->trackv[i].id == id->sout_id ) { rtp_del_sink( id->sout_id, ses->trackv[i].fd ); REMOVE_ELEM( ses->trackv, ses->trackc, i ); } } } vlc_mutex_unlock( &rtsp->lock ); break; } default: return VLC_EGENERIC; } if( psz_session ) httpd_MsgAdd( answer, "Session", "%s"/*;timeout=5*/, psz_session ); httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body ); httpd_MsgAdd( answer, "Cache-Control", "no-cache" ); psz = httpd_MsgGet( query, "Cseq" ); if( psz != NULL ) httpd_MsgAdd( answer, "Cseq", "%s", psz ); psz = httpd_MsgGet( query, "Timestamp" ); if( psz != NULL ) httpd_MsgAdd( answer, "Timestamp", "%s", psz ); return VLC_SUCCESS; }
/** * Perform an action on a variable * * \param p_this The object that holds the variable * \param psz_name The name of the variable * \param i_action The action to perform. Must be one of \ref var_action * \param p_val First action parameter * \param p_val2 Second action parameter */ int var_Change( vlc_object_t *p_this, const char *psz_name, int i_action, vlc_value_t *p_val, vlc_value_t *p_val2 ) { int ret = VLC_SUCCESS; variable_t *p_var; vlc_value_t oldval; vlc_value_t newval; assert( p_this ); vlc_object_internals_t *p_priv = vlc_internals( p_this ); p_var = Lookup( p_this, psz_name ); if( p_var == NULL ) { vlc_mutex_unlock( &p_priv->var_lock ); return VLC_ENOVAR; } switch( i_action ) { case VLC_VAR_SETMIN: if( p_var->i_type & VLC_VAR_HASMIN ) { p_var->ops->pf_free( &p_var->min ); } p_var->i_type |= VLC_VAR_HASMIN; p_var->min = *p_val; p_var->ops->pf_dup( &p_var->min ); CheckValue( p_var, &p_var->val ); break; case VLC_VAR_GETMIN: if( p_var->i_type & VLC_VAR_HASMIN ) *p_val = p_var->min; else ret = VLC_EGENERIC; break; case VLC_VAR_SETMAX: if( p_var->i_type & VLC_VAR_HASMAX ) { p_var->ops->pf_free( &p_var->max ); } p_var->i_type |= VLC_VAR_HASMAX; p_var->max = *p_val; p_var->ops->pf_dup( &p_var->max ); CheckValue( p_var, &p_var->val ); break; case VLC_VAR_GETMAX: if( p_var->i_type & VLC_VAR_HASMAX ) *p_val = p_var->max; else ret = VLC_EGENERIC; break; case VLC_VAR_SETSTEP: if( p_var->i_type & VLC_VAR_HASSTEP ) { p_var->ops->pf_free( &p_var->step ); } p_var->i_type |= VLC_VAR_HASSTEP; p_var->step = *p_val; p_var->ops->pf_dup( &p_var->step ); CheckValue( p_var, &p_var->val ); break; case VLC_VAR_GETSTEP: if( p_var->i_type & VLC_VAR_HASSTEP ) *p_val = p_var->step; else ret = VLC_EGENERIC; break; case VLC_VAR_ADDCHOICE: { int i = p_var->choices.i_count; INSERT_ELEM( p_var->choices.p_values, p_var->choices.i_count, i, *p_val ); INSERT_ELEM( p_var->choices_text.p_values, p_var->choices_text.i_count, i, *p_val ); p_var->ops->pf_dup( &p_var->choices.p_values[i] ); p_var->choices_text.p_values[i].psz_string = ( p_val2 && p_val2->psz_string ) ? strdup( p_val2->psz_string ) : NULL; CheckValue( p_var, &p_var->val ); TriggerListCallback(p_this, p_var, psz_name, VLC_VAR_ADDCHOICE, p_val); break; } case VLC_VAR_DELCHOICE: { int i; for( i = 0 ; i < p_var->choices.i_count ; i++ ) if( p_var->ops->pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 ) break; if( i == p_var->choices.i_count ) { /* Not found */ vlc_mutex_unlock( &p_priv->var_lock ); return VLC_EGENERIC; } if( p_var->i_default > i ) p_var->i_default--; else if( p_var->i_default == i ) p_var->i_default = -1; p_var->ops->pf_free( &p_var->choices.p_values[i] ); free( p_var->choices_text.p_values[i].psz_string ); REMOVE_ELEM( p_var->choices.p_values, p_var->choices.i_count, i ); REMOVE_ELEM( p_var->choices_text.p_values, p_var->choices_text.i_count, i ); CheckValue( p_var, &p_var->val ); TriggerListCallback(p_this, p_var, psz_name, VLC_VAR_DELCHOICE, p_val); break; } case VLC_VAR_CHOICESCOUNT: p_val->i_int = p_var->choices.i_count; break; case VLC_VAR_CLEARCHOICES: for( int i = 0 ; i < p_var->choices.i_count ; i++ ) p_var->ops->pf_free( &p_var->choices.p_values[i] ); for( int i = 0 ; i < p_var->choices_text.i_count ; i++ ) free( p_var->choices_text.p_values[i].psz_string ); if( p_var->choices.i_count ) free( p_var->choices.p_values ); if( p_var->choices_text.i_count ) free( p_var->choices_text.p_values ); p_var->choices.i_count = 0; p_var->choices.p_values = NULL; p_var->choices_text.i_count = 0; p_var->choices_text.p_values = NULL; p_var->i_default = -1; TriggerListCallback(p_this, p_var, psz_name, VLC_VAR_CLEARCHOICES, NULL); break; case VLC_VAR_SETDEFAULT: { int i; /* FIXME: the list is sorted, dude. Use something cleverer. */ for( i = 0 ; i < p_var->choices.i_count ; i++ ) if( p_var->ops->pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 ) break; if( i == p_var->choices.i_count ) /* Not found */ break; p_var->i_default = i; CheckValue( p_var, &p_var->val ); break; } case VLC_VAR_SETVALUE: /* Duplicate data if needed */ newval = *p_val; p_var->ops->pf_dup( &newval ); /* Backup needed stuff */ oldval = p_var->val; /* Check boundaries and list */ CheckValue( p_var, &newval ); /* Set the variable */ p_var->val = newval; /* Free data if needed */ p_var->ops->pf_free( &oldval ); break; case VLC_VAR_GETCHOICES: p_val->p_list = xmalloc( sizeof(vlc_list_t) ); p_val->p_list->p_values = xmalloc( p_var->choices.i_count * sizeof(vlc_value_t) ); p_val->p_list->i_type = p_var->i_type; p_val->p_list->i_count = p_var->choices.i_count; if( p_val2 ) { p_val2->p_list = xmalloc( sizeof(vlc_list_t) ); p_val2->p_list->p_values = xmalloc( p_var->choices.i_count * sizeof(vlc_value_t) ); p_val2->p_list->i_type = VLC_VAR_STRING; p_val2->p_list->i_count = p_var->choices.i_count; } for( int i = 0 ; i < p_var->choices.i_count ; i++ ) { p_val->p_list->p_values[i] = p_var->choices.p_values[i]; p_var->ops->pf_dup( &p_val->p_list->p_values[i] ); if( p_val2 ) { p_val2->p_list->p_values[i].psz_string = p_var->choices_text.p_values[i].psz_string ? strdup(p_var->choices_text.p_values[i].psz_string) : NULL; } } break; case VLC_VAR_SETTEXT: free( p_var->psz_text ); if( p_val && p_val->psz_string ) p_var->psz_text = strdup( p_val->psz_string ); else p_var->psz_text = NULL; break; case VLC_VAR_GETTEXT: p_val->psz_string = p_var->psz_text ? strdup( p_var->psz_text ) : NULL; break; default: break; } vlc_mutex_unlock( &p_priv->var_lock ); return ret; }