int upnp_append_variable(struct action_event *event, int varnum, char *paramname) { char *value; struct service *service = event->service; int retval = -1; ENTER(); if (varnum >= service->variable_count) { upnp_set_error(event, UPNP_E_INTERNAL_ERROR, "Internal Error - illegal variable number %d", varnum); goto out; } ithread_mutex_lock(service->service_mutex); value = (char *) service->variable_values[varnum]; if (value == NULL) { upnp_set_error(event, UPNP_E_INTERNAL_ERROR, "Internal Error"); } else { retval = upnp_add_response(event, paramname, value); } ithread_mutex_unlock(service->service_mutex); out: LEAVE(); return retval; }
DBG_STATIC int xpause(struct action_event *event) { int rc = 0; if (upnp_obtain_instanceid(event, NULL)) { upnp_set_error(event, UPNP_TRANSPORT_E_INVALID_IID, "ID non-zero invalid"); return -1; } // Check MPD connection if (check_mpd_connection(TRUE) == STATUS_FAIL) return -1; ithread_mutex_lock(&transport_mutex); switch (transport_state) { case TRANSPORT_STOPPED: break; case TRANSPORT_PLAYING: if (output_pause()) { upnp_set_error(event, UPNP_TRANSPORT_E_NO_CONTENTS, "Player Pause failed"); rc = -1; } else { transport_state = TRANSPORT_PAUSED_PLAYBACK; transport_change_var(event, TRANSPORT_VAR_TRANSPORT_STATE, "PAUSED_PLAYBACK"); } break; case TRANSPORT_PAUSED_PLAYBACK: if (output_play()) { upnp_set_error(event, UPNP_TRANSPORT_E_NO_CONTENTS, "Player Start failed"); rc = -1; } else { transport_state = TRANSPORT_PLAYING; transport_change_var(event, TRANSPORT_VAR_TRANSPORT_STATE, "PLAYING"); } break; case TRANSPORT_TRANSITIONING: 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; } ithread_mutex_unlock(&transport_mutex); 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; }
DBG_STATIC int get_transport_info(struct action_event *event) { int rc = -1; if (upnp_obtain_instanceid(event, NULL)) { upnp_set_error(event, UPNP_TRANSPORT_E_INVALID_IID, "ID non-zero invalid"); //return -1; } 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: return rc; }
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; }
DBG_STATIC int set_avtransport_uri(struct action_event *event) { char *value; int rc = 0; if (upnp_obtain_instanceid(event, NULL)) { upnp_set_error(event, UPNP_TRANSPORT_E_INVALID_IID, "ID non-zero invalid"); return -1; } value = upnp_get_string(event, "CurrentURI"); if (value == NULL) return -1; ithread_mutex_lock(&transport_mutex); DBG_PRINT(DBG_LVL4, "%s: Set URI to '%s'\n", __FUNCTION__, value); // do the work output_set_uri(value); transport_set_var(TRANSPORT_VAR_AV_URI, value); free(value); value = upnp_get_string(event, "CurrentURIMetaData"); if (value != NULL) { DBG_PRINT(DBG_LVL4, "%s: Set URI MetaData to '%s'\n", __FUNCTION__, value); // First set new value so we may extract some information about // the stream (Ex: track_duration) transport_set_var(TRANSPORT_VAR_AV_URI_META, value); free(value); // Locate duration attribute in 'res' element under 'item' value = (char *)transport_get_attr_metadata("duration"); if (value) { transport_set_var(TRANSPORT_VAR_CUR_TRACK_DUR, value); free(value); } } else { rc = -1; } transport_state = TRANSPORT_STOPPED; transport_set_var(TRANSPORT_VAR_TRANSPORT_STATE, "STOPPED"); transport_notify_lastchange(event, transport_get_state_lastchange()); ithread_mutex_unlock(&transport_mutex); return rc; }
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; }
DBG_STATIC int xprevious(struct action_event *event) { if (upnp_obtain_instanceid(event, NULL)) { upnp_set_error(event, UPNP_TRANSPORT_E_INVALID_IID, "ID non-zero invalid"); return -1; } // Check MPD connection if (check_mpd_connection(TRUE) == STATUS_FAIL) return -1; if (output_prev()) { upnp_set_error(event, UPNP_TRANSPORT_E_TRANSITION_NA, "Player Previous failed"); return -1; } return 0; }
DBG_STATIC int get_position_info(struct action_event *event) { int rc = -1; if (upnp_obtain_instanceid(event, NULL)) { upnp_set_error(event, UPNP_TRANSPORT_E_INVALID_IID, "ID non-zero invalid"); return -1; } ithread_mutex_lock(&transport_mutex); // Calls back into transport to set vars output_update_position(); ithread_mutex_unlock(&transport_mutex); 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: return rc; }
DBG_STATIC int xseek(struct action_event *event) { char *value, *mode; int rc = 0; if (upnp_obtain_instanceid(event, NULL)) { upnp_set_error(event, UPNP_TRANSPORT_E_INVALID_IID, "ID non-zero invalid"); return -1; } mode = upnp_get_string(event, "Unit"); if (mode == NULL) return -1; value = upnp_get_string(event, "Target"); if (value == NULL) { free(mode); return -1; } // Check MPD connection if (check_mpd_connection(TRUE) == STATUS_FAIL) return -1; // Attempt to seek player (doesn't work for streams) rc = output_seekto(mode, value); free(mode); free(value); if (rc != 0) { upnp_set_error(event, UPNP_TRANSPORT_E_ILL_SEEKTARGET, "Player Seek failed"); return -1; } return rc; }
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 get_media_info(struct action_event *event) { int rc = -1; if (upnp_obtain_instanceid(event, NULL)) { upnp_set_error(event, UPNP_TRANSPORT_E_INVALID_IID, "ID non-zero invalid"); return -1; } rc = upnp_append_variable(event, TRANSPORT_VAR_NR_TRACKS, "NrTracks"); if (rc) goto out; rc = upnp_append_variable(event, TRANSPORT_VAR_CUR_MEDIA_DUR, "MediaDuration"); if (rc) goto out; rc = upnp_append_variable(event, TRANSPORT_VAR_AV_URI, "CurrentURI"); if (rc) goto out; rc = upnp_append_variable(event, TRANSPORT_VAR_AV_URI_META, "CurrentURIMetaData"); if (rc) goto out; rc = upnp_append_variable(event, TRANSPORT_VAR_NEXT_AV_URI, "NextURI"); if (rc) goto out; rc = upnp_append_variable(event, TRANSPORT_VAR_NEXT_AV_URI_META, "NextURIMetaData"); if (rc) goto out; rc = upnp_append_variable(event, TRANSPORT_VAR_REC_MEDIA, "PlayMedium"); if (rc) goto out; rc = upnp_append_variable(event, TRANSPORT_VAR_REC_MEDIUM, "RecordMedium"); if (rc) goto out; rc = upnp_append_variable(event, TRANSPORT_VAR_REC_MEDIUM_WR_STATUS, "WriteStatus"); if (rc) goto out; out: return rc; }
static int obtain_instanceid(struct action_event *event, int *instance) { char *value = upnp_get_string(event, "InstanceID"); if (value == NULL) { upnp_set_error(event, UPNP_SOAP_E_INVALID_ARGS, "Missing InstanceID"); return -1; } free(value); // TODO - parse value, and store in *instance, if instance!=NULL return 0; }
DBG_STATIC int get_device_caps(struct action_event *event) { int rc = 0; if (upnp_obtain_instanceid(event, NULL)) { upnp_set_error(event, UPNP_TRANSPORT_E_INVALID_IID, "ID non-zero invalid"); return -1; } // *** TODO: Add some information return rc; }
DBG_STATIC int xplaymode(struct action_event *event) { char *newmode; int rc = 0; if (upnp_obtain_instanceid(event, NULL)) { upnp_set_error(event, UPNP_TRANSPORT_E_INVALID_IID, "ID non-zero invalid"); return -1; } newmode = upnp_get_string(event, "NewPlayMode"); DBG_PRINT(DBG_LVL4, "Set NewPlayMode: %s\n", newmode); // Check MPD connection if (check_mpd_connection(TRUE) == STATUS_FAIL) return -1; ithread_mutex_lock(&transport_mutex); rc = output_playmode(newmode); if (rc != 0) { free(newmode); upnp_set_error(event, UPNP_TRANSPORT_E_PLAYMODE_NS, "Set playmode failed"); goto out; } transport_change_var(event, TRANSPORT_VAR_CUR_PLAY_MODE, newmode); free(newmode); out: ithread_mutex_unlock(&transport_mutex); return rc; }
DBG_STATIC int get_transport_settings(struct action_event *event) { int rc = -1; if (upnp_obtain_instanceid(event, NULL)) { upnp_set_error(event, UPNP_TRANSPORT_E_INVALID_IID, "ID non-zero invalid"); return -1; } rc = upnp_append_variable(event, TRANSPORT_VAR_CUR_PLAY_MODE, "CurrentPlayMode"); if (rc) goto out; rc = upnp_append_variable(event, TRANSPORT_VAR_CUR_REC_QUAL_MODE, "CurrentRecordQualityMode"); if (rc) goto out; out: return rc; }
int upnp_append_variable(struct action_event *event, int varnum, const char *paramname) { const char *value; struct service *service = event->service; int retval = -1; //ENTER(); assert(event != NULL); assert(paramname != NULL); if (varnum >= service->variable_count) { #ifdef HAVE_LIBUPNP upnp_set_error(event, UPNP_E_INTERNAL_ERROR, "Internal Error - illegal variable number %d", varnum); #endif goto out; } #ifdef HAVE_LIBUPNP ithread_mutex_lock(service->service_mutex); #endif #if 0 fprintf(stderr, "\tHZ: %s = '%s'\n", service->variable_names[varnum], service->variable_values[varnum]); #endif value = service->variable_values[varnum]; assert(value != NULL); retval = upnp_add_response(event, paramname, value); #ifdef HAVE_LIBUPNP ithread_mutex_unlock(service->service_mutex); #endif out: //LEAVE(); return retval; }
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 obtain_instanceid(struct action_event *event, int *instance) { char *value; int rc = 0; ENTER(); value = upnp_get_string(event, "InstanceID"); if (value == NULL) { #ifdef HAVE_LIBUPNP upnp_set_error(event, UPNP_SOAP_E_INVALID_ARGS, "Missing InstanceID"); #endif return -1; } //printf("%s: InstanceID='%s'\n", __FUNCTION__, value); free(value); // TODO - parse value, and store in *instance, if instance!=NULL LEAVE(); return rc; }