On 29/06/2021 20:21, Deborah Brouwer wrote: > Check that the recording device ignores a Standby message while it is > recording. When the recording is finished, check that the recording device > enters standby unless the recording device is the active source. > > Signed-off-by: Deborah Brouwer <deborahbrouwer3563@xxxxxxxxx> > --- > utils/cec-compliance/cec-test-power.cpp | 62 +++++++++++++++++++++++++ > utils/cec-follower/cec-follower.cpp | 1 + > utils/cec-follower/cec-follower.h | 2 + > utils/cec-follower/cec-processing.cpp | 14 +++++- > utils/cec-follower/cec-tuner.cpp | 9 ++++ > 5 files changed, 87 insertions(+), 1 deletion(-) > > diff --git a/utils/cec-compliance/cec-test-power.cpp b/utils/cec-compliance/cec-test-power.cpp > index b675bfc4..f23d0414 100644 > --- a/utils/cec-compliance/cec-test-power.cpp > +++ b/utils/cec-compliance/cec-test-power.cpp > @@ -677,6 +677,66 @@ static int standby_resume_wakeup_deck_play(struct node *node, unsigned me, unsig > return standby_resume_wakeup_deck(node, me, la, interactive, CEC_OP_PLAY_MODE_PLAY_FWD); > } > > +static int standby_record(struct node *node, unsigned me, unsigned la, bool interactive, bool active_source) > +{ > + struct cec_msg msg; > + __u8 rec_status; > + unsigned unresponsive_time = 0; > + > + cec_msg_init(&msg, me, la); > + cec_msg_record_on_own(&msg); > + msg.reply = CEC_MSG_RECORD_STATUS; > + fail_on_test(!transmit_timeout(node, &msg, 10000)); > + if (timed_out_or_abort(&msg)) > + return OK_NOT_SUPPORTED; > + cec_ops_record_status(&msg, &rec_status); > + fail_on_test(rec_status != CEC_OP_RECORD_STATUS_CUR_SRC && > + rec_status != CEC_OP_RECORD_STATUS_ALREADY_RECORDING); > + > + cec_msg_init(&msg, me, la); > + if (active_source) > + cec_msg_active_source(&msg, node->remote[la].phys_addr); > + else > + cec_msg_active_source(&msg, me); > + fail_on_test(!transmit_timeout(node, &msg)); > + > + cec_msg_init(&msg, me, la); > + cec_msg_standby(&msg); > + fail_on_test(!transmit_timeout(node, &msg)); > + /* Standby should not interrupt the recording. */ > + fail_on_test(!poll_stable_power_status(node, me, la, CEC_OP_POWER_STATUS_ON, unresponsive_time)); > + > + cec_msg_init(&msg, me, la); > + cec_msg_record_off(&msg, false); > + fail_on_test(!transmit_timeout(node, &msg)); > + > + /* When the recording stops, recorder should standby unless it is the active source. */ > + if (active_source) { > + fail_on_test(!poll_stable_power_status(node, me, la, CEC_OP_POWER_STATUS_ON, unresponsive_time)); > + } else { > + fail_on_test(!poll_stable_power_status(node, me, la, CEC_OP_POWER_STATUS_STANDBY, unresponsive_time)); > + fail_on_test(interactive && !question("Is the device in standby?")); > + node->remote[la].in_standby = true; > + > + int ret = standby_resume_wakeup(node, me, la, interactive); > + if (ret) > + return ret; > + node->remote[la].in_standby = false; > + } > + > + return OK; > +} > + > +static int standby_record_active_source(struct node *node, unsigned me, unsigned la, bool interactive) > +{ > + return standby_record(node, me, la, interactive, true); > +} > + > +static int standby_record_inactive_source(struct node *node, unsigned me, unsigned la, bool interactive) > +{ > + return standby_record(node, me, la, interactive, false); > +} > + > const vec_remote_subtests standby_resume_subtests{ > { "Standby", CEC_LOG_ADDR_MASK_ALL, standby_resume_standby }, > { "Repeated Standby message does not wake up", CEC_LOG_ADDR_MASK_ALL, standby_resume_standby_toggle }, > @@ -697,4 +757,6 @@ const vec_remote_subtests standby_resume_subtests{ > { "Power State Transitions", CEC_LOG_ADDR_MASK_TV, power_state_transitions, false, true }, > { "Deck Eject Standby Resume", CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD, standby_resume_wakeup_deck_eject }, > { "Deck Play Standby Resume", CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD, standby_resume_wakeup_deck_play }, > + { "Record Standby Active Source", CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP, standby_record_active_source }, > + { "Record Standby Inactive Source", CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP, standby_record_inactive_source }, > }; > diff --git a/utils/cec-follower/cec-follower.cpp b/utils/cec-follower/cec-follower.cpp > index 482192e7..2816fb85 100644 > --- a/utils/cec-follower/cec-follower.cpp > +++ b/utils/cec-follower/cec-follower.cpp > @@ -318,6 +318,7 @@ void state_init(struct node &node) > node.state.deck_state = CEC_OP_DECK_INFO_STOP; > node.state.deck_skip_start = 0; > node.state.one_touch_record_on = false; > + node.state.record_received_standby = false; > tuner_dev_info_init(&node.state); > node.state.last_aud_rate_rx_ts = 0; > } > diff --git a/utils/cec-follower/cec-follower.h b/utils/cec-follower/cec-follower.h > index 8dfbd39f..833dec5e 100644 > --- a/utils/cec-follower/cec-follower.h > +++ b/utils/cec-follower/cec-follower.h > @@ -54,6 +54,7 @@ struct state { > __u8 deck_state; > __u64 deck_skip_start; > bool one_touch_record_on; > + bool record_received_standby; > time_t toggle_power_status; > __u64 last_aud_rate_rx_ts; > }; > @@ -230,5 +231,6 @@ void process_tuner_record_timer_msgs(struct node *node, struct cec_msg &msg, uns > void reply_feature_abort(struct node *node, struct cec_msg *msg, > __u8 reason = CEC_OP_ABORT_UNRECOGNIZED_OP); > void testProcessing(struct node *node, bool wallclock); > +bool enter_standby(struct node *node); > > #endif > diff --git a/utils/cec-follower/cec-processing.cpp b/utils/cec-follower/cec-processing.cpp > index e1a71d6c..32375966 100644 > --- a/utils/cec-follower/cec-processing.cpp > +++ b/utils/cec-follower/cec-processing.cpp > @@ -146,6 +146,9 @@ void reply_feature_abort(struct node *node, struct cec_msg *msg, __u8 reason) > > static bool exit_standby(struct node *node) > { > + /* Cancel any standby request that was pending. */ > + node->state.record_received_standby = false; > + > if (node->state.power_status == CEC_OP_POWER_STATUS_STANDBY || > node->state.power_status == CEC_OP_POWER_STATUS_TO_STANDBY) { > node->state.old_power_status = node->state.power_status; > @@ -157,14 +160,23 @@ static bool exit_standby(struct node *node) > return false; > } > > -static bool enter_standby(struct node *node) > +bool enter_standby(struct node *node) > { > if (node->state.power_status == CEC_OP_POWER_STATUS_ON || > node->state.power_status == CEC_OP_POWER_STATUS_TO_ON) { > + /* > + * Standby should not interrupt a recording in progress, but > + * remember to go to standby once the recording is finished. > + */ > + if (node->state.one_touch_record_on) { > + node->state.record_received_standby = true; > + return false; > + } > node->state.old_power_status = node->state.power_status; > node->state.power_status = CEC_OP_POWER_STATUS_STANDBY; > node->state.power_status_changed_time = time(nullptr); > node->state.deck_skip_start = 0; > + node->state.record_received_standby = false; > dev_info("Changing state to standby\n"); > return true; > } > diff --git a/utils/cec-follower/cec-tuner.cpp b/utils/cec-follower/cec-tuner.cpp > index 13cf6d20..e1d8b8fc 100644 > --- a/utils/cec-follower/cec-tuner.cpp > +++ b/utils/cec-follower/cec-tuner.cpp > @@ -724,6 +724,15 @@ void process_tuner_record_timer_msgs(struct node *node, struct cec_msg &msg, uns > cec_msg_record_status(&msg, CEC_OP_RECORD_STATUS_TERMINATED_OK); > transmit(node, &msg); > node->state.one_touch_record_on = false; > + /* > + * If standby was received during recording, enter standby when the > + * recording is finished unless recording device is the active source. > + */ > + if (node->state.record_received_standby) { > + if (node->phys_addr != node->state.active_source_pa) > + enter_standby(node); > + node->state.record_received_standby = false; > + } > return; > case CEC_MSG_RECORD_STATUS: > return; > Looks good! I'll wait for v7 before merging as I expect that to be the final version. Regards, Hans