static int stop(struct action_event *event)
{
	if (obtain_instanceid(event, NULL) < 0) {
		return -1;
	}

	service_lock();
	switch (transport_state_) {
	case TRANSPORT_STOPPED:
		// nothing to change.
		break;
	case TRANSPORT_PLAYING:
	case TRANSPORT_TRANSITIONING:
	case TRANSPORT_PAUSED_RECORDING:
	case TRANSPORT_RECORDING:
	case TRANSPORT_PAUSED_PLAYBACK:
		output_stop();
		change_transport_state(TRANSPORT_STOPPED);
		break;

	case TRANSPORT_NO_MEDIA_PRESENT:
		/* action not allowed in these states - error 701 */
		upnp_set_error(event, UPNP_TRANSPORT_E_TRANSITION_NA,
			       "Transition not allowed; allowed=%s",
			       get_var(TRANSPORT_VAR_CUR_TRANSPORT_ACTIONS));

		break;
	}
	service_unlock();

	return 0;
}
static int seek(struct action_event *event)
{
	if (obtain_instanceid(event, NULL) < 0) {
		return -1;
	}

	char *unit = upnp_get_string(event, "Unit");
	if (strcmp(unit, "REL_TIME") == 0) {
		// This is the only thing we support right now.
		char *target = upnp_get_string(event, "Target");
		gint64 nanos = parse_upnp_time(target);
		service_lock();
		if (output_seek(nanos) == 0) {
			// TODO(hzeller): Seeking might take some time,
			// pretend to already be there. Should we go into
			// TRANSITION mode ?
			// (gstreamer will go into PAUSE, then PLAYING)
			replace_var(TRANSPORT_VAR_REL_TIME_POS, target);
		}
		service_unlock();
		free(target);
	}
	free(unit);

	return 0;
}
static int set_avtransport_uri(struct action_event *event)
{
	if (obtain_instanceid(event, NULL) < 0) {
		return -1;
	}
	char *uri = upnp_get_string(event, "CurrentURI");
	if (uri == NULL) {
		return -1;
	}

	service_lock();
	char *meta = upnp_get_string(event, "CurrentURIMetaData");
	// Transport URI/Meta set now, current URI/Meta when it starts playing.
	int requires_meta_update = replace_transport_uri_and_meta(uri, meta);

	if (transport_state_ == TRANSPORT_PLAYING) {
		// Uh, wrong state.
		// Usually, this should not be called while we are PLAYING, only
		// STOPPED or PAUSED. But if actually some controller sets this
		// while playing, probably the best is to update the current
		// current URI/Meta as well to reflect the state best.
		replace_current_uri_and_meta(uri, meta);
	}

	output_set_uri(uri, (requires_meta_update
			     ? update_meta_from_stream
			     : NULL));
	service_unlock();

	free(uri);
	free(meta);

	return 0;
}
static int set_avtransport_uri(struct action_event *event)
{
	int rc = 0;

	ENTER();

	if (obtain_instanceid(event, NULL)) {
		LEAVE();
		return -1;
	}
	char *uri = upnp_get_string(event, "CurrentURI");
	if (uri == NULL) {
		LEAVE();
		return -1;
	}

	service_lock();

	char *meta = upnp_get_string(event, "CurrentURIMetaData");
	int requires_meta_update = replace_transport_uri_and_meta(uri, meta);

	output_set_uri(uri, (requires_meta_update
			     ? update_meta_from_stream
			     : NULL));

	notify_changed_uris();
	service_unlock();

	free(uri);
	free(meta);

	LEAVE();
	return rc;
}
static int pause_stream(struct action_event *event)
{
	if (obtain_instanceid(event, NULL) < 0) {
		return -1;
	}

	int rc = 0;
	service_lock();
	switch (transport_state_) {
        case TRANSPORT_PAUSED_PLAYBACK:
		// Nothing to change.
		break;

	case TRANSPORT_PLAYING:
		if (output_pause()) {
			upnp_set_error(event, 704, "Pause failed");
			rc = -1;
		} else {
			change_transport_state(TRANSPORT_PAUSED_PLAYBACK);
		}
		break;

        default:
		/* action not allowed in these states - error 701 */
		upnp_set_error(event, UPNP_TRANSPORT_E_TRANSITION_NA,
			       "Transition not allowed; allowed=%s",
			       get_var(TRANSPORT_VAR_CUR_TRANSPORT_ACTIONS));
		rc = -1;
        }
	service_unlock();

	return rc;
}
static int set_next_avtransport_uri(struct action_event *event)
{
	if (obtain_instanceid(event, NULL) < 0) {
		return -1;
	}

	char *next_uri = upnp_get_string(event, "NextURI");
	if (next_uri == NULL) {
		return -1;
	}

	int rc = 0;
	service_lock();

	output_set_next_uri(next_uri);
	replace_var(TRANSPORT_VAR_NEXT_AV_URI, next_uri);

	char *next_uri_meta = upnp_get_string(event, "NextURIMetaData");
	if (next_uri_meta == NULL) {
		rc = -1;
	} else {
		replace_var(TRANSPORT_VAR_NEXT_AV_URI_META, next_uri_meta);
	}

	service_unlock();

	free(next_uri);
	free(next_uri_meta);

	return rc;
}
static int get_transport_info(struct action_event *event)
{
	int rc;
	ENTER();

	if (obtain_instanceid(event, NULL)) {
		rc = -1;
		goto out;
	}

	rc = upnp_append_variable(event, TRANSPORT_VAR_TRANSPORT_STATE,
				  "CurrentTransportState");
	if (rc)
		goto out;

	rc = upnp_append_variable(event, TRANSPORT_VAR_TRANSPORT_STATUS,
				  "CurrentTransportStatus");
	if (rc)
		goto out;

	rc = upnp_append_variable(event,
				  TRANSPORT_VAR_TRANSPORT_PLAY_SPEED,
				  "CurrentSpeed");
	if (rc)
		goto out;

      out:
	LEAVE();
	return rc;
}
static int get_device_caps(struct action_event *event)
{
	if (obtain_instanceid(event, NULL) < 0) {
		return -1;
	}
	// TODO: implement ?
	return 0;
}
static int get_transport_settings(struct action_event *event)
{
	if (obtain_instanceid(event, NULL) < 0) {
		return -1;
	}
	// TODO: what variables to add ?
	return 0;
}
static int set_streaming_playlist(struct action_event *event)  
{
	if (obtain_instanceid(event, NULL) < 0) {
		return -1;
	}

	char *playlistdata = upnp_get_string(event, "PlaylistData");
	if (playlistdata == NULL) {
		return -1;
	}
	int playlistdatalength = atoi(upnp_get_string(event, "PlaylistDataLength"));
	/*char *playlistmimetype = upnp_get_string(event, "PlaylistMIMEType");
	if (playlistmimetype == NULL) {
		free(playlistdata);
		return -1;
	} */
	char *playliststep = upnp_get_string(event, "PlaylistStep");  //Initial Continue Stop Reset
	if (playliststep == NULL) {
		free(playlistdata);
	//	free(playlistmimetype);
		return -1;
	}

	int rc = 0;
	service_lock();
	if(strcmp(playliststep, "Initial") == 0){
		//TODO:
		rc = write_playlist(event, playlistdata, playlistdatalength, "w");
		
	}

	if(strcmp(playliststep, "Continue") == 0){
		rc = write_playlist(event, playlistdata, playlistdatalength, "a");
		
	}

	if(strcmp(playliststep, "Stop") == 0){
		//TODO:  Indicates that the current streaming playlist operation will end when all pending playlist data at then device is consumed.
		if(playlistdata)
			rc = write_playlist(event, playlistdata, playlistdatalength,  "a");
		output_set_playlist(M3U_STREAMINGPLAYLIST_PATH);
	}

	if(strcmp(playliststep, "Reset") == 0){
		//TODO: Indicates that processing of the current streaming playlist ends immediately. any pending playlist data for the streaming playlist is discarded.
		output_set_playlist(M3U_STREAMINGPLAYLIST_PATH);
	}

	if(!rc)
		replace_var(TRANSPORT_VAR_AAT_PLAYLIST_STEP, playliststep);
	service_unlock();
	if(playlistdata)
		free(playlistdata);
	free(playliststep);
	return rc;

}
//TODO:FIXME
static int set_static_playlist(struct action_event *event)  
{
	if (obtain_instanceid(event, NULL) < 0) {
		return -1;
	}
	
	return 0;

}
static int get_current_transportactions(struct action_event *event)
{
	if (obtain_instanceid(event, NULL) < 0) {
		return -1;
	}

	upnp_append_variable(event, TRANSPORT_VAR_CUR_TRANSPORT_ACTIONS,
			     "Actions");
	return 0;
}
static int get_transport_info(struct action_event *event)
{
	if (obtain_instanceid(event, NULL) < 0) {
		return -1;
	}

	upnp_append_variable(event, TRANSPORT_VAR_TRANSPORT_STATE,
			     "CurrentTransportState");
	upnp_append_variable(event, TRANSPORT_VAR_TRANSPORT_STATUS,
			     "CurrentTransportStatus");
	upnp_append_variable(event, TRANSPORT_VAR_TRANSPORT_PLAY_SPEED,
			     "CurrentSpeed");
	return 0;
}
static int get_device_caps(struct action_event *event)
{
	int rc = 0;
	ENTER();

	if (obtain_instanceid(event, NULL)) {
		rc = -1;
		goto out;
	}

      out:
	LEAVE();
	return rc;
}
static int play(struct action_event *event)
{
	if (obtain_instanceid(event, NULL) < 0) {
		return -1;
	}

	int rc = 0;
	service_lock();
	switch (transport_state_) {
	// even if already playing, we must restart playback when Play
	// action is executed. Kinsky, for example, would not send Stop
	// when changing tracks and playback is already in progress -
	// it will just set new URI, and send Play command
	case TRANSPORT_PLAYING:
	case TRANSPORT_STOPPED:
		// If we were stopped before, we start a new song now. So just
		// set the time to zero now; otherwise we will see the old
		// value of the previous song until it updates some fractions
		// of a second later.
		replace_var(TRANSPORT_VAR_REL_TIME_POS, kZeroTime);

		/* >>> fall through */

	case TRANSPORT_PAUSED_PLAYBACK:
		if (output_play(&inform_play_transition_from_output)) {
			upnp_set_error(event, 704, "Playing failed");
			rc = -1;
		} else {
			change_transport_state(TRANSPORT_PLAYING);
			const char *av_uri = get_var(TRANSPORT_VAR_AV_URI);
			const char *av_meta = get_var(TRANSPORT_VAR_AV_URI_META);
			replace_current_uri_and_meta(av_uri, av_meta);
		}
		break;

	case TRANSPORT_NO_MEDIA_PRESENT:
	case TRANSPORT_TRANSITIONING:
	case TRANSPORT_PAUSED_RECORDING:
	case TRANSPORT_RECORDING:
		/* action not allowed in these states - error 701 */
		upnp_set_error(event, UPNP_TRANSPORT_E_TRANSITION_NA,
			       "Transition not allowed; allowed=%s",
			       get_var(TRANSPORT_VAR_CUR_TRANSPORT_ACTIONS));
		rc = -1;
		break;
	}
	service_unlock();

	return rc;
}
static int get_transport_settings(struct action_event *event)
{
	int rc = 0;
	ENTER();

	if (obtain_instanceid(event, NULL)) {
		rc = -1;
		goto out;
	}

      out:
	LEAVE();
	return rc;
}
static int get_playlist_info(struct action_event *event)  
{
	if (obtain_instanceid(event, NULL) < 0) {
		return -1;
	}
	char *playlisttype = upnp_get_string(event, "PlaylistType");
	if (playlisttype == NULL) {
		return -1;
	}

	//fprintf(stderr, "InstanceID = %s \n", unit);
	free(playlisttype);

	return 0;

}
static int play(struct action_event *event)
{
	int rc = 0;

	ENTER();

	if (obtain_instanceid(event, NULL)) {
		LEAVE();
		return -1;
	}

	service_lock();
	switch (transport_state_) {
	case TRANSPORT_PLAYING:
		// For clients that didn't get it.
		change_and_notify_transport(TRANSPORT_PLAYING);
		// Set TransportPlaySpeed to '1'
		break;
	case TRANSPORT_STOPPED:
	case TRANSPORT_PAUSED_PLAYBACK:
		if (output_play(&inform_done_playing)) {
			upnp_set_error(event, 704, "Playing failed");
			rc = -1;
		} else {
			change_and_notify_transport(TRANSPORT_PLAYING);
		}
		// Set TransportPlaySpeed to '1'
		break;

	case TRANSPORT_NO_MEDIA_PRESENT:
	case TRANSPORT_TRANSITIONING:
	case TRANSPORT_PAUSED_RECORDING:
	case TRANSPORT_RECORDING:
		/* action not allowed in these states - error 701 */
		upnp_set_error(event, UPNP_TRANSPORT_E_TRANSITION_NA,
			       "Transition not allowed");
		rc = -1;

		break;
	}
	service_unlock();

	LEAVE();
	return rc;
}
static int get_current_transportactions(struct action_event *event)
{
	int rc;
	ENTER();

	if (obtain_instanceid(event, NULL)) {
		rc = -1;
		goto out;
	}

	rc = upnp_append_variable(event, TRANSPORT_VAR_CUR_TRANSPORT_ACTIONS,
				  "Actions");
	if (rc)
		goto out;
      out:
	LEAVE();
	return rc;
}
//TODO:FIXME
static int set_playmode(struct action_event *event)
{
	if (obtain_instanceid(event, NULL) < 0) {
		return -1;
	}
	char *playmode = upnp_get_string(event, "NewPlayMode");
	if (playmode == NULL) {
		return -1;
	}
//TODO: support this playmode?  error 712
	
// This is the only thing we support right now.
	service_lock();
	replace_var(TRANSPORT_VAR_CUR_PLAY_MODE, playmode);
	service_unlock();
	free(playmode);
	return 0;
}
static int get_position_info(struct action_event *event)
{
	if (obtain_instanceid(event, NULL) < 0) {
		return -1;
	}

	upnp_append_variable(event, TRANSPORT_VAR_CUR_TRACK, "Track");
	upnp_append_variable(event, TRANSPORT_VAR_CUR_TRACK_DUR,
			     "TrackDuration");
	upnp_append_variable(event, TRANSPORT_VAR_CUR_TRACK_META,
			     "TrackMetaData");
	upnp_append_variable(event, TRANSPORT_VAR_CUR_TRACK_URI, "TrackURI");
	upnp_append_variable(event, TRANSPORT_VAR_REL_TIME_POS, "RelTime");
	upnp_append_variable(event, TRANSPORT_VAR_ABS_TIME_POS, "AbsTime");
	upnp_append_variable(event, TRANSPORT_VAR_REL_CTR_POS, "RelCount");
	upnp_append_variable(event, TRANSPORT_VAR_ABS_CTR_POS, "AbsCount");

	return 0;
}
static int get_media_info(struct action_event *event)
{
	if (obtain_instanceid(event, NULL) < 0) {
		return -1;
	}

	upnp_append_variable(event, TRANSPORT_VAR_NR_TRACKS, "NrTracks");
	upnp_append_variable(event, TRANSPORT_VAR_CUR_MEDIA_DUR,
			     "MediaDuration");
	upnp_append_variable(event, TRANSPORT_VAR_AV_URI, "CurrentURI");
	upnp_append_variable(event, TRANSPORT_VAR_AV_URI_META,
			     "CurrentURIMetaData");
	upnp_append_variable(event, TRANSPORT_VAR_NEXT_AV_URI, "NextURI");
	upnp_append_variable(event, TRANSPORT_VAR_NEXT_AV_URI_META,
			     "NextURIMetaData");
	upnp_append_variable(event, TRANSPORT_VAR_REC_MEDIA, "PlayMedium");
	upnp_append_variable(event, TRANSPORT_VAR_REC_MEDIUM, "RecordMedium");
	upnp_append_variable(event, TRANSPORT_VAR_REC_MEDIUM_WR_STATUS,
			     "WriteStatus");
	return 0;
}
static int pause_stream(struct action_event *event)
{
	int rc = 0;
	ENTER();

	if (obtain_instanceid(event, NULL)) {
		LEAVE();
		return -1;
	}

	service_lock();
	switch (transport_state_) {
        case TRANSPORT_PAUSED_PLAYBACK:
		// For clients that didn't get it.
		change_and_notify_transport(TRANSPORT_PAUSED_PLAYBACK);
		break;

	case TRANSPORT_PLAYING:
		if (output_pause()) {
			upnp_set_error(event, 704, "Pause failed");
			rc = -1;
		} else {
			change_and_notify_transport(TRANSPORT_PAUSED_PLAYBACK);
		}
		// Set TransportPlaySpeed to '1'
		break;

        default:
		/* action not allowed in these states - error 701 */
		upnp_set_error(event, UPNP_TRANSPORT_E_TRANSITION_NA,
			       "Transition not allowed");
		rc = -1;
        }
	service_unlock();

	LEAVE();

	return rc;
}
static int set_next_avtransport_uri(struct action_event *event)
{
	int rc = 0;
	char *value;

	ENTER();

	if (obtain_instanceid(event, NULL)) {
		LEAVE();
		return -1;
	}

	value = upnp_get_string(event, "NextURI");
	if (value == NULL) {
		LEAVE();
		return -1;
	}

	service_lock();

	output_set_next_uri(value);
	change_var_and_notify(TRANSPORT_VAR_NEXT_AV_URI, value);

	printf("%s: NextURI='%s'\n", __FUNCTION__, value);
	free(value);
	value = upnp_get_string(event, "NextURIMetaData");
	if (value == NULL) {
		rc = -1;
	} else {
		change_var_and_notify(TRANSPORT_VAR_NEXT_AV_URI_META, value);
		free(value);
	}

	service_unlock();

	LEAVE();
	return rc;
}
static int stop(struct action_event *event)
{
	ENTER();

	if (obtain_instanceid(event, NULL)) {
		return -1;
	}

	service_lock();
	switch (transport_state_) {
	case TRANSPORT_STOPPED:
		// For clients that didn't get it.
		change_and_notify_transport(TRANSPORT_STOPPED);
		break;
	case TRANSPORT_PLAYING:
	case TRANSPORT_TRANSITIONING:
	case TRANSPORT_PAUSED_RECORDING:
	case TRANSPORT_RECORDING:
	case TRANSPORT_PAUSED_PLAYBACK:
		output_stop();
		change_and_notify_transport(TRANSPORT_STOPPED);
		// Set TransportPlaySpeed to '1'
		break;

	case TRANSPORT_NO_MEDIA_PRESENT:
		/* action not allowed in these states - error 701 */
		upnp_set_error(event, UPNP_TRANSPORT_E_TRANSITION_NA,
			       "Transition not allowed");

		break;
	}
	service_unlock();

	LEAVE();

	return 0;
}
static int get_position_info(struct action_event *event)
{
	int rc;
	ENTER();

	if (obtain_instanceid(event, NULL)) {
		rc = -1;
		goto out;
	}
	
	gint64 duration, position;
	service_lock();
	const int pos_result = output_get_position(&duration, &position);
	service_unlock();
	if (pos_result == 0) {
		char tbuf[32];
		print_upnp_time_into_buffer(tbuf, sizeof(tbuf), duration);
		replace_var(TRANSPORT_VAR_CUR_TRACK_DUR, tbuf);
		print_upnp_time_into_buffer(tbuf, sizeof(tbuf), position);
		replace_var(TRANSPORT_VAR_REL_TIME_POS, tbuf);
	}

	rc = upnp_append_variable(event, TRANSPORT_VAR_CUR_TRACK, "Track");
	if (rc)
		goto out;

	rc = upnp_append_variable(event, TRANSPORT_VAR_CUR_TRACK_DUR,
				  "TrackDuration");
	if (rc)
		goto out;

	rc = upnp_append_variable(event, TRANSPORT_VAR_CUR_TRACK_META,
				  "TrackMetaData");
	if (rc)
		goto out;

	rc = upnp_append_variable(event, TRANSPORT_VAR_CUR_TRACK_URI,
				  "TrackURI");
	if (rc)
		goto out;

	rc = upnp_append_variable(event, TRANSPORT_VAR_REL_TIME_POS,
				  "RelTime");
	if (rc)
		goto out;

	rc = upnp_append_variable(event, TRANSPORT_VAR_ABS_TIME_POS,
				  "AbsTime");
	if (rc)
		goto out;

	rc = upnp_append_variable(event, TRANSPORT_VAR_REL_CTR_POS,
				  "RelCount");
	if (rc)
		goto out;

	rc = upnp_append_variable(event, TRANSPORT_VAR_ABS_CTR_POS,
				  "AbsCount");
	if (rc)
		goto out;

      out:
	LEAVE();
	return rc;
}