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; }