audio: Make StreamDescriptor::Command a union
Previously StreamDescriptor::Command used to be a parcelable
holding a command code (enum) + a command argument which was
used for one command only. This got replaced with an equivalent
union, where each command w/o arguments is represented by a
'Void' variant, and the command with an argument with a variant
of a corresponding type.
This has the following benefits:
- the union guarantees that the argument is only set for
commands that actually use it, thus all related comments
and validations can be removed;
- the command dispatch can be turned into an exhaustive
switch.
To be able to use an exhaustive switch, the 'exit' command
has been exposed at the interface, but marked as 'hal_reserved'.
Bug: 205884982
Test: atest VtsHalAudioCoreTargetTest
Change-Id: I3f2c27a48e4d0b7cfce1171244b2eddc1637005f
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
index da24a10..3a77ad1 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
@@ -55,19 +55,15 @@
DRAIN_PAUSED = 6,
ERROR = 100,
}
- @Backing(type="int") @VintfStability
- enum CommandCode {
- START = 1,
- BURST = 2,
- DRAIN = 3,
- STANDBY = 4,
- PAUSE = 5,
- FLUSH = 6,
- }
@FixedSize @VintfStability
- parcelable Command {
- android.hardware.audio.core.StreamDescriptor.CommandCode code = android.hardware.audio.core.StreamDescriptor.CommandCode.START;
- int fmqByteCount;
+ union Command {
+ int hal_reserved_exit;
+ android.media.audio.common.Void start;
+ int burst;
+ android.media.audio.common.Void drain;
+ android.media.audio.common.Void standby;
+ android.media.audio.common.Void pause;
+ android.media.audio.common.Void flush;
}
@FixedSize @VintfStability
parcelable Reply {
diff --git a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
index e5e56fc..2b1fc99 100644
--- a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
+++ b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
@@ -19,6 +19,7 @@
import android.hardware.audio.core.MmapBufferDescriptor;
import android.hardware.common.fmq.MQDescriptor;
import android.hardware.common.fmq.SynchronizedReadWrite;
+import android.media.audio.common.Void;
/**
* Stream descriptor contains fast message queues and buffers used for sending
@@ -177,76 +178,41 @@
ERROR = 100,
}
- @VintfStability
- @Backing(type="int")
- enum CommandCode {
- /**
- * See the state machines on the applicability of this command to
- * different states. The 'fmqByteCount' field must always be set to 0.
- */
- START = 1,
- /**
- * The BURST command used for audio I/O, see 'AudioBuffer'. Differences
- * for the MMap No IRQ mode:
- *
- * - this command only provides updated positions and latency because
- * actual audio I/O is done via the 'AudioBuffer.mmap' shared buffer.
- * The client does not synchronize reads and writes into the buffer
- * with sending of this command.
- *
- * - the 'fmqByteCount' must always be set to 0.
- */
- BURST = 2,
- /**
- * See the state machines on the applicability of this command to
- * different states. The 'fmqByteCount' field must always be set to 0.
- */
- DRAIN = 3,
- /**
- * See the state machines on the applicability of this command to
- * different states. The 'fmqByteCount' field must always be set to 0.
- *
- * Note that it's left on the discretion of the HAL implementation to
- * assess all the necessary conditions that could prevent hardware from
- * being suspended. Even if it can not be suspended, the state machine
- * must still enter the 'STANDBY' state for consistency. Since the
- * buffer must remain empty in this state, even if capturing hardware is
- * still active, captured data must be discarded.
- */
- STANDBY = 4,
- /**
- * See the state machines on the applicability of this command to
- * different states. The 'fmqByteCount' field must always be set to 0.
- */
- PAUSE = 5,
- /**
- * See the state machines on the applicability of this command to
- * different states. The 'fmqByteCount' field must always be set to 0.
- */
- FLUSH = 6,
- }
-
/**
* Used for sending commands to the HAL module. The client writes into
* the queue, the HAL module reads. The queue can only contain a single
* command.
+ *
+ * Variants of type 'Void' correspond to commands without
+ * arguments. Variants of other types correspond to commands with an
+ * argument. Would in future a need for a command with multiple argument
+ * arise, a Parcelable type should be used for the corresponding variant.
*/
@VintfStability
@FixedSize
- parcelable Command {
+ union Command {
/**
- * The code of the command.
+ * Reserved for the HAL implementation to allow unblocking the wait on a
+ * command and exiting the I/O thread. A command of this variant must
+ * never be sent from the client side. To prevent that, the
+ * implementation must pass a random cookie as the command argument,
+ * which is only known to the implementation.
*/
- CommandCode code = CommandCode.START;
+ int hal_reserved_exit;
/**
- * This field is only used for the BURST command. For all other commands
- * it must be set to 0. The following description applies to the use
- * of this field for the BURST command.
+ * See the state machines on the applicability of this command to
+ * different states.
+ */
+ Void start;
+ /**
+ * The 'burst' command used for audio I/O, see 'AudioBuffer'. The value
+ * specifies:
*
- * For output streams: the amount of bytes that the client requests the
- * HAL module to use out of the data contained in the 'audio.fmq' queue.
- * For input streams: the amount of bytes requested by the client to
- * read from the hardware into the 'audio.fmq' queue.
+ * - for output streams: the amount of bytes that the client requests the
+ * HAL module to use out of the data contained in the 'audio.fmq' queue.
+ *
+ * - for input streams: the amount of bytes requested by the client to
+ * read from the hardware into the 'audio.fmq' queue.
*
* In both cases it is allowed for this field to contain any
* non-negative number. The value 0 can be used if the client only needs
@@ -258,8 +224,44 @@
* return the amount of actually read or written data via the
* 'Reply.fmqByteCount' field. Thus, only attempts to pass a negative
* number must be constituted as a client's error.
+ *
+ * Differences for the MMap No IRQ mode:
+ *
+ * - this command only provides updated positions and latency because
+ * actual audio I/O is done via the 'AudioBuffer.mmap' shared buffer.
+ * The client does not synchronize reads and writes into the buffer
+ * with sending of this command.
+ *
+ * - the value must always be set to 0.
*/
- int fmqByteCount;
+ int burst;
+ /**
+ * See the state machines on the applicability of this command to
+ * different states.
+ */
+ Void drain;
+ /**
+ * See the state machines on the applicability of this command to
+ * different states.
+ *
+ * Note that it's left on the discretion of the HAL implementation to
+ * assess all the necessary conditions that could prevent hardware from
+ * being suspended. Even if it can not be suspended, the state machine
+ * must still enter the 'STANDBY' state for consistency. Since the
+ * buffer must remain empty in this state, even if capturing hardware is
+ * still active, captured data must be discarded.
+ */
+ Void standby;
+ /**
+ * See the state machines on the applicability of this command to
+ * different states.
+ */
+ Void pause;
+ /**
+ * See the state machines on the applicability of this command to
+ * different states.
+ */
+ Void flush;
}
MQDescriptor<Command, SynchronizedReadWrite> command;
@@ -293,15 +295,15 @@
*/
int status;
/**
- * Used with the BURST command only.
+ * Used with the 'burst' command only.
*
* For output streams: the amount of bytes of data actually consumed
* by the HAL module.
* For input streams: the amount of bytes actually provided by the HAL
* in the 'audio.fmq' queue.
*
- * The returned value must not exceed the value passed in the
- * 'fmqByteCount' field of the corresponding command or be negative.
+ * The returned value must not exceed the value passed as the
+ * argument of the corresponding command, or be negative.
*/
int fmqByteCount;
/**
diff --git a/audio/aidl/android/hardware/audio/core/stream-in-sm.gv b/audio/aidl/android/hardware/audio/core/stream-in-sm.gv
index 889a14b..805dc32 100644
--- a/audio/aidl/android/hardware/audio/core/stream-in-sm.gv
+++ b/audio/aidl/android/hardware/audio/core/stream-in-sm.gv
@@ -23,16 +23,16 @@
node [style=dashed] ANY_STATE;
node [fillcolor=lightblue style=filled];
I -> STANDBY;
- STANDBY -> IDLE [label="START"]; // producer -> active
- IDLE -> STANDBY [label="STANDBY"]; // producer -> passive, buffer is cleared
- IDLE -> ACTIVE [label="BURST"]; // consumer -> active
- ACTIVE -> ACTIVE [label="BURST"];
- ACTIVE -> PAUSED [label="PAUSE"]; // consumer -> passive
- ACTIVE -> DRAINING [label="DRAIN"]; // producer -> passive
- PAUSED -> ACTIVE [label="BURST"]; // consumer -> active
- PAUSED -> STANDBY [label="FLUSH"]; // producer -> passive, buffer is cleared
- DRAINING -> DRAINING [label="BURST"];
- DRAINING -> ACTIVE [label="START"]; // producer -> active
+ STANDBY -> IDLE [label="start"]; // producer -> active
+ IDLE -> STANDBY [label="standby"]; // producer -> passive, buffer is cleared
+ IDLE -> ACTIVE [label="burst"]; // consumer -> active
+ ACTIVE -> ACTIVE [label="burst"];
+ ACTIVE -> PAUSED [label="pause"]; // consumer -> passive
+ ACTIVE -> DRAINING [label="drain"]; // producer -> passive
+ PAUSED -> ACTIVE [label="burst"]; // consumer -> active
+ PAUSED -> STANDBY [label="flush"]; // producer -> passive, buffer is cleared
+ DRAINING -> DRAINING [label="burst"];
+ DRAINING -> ACTIVE [label="start"]; // producer -> active
DRAINING -> STANDBY [label="<empty buffer>"]; // consumer deactivates
IDLE -> ERROR [label="<hardware failure>"];
ACTIVE -> ERROR [label="<hardware failure>"];
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
index 56dd5290..6aa5c61 100644
--- a/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
+++ b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
@@ -24,22 +24,22 @@
node [style=dashed] ANY_STATE;
node [fillcolor=lightblue style=filled];
I -> STANDBY;
- STANDBY -> IDLE [label="START"]; // consumer -> active
- STANDBY -> PAUSED [label="BURST"]; // producer -> active
- IDLE -> STANDBY [label="STANDBY"]; // consumer -> passive
- IDLE -> ACTIVE [label="BURST"]; // producer -> active
- ACTIVE -> ACTIVE [label="BURST"];
- ACTIVE -> PAUSED [label="PAUSE"]; // consumer -> passive (not consuming)
- ACTIVE -> DRAINING [label="DRAIN"]; // producer -> passive
- PAUSED -> PAUSED [label="BURST"];
- PAUSED -> ACTIVE [label="START"]; // consumer -> active
- PAUSED -> IDLE [label="FLUSH"]; // producer -> passive, buffer is cleared
+ STANDBY -> IDLE [label="start"]; // consumer -> active
+ STANDBY -> PAUSED [label="burst"]; // producer -> active
+ IDLE -> STANDBY [label="standby"]; // consumer -> passive
+ IDLE -> ACTIVE [label="burst"]; // producer -> active
+ ACTIVE -> ACTIVE [label="burst"];
+ ACTIVE -> PAUSED [label="pause"]; // consumer -> passive (not consuming)
+ ACTIVE -> DRAINING [label="drain"]; // producer -> passive
+ PAUSED -> PAUSED [label="burst"];
+ PAUSED -> ACTIVE [label="start"]; // consumer -> active
+ PAUSED -> IDLE [label="flush"]; // producer -> passive, buffer is cleared
DRAINING -> IDLE [label="<empty buffer>"];
- DRAINING -> ACTIVE [label="BURST"]; // producer -> active
- DRAINING -> DRAIN_PAUSED [label="PAUSE"]; // consumer -> passive (not consuming)
- DRAIN_PAUSED -> DRAINING [label="START"]; // consumer -> active
- DRAIN_PAUSED -> PAUSED [label="BURST"]; // producer -> active
- DRAIN_PAUSED -> IDLE [label="FLUSH"]; // buffer is cleared
+ DRAINING -> ACTIVE [label="burst"]; // producer -> active
+ DRAINING -> DRAIN_PAUSED [label="pause"]; // consumer -> passive (not consuming)
+ DRAIN_PAUSED -> DRAINING [label="start"]; // consumer -> active
+ DRAIN_PAUSED -> PAUSED [label="burst"]; // producer -> active
+ DRAIN_PAUSED -> IDLE [label="flush"]; // buffer is cleared
IDLE -> ERROR [label="<hardware failure>"];
ACTIVE -> ERROR [label="<hardware failure>"];
DRAINING -> ERROR [label="<hardware failure>"];
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index 7b544a1..21dc4b6 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -106,101 +106,116 @@
return Status::ABORT;
}
StreamDescriptor::Reply reply{};
- if (static_cast<int32_t>(command.code) == StreamContext::COMMAND_EXIT &&
- command.fmqByteCount == mInternalCommandCookie) {
- LOG(DEBUG) << __func__ << ": received EXIT command";
- setClosed();
- // This is an internal command, no need to reply.
- return Status::EXIT;
- } else if (command.code == StreamDescriptor::CommandCode::START && command.fmqByteCount >= 0) {
- LOG(DEBUG) << __func__ << ": received START read command";
- if (mState == StreamDescriptor::State::STANDBY ||
- mState == StreamDescriptor::State::DRAINING) {
- populateReply(&reply, mIsConnected);
- mState = mState == StreamDescriptor::State::STANDBY ? StreamDescriptor::State::IDLE
- : StreamDescriptor::State::ACTIVE;
- } else {
- LOG(WARNING) << __func__ << ": START command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
- }
- } else if (command.code == StreamDescriptor::CommandCode::BURST && command.fmqByteCount >= 0) {
- LOG(DEBUG) << __func__ << ": received BURST read command for " << command.fmqByteCount
- << " bytes";
- if (mState == StreamDescriptor::State::IDLE || mState == StreamDescriptor::State::ACTIVE ||
- mState == StreamDescriptor::State::PAUSED ||
- mState == StreamDescriptor::State::DRAINING) {
- if (!read(command.fmqByteCount, &reply)) {
- mState = StreamDescriptor::State::ERROR;
+ reply.status = STATUS_BAD_VALUE;
+ using Tag = StreamDescriptor::Command::Tag;
+ switch (command.getTag()) {
+ case Tag::hal_reserved_exit:
+ if (const int32_t cookie = command.get<Tag::hal_reserved_exit>();
+ cookie == mInternalCommandCookie) {
+ LOG(DEBUG) << __func__ << ": received EXIT command";
+ setClosed();
+ // This is an internal command, no need to reply.
+ return Status::EXIT;
+ } else {
+ LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
}
- if (mState == StreamDescriptor::State::IDLE ||
- mState == StreamDescriptor::State::PAUSED) {
- mState = StreamDescriptor::State::ACTIVE;
- } else if (mState == StreamDescriptor::State::DRAINING) {
- // To simplify the reference code, we assume that the read operation
- // has consumed all the data remaining in the hardware buffer.
- // TODO: Provide parametrization on the duration of draining to test
- // handling of commands during the 'DRAINING' state.
+ break;
+ case Tag::start:
+ LOG(DEBUG) << __func__ << ": received START read command";
+ if (mState == StreamDescriptor::State::STANDBY ||
+ mState == StreamDescriptor::State::DRAINING) {
+ populateReply(&reply, mIsConnected);
+ mState = mState == StreamDescriptor::State::STANDBY
+ ? StreamDescriptor::State::IDLE
+ : StreamDescriptor::State::ACTIVE;
+ } else {
+ LOG(WARNING) << __func__ << ": START command can not be handled in the state "
+ << toString(mState);
+ reply.status = STATUS_INVALID_OPERATION;
+ }
+ break;
+ case Tag::burst:
+ if (const int32_t fmqByteCount = command.get<Tag::burst>(); fmqByteCount >= 0) {
+ LOG(DEBUG) << __func__ << ": received BURST read command for " << fmqByteCount
+ << " bytes";
+ if (mState == StreamDescriptor::State::IDLE ||
+ mState == StreamDescriptor::State::ACTIVE ||
+ mState == StreamDescriptor::State::PAUSED ||
+ mState == StreamDescriptor::State::DRAINING) {
+ if (!read(fmqByteCount, &reply)) {
+ mState = StreamDescriptor::State::ERROR;
+ }
+ if (mState == StreamDescriptor::State::IDLE ||
+ mState == StreamDescriptor::State::PAUSED) {
+ mState = StreamDescriptor::State::ACTIVE;
+ } else if (mState == StreamDescriptor::State::DRAINING) {
+ // To simplify the reference code, we assume that the read operation
+ // has consumed all the data remaining in the hardware buffer.
+ // TODO: Provide parametrization on the duration of draining to test
+ // handling of commands during the 'DRAINING' state.
+ mState = StreamDescriptor::State::STANDBY;
+ }
+ } else {
+ LOG(WARNING) << __func__ << ": BURST command can not be handled in the state "
+ << toString(mState);
+ reply.status = STATUS_INVALID_OPERATION;
+ }
+ } else {
+ LOG(WARNING) << __func__ << ": invalid burst byte count: " << fmqByteCount;
+ }
+ break;
+ case Tag::drain:
+ LOG(DEBUG) << __func__ << ": received DRAIN read command";
+ if (mState == StreamDescriptor::State::ACTIVE) {
+ usleep(1000); // Simulate a blocking call into the driver.
+ populateReply(&reply, mIsConnected);
+ // Can switch the state to ERROR if a driver error occurs.
+ mState = StreamDescriptor::State::DRAINING;
+ } else {
+ LOG(WARNING) << __func__ << ": DRAIN command can not be handled in the state "
+ << toString(mState);
+ reply.status = STATUS_INVALID_OPERATION;
+ }
+ break;
+ case Tag::standby:
+ LOG(DEBUG) << __func__ << ": received STANDBY read command";
+ if (mState == StreamDescriptor::State::IDLE) {
+ usleep(1000); // Simulate a blocking call into the driver.
+ populateReply(&reply, mIsConnected);
+ // Can switch the state to ERROR if a driver error occurs.
mState = StreamDescriptor::State::STANDBY;
+ } else {
+ LOG(WARNING) << __func__ << ": FLUSH command can not be handled in the state "
+ << toString(mState);
+ reply.status = STATUS_INVALID_OPERATION;
}
- } else {
- LOG(WARNING) << __func__ << ": BURST command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
- }
- } else if (command.code == StreamDescriptor::CommandCode::DRAIN && command.fmqByteCount == 0) {
- LOG(DEBUG) << __func__ << ": received DRAIN read command";
- if (mState == StreamDescriptor::State::ACTIVE) {
- usleep(1000); // Simulate a blocking call into the driver.
- populateReply(&reply, mIsConnected);
- // Can switch the state to ERROR if a driver error occurs.
- mState = StreamDescriptor::State::DRAINING;
- } else {
- LOG(WARNING) << __func__ << ": DRAIN command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
- }
- } else if (command.code == StreamDescriptor::CommandCode::PAUSE && command.fmqByteCount == 0) {
- LOG(DEBUG) << __func__ << ": received PAUSE read command";
- if (mState == StreamDescriptor::State::ACTIVE) {
- usleep(1000); // Simulate a blocking call into the driver.
- populateReply(&reply, mIsConnected);
- // Can switch the state to ERROR if a driver error occurs.
- mState = StreamDescriptor::State::PAUSED;
- } else {
- LOG(WARNING) << __func__ << ": PAUSE command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
- }
- } else if (command.code == StreamDescriptor::CommandCode::FLUSH && command.fmqByteCount == 0) {
- LOG(DEBUG) << __func__ << ": received FLUSH read command";
- if (mState == StreamDescriptor::State::PAUSED) {
- usleep(1000); // Simulate a blocking call into the driver.
- populateReply(&reply, mIsConnected);
- // Can switch the state to ERROR if a driver error occurs.
- mState = StreamDescriptor::State::STANDBY;
- } else {
- LOG(WARNING) << __func__ << ": FLUSH command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
- }
- } else if (command.code == StreamDescriptor::CommandCode::STANDBY &&
- command.fmqByteCount == 0) {
- LOG(DEBUG) << __func__ << ": received STANDBY read command";
- if (mState == StreamDescriptor::State::IDLE) {
- usleep(1000); // Simulate a blocking call into the driver.
- populateReply(&reply, mIsConnected);
- // Can switch the state to ERROR if a driver error occurs.
- mState = StreamDescriptor::State::STANDBY;
- } else {
- LOG(WARNING) << __func__ << ": FLUSH command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
- }
- } else {
- LOG(WARNING) << __func__ << ": invalid command (" << command.toString()
- << ") or count: " << command.fmqByteCount;
- reply.status = STATUS_BAD_VALUE;
+ break;
+ case Tag::pause:
+ LOG(DEBUG) << __func__ << ": received PAUSE read command";
+ if (mState == StreamDescriptor::State::ACTIVE) {
+ usleep(1000); // Simulate a blocking call into the driver.
+ populateReply(&reply, mIsConnected);
+ // Can switch the state to ERROR if a driver error occurs.
+ mState = StreamDescriptor::State::PAUSED;
+ } else {
+ LOG(WARNING) << __func__ << ": PAUSE command can not be handled in the state "
+ << toString(mState);
+ reply.status = STATUS_INVALID_OPERATION;
+ }
+ break;
+ case Tag::flush:
+ LOG(DEBUG) << __func__ << ": received FLUSH read command";
+ if (mState == StreamDescriptor::State::PAUSED) {
+ usleep(1000); // Simulate a blocking call into the driver.
+ populateReply(&reply, mIsConnected);
+ // Can switch the state to ERROR if a driver error occurs.
+ mState = StreamDescriptor::State::STANDBY;
+ } else {
+ LOG(WARNING) << __func__ << ": FLUSH command can not be handled in the state "
+ << toString(mState);
+ reply.status = STATUS_INVALID_OPERATION;
+ }
+ break;
}
reply.state = mState;
LOG(DEBUG) << __func__ << ": writing reply " << reply.toString();
@@ -253,109 +268,123 @@
return Status::ABORT;
}
StreamDescriptor::Reply reply{};
- if (static_cast<int32_t>(command.code) == StreamContext::COMMAND_EXIT &&
- command.fmqByteCount == mInternalCommandCookie) {
- LOG(DEBUG) << __func__ << ": received EXIT command";
- setClosed();
- // This is an internal command, no need to reply.
- return Status::EXIT;
- } else if (command.code == StreamDescriptor::CommandCode::START && command.fmqByteCount >= 0) {
- LOG(DEBUG) << __func__ << ": received START read command";
- switch (mState) {
- case StreamDescriptor::State::STANDBY:
+ reply.status = STATUS_BAD_VALUE;
+ using Tag = StreamDescriptor::Command::Tag;
+ switch (command.getTag()) {
+ case Tag::hal_reserved_exit:
+ if (const int32_t cookie = command.get<Tag::hal_reserved_exit>();
+ cookie == mInternalCommandCookie) {
+ LOG(DEBUG) << __func__ << ": received EXIT command";
+ setClosed();
+ // This is an internal command, no need to reply.
+ return Status::EXIT;
+ } else {
+ LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
+ }
+ break;
+ case Tag::start:
+ LOG(DEBUG) << __func__ << ": received START write command";
+ switch (mState) {
+ case StreamDescriptor::State::STANDBY:
+ mState = StreamDescriptor::State::IDLE;
+ break;
+ case StreamDescriptor::State::PAUSED:
+ mState = StreamDescriptor::State::ACTIVE;
+ break;
+ case StreamDescriptor::State::DRAIN_PAUSED:
+ mState = StreamDescriptor::State::PAUSED;
+ break;
+ default:
+ LOG(WARNING) << __func__ << ": START command can not be handled in the state "
+ << toString(mState);
+ reply.status = STATUS_INVALID_OPERATION;
+ }
+ if (reply.status != STATUS_INVALID_OPERATION) {
+ populateReply(&reply, mIsConnected);
+ }
+ break;
+ case Tag::burst:
+ if (const int32_t fmqByteCount = command.get<Tag::burst>(); fmqByteCount >= 0) {
+ LOG(DEBUG) << __func__ << ": received BURST write command for " << fmqByteCount
+ << " bytes";
+ if (mState !=
+ StreamDescriptor::State::ERROR) { // BURST can be handled in all valid states
+ if (!write(fmqByteCount, &reply)) {
+ mState = StreamDescriptor::State::ERROR;
+ }
+ if (mState == StreamDescriptor::State::STANDBY ||
+ mState == StreamDescriptor::State::DRAIN_PAUSED) {
+ mState = StreamDescriptor::State::PAUSED;
+ } else if (mState == StreamDescriptor::State::IDLE ||
+ mState == StreamDescriptor::State::DRAINING) {
+ mState = StreamDescriptor::State::ACTIVE;
+ } // When in 'ACTIVE' and 'PAUSED' do not need to change the state.
+ } else {
+ LOG(WARNING) << __func__ << ": BURST command can not be handled in the state "
+ << toString(mState);
+ reply.status = STATUS_INVALID_OPERATION;
+ }
+ } else {
+ LOG(WARNING) << __func__ << ": invalid burst byte count: " << fmqByteCount;
+ }
+ break;
+ case Tag::drain:
+ LOG(DEBUG) << __func__ << ": received DRAIN write command";
+ if (mState == StreamDescriptor::State::ACTIVE) {
+ usleep(1000); // Simulate a blocking call into the driver.
+ populateReply(&reply, mIsConnected);
+ // Can switch the state to ERROR if a driver error occurs.
mState = StreamDescriptor::State::IDLE;
- break;
- case StreamDescriptor::State::PAUSED:
- mState = StreamDescriptor::State::ACTIVE;
- break;
- case StreamDescriptor::State::DRAIN_PAUSED:
- mState = StreamDescriptor::State::PAUSED;
- break;
- default:
- LOG(WARNING) << __func__ << ": START command can not be handled in the state "
+ // Since there is no actual hardware that would be draining the buffer,
+ // in order to simplify the reference code, we assume that draining
+ // happens instantly, thus skipping the 'DRAINING' state.
+ // TODO: Provide parametrization on the duration of draining to test
+ // handling of commands during the 'DRAINING' state.
+ } else {
+ LOG(WARNING) << __func__ << ": DRAIN command can not be handled in the state "
<< toString(mState);
reply.status = STATUS_INVALID_OPERATION;
- }
- if (reply.status != STATUS_INVALID_OPERATION) {
- populateReply(&reply, mIsConnected);
- }
- } else if (command.code == StreamDescriptor::CommandCode::BURST && command.fmqByteCount >= 0) {
- LOG(DEBUG) << __func__ << ": received BURST write command for " << command.fmqByteCount
- << " bytes";
- if (mState != StreamDescriptor::State::ERROR) { // BURST can be handled in all valid states
- if (!write(command.fmqByteCount, &reply)) {
- mState = StreamDescriptor::State::ERROR;
}
- if (mState == StreamDescriptor::State::STANDBY ||
+ break;
+ case Tag::standby:
+ LOG(DEBUG) << __func__ << ": received STANDBY write command";
+ if (mState == StreamDescriptor::State::IDLE) {
+ usleep(1000); // Simulate a blocking call into the driver.
+ populateReply(&reply, mIsConnected);
+ // Can switch the state to ERROR if a driver error occurs.
+ mState = StreamDescriptor::State::STANDBY;
+ } else {
+ LOG(WARNING) << __func__ << ": STANDBY command can not be handled in the state "
+ << toString(mState);
+ reply.status = STATUS_INVALID_OPERATION;
+ }
+ break;
+ case Tag::pause:
+ LOG(DEBUG) << __func__ << ": received PAUSE write command";
+ if (mState == StreamDescriptor::State::ACTIVE ||
+ mState == StreamDescriptor::State::DRAINING) {
+ populateReply(&reply, mIsConnected);
+ mState = mState == StreamDescriptor::State::ACTIVE
+ ? StreamDescriptor::State::PAUSED
+ : StreamDescriptor::State::DRAIN_PAUSED;
+ } else {
+ LOG(WARNING) << __func__ << ": PAUSE command can not be handled in the state "
+ << toString(mState);
+ reply.status = STATUS_INVALID_OPERATION;
+ }
+ break;
+ case Tag::flush:
+ LOG(DEBUG) << __func__ << ": received FLUSH write command";
+ if (mState == StreamDescriptor::State::PAUSED ||
mState == StreamDescriptor::State::DRAIN_PAUSED) {
- mState = StreamDescriptor::State::PAUSED;
- } else if (mState == StreamDescriptor::State::IDLE ||
- mState == StreamDescriptor::State::DRAINING) {
- mState = StreamDescriptor::State::ACTIVE;
- } // When in 'ACTIVE' and 'PAUSED' do not need to change the state.
- } else {
- LOG(WARNING) << __func__ << ": BURST command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
- }
- } else if (command.code == StreamDescriptor::CommandCode::DRAIN && command.fmqByteCount == 0) {
- LOG(DEBUG) << __func__ << ": received DRAIN write command";
- if (mState == StreamDescriptor::State::ACTIVE) {
- usleep(1000); // Simulate a blocking call into the driver.
- populateReply(&reply, mIsConnected);
- // Can switch the state to ERROR if a driver error occurs.
- mState = StreamDescriptor::State::IDLE;
- // Since there is no actual hardware that would be draining the buffer,
- // in order to simplify the reference code, we assume that draining
- // happens instantly, thus skipping the 'DRAINING' state.
- // TODO: Provide parametrization on the duration of draining to test
- // handling of commands during the 'DRAINING' state.
- } else {
- LOG(WARNING) << __func__ << ": DRAIN command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
- }
- } else if (command.code == StreamDescriptor::CommandCode::STANDBY &&
- command.fmqByteCount == 0) {
- LOG(DEBUG) << __func__ << ": received STANDBY write command";
- if (mState == StreamDescriptor::State::IDLE) {
- usleep(1000); // Simulate a blocking call into the driver.
- populateReply(&reply, mIsConnected);
- // Can switch the state to ERROR if a driver error occurs.
- mState = StreamDescriptor::State::STANDBY;
- } else {
- LOG(WARNING) << __func__ << ": STANDBY command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
- }
- } else if (command.code == StreamDescriptor::CommandCode::PAUSE && command.fmqByteCount == 0) {
- LOG(DEBUG) << __func__ << ": received PAUSE write command";
- if (mState == StreamDescriptor::State::ACTIVE ||
- mState == StreamDescriptor::State::DRAINING) {
- populateReply(&reply, mIsConnected);
- mState = mState == StreamDescriptor::State::ACTIVE
- ? StreamDescriptor::State::PAUSED
- : StreamDescriptor::State::DRAIN_PAUSED;
- } else {
- LOG(WARNING) << __func__ << ": PAUSE command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
- }
- } else if (command.code == StreamDescriptor::CommandCode::FLUSH && command.fmqByteCount == 0) {
- LOG(DEBUG) << __func__ << ": received FLUSH write command";
- if (mState == StreamDescriptor::State::PAUSED ||
- mState == StreamDescriptor::State::DRAIN_PAUSED) {
- populateReply(&reply, mIsConnected);
- mState = StreamDescriptor::State::IDLE;
- } else {
- LOG(WARNING) << __func__ << ": FLUSH command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
- }
- } else {
- LOG(WARNING) << __func__ << ": invalid command (" << command.toString()
- << ") or count: " << command.fmqByteCount;
- reply.status = STATUS_BAD_VALUE;
+ populateReply(&reply, mIsConnected);
+ mState = StreamDescriptor::State::IDLE;
+ } else {
+ LOG(WARNING) << __func__ << ": FLUSH command can not be handled in the state "
+ << toString(mState);
+ reply.status = STATUS_INVALID_OPERATION;
+ }
+ break;
}
reply.state = mState;
LOG(DEBUG) << __func__ << ": writing reply " << reply.toString();
@@ -421,9 +450,9 @@
void StreamCommon<Metadata, StreamWorker>::stopWorker() {
if (auto commandMQ = mContext.getCommandMQ(); commandMQ != nullptr) {
LOG(DEBUG) << __func__ << ": asking the worker to exit...";
- StreamDescriptor::Command cmd;
- cmd.code = StreamDescriptor::CommandCode(StreamContext::COMMAND_EXIT);
- cmd.fmqByteCount = mContext.getInternalCommandCookie();
+ auto cmd =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::hal_reserved_exit>(
+ mContext.getInternalCommandCookie());
// Note: never call 'pause' and 'resume' methods of StreamWorker
// in the HAL implementation. These methods are to be used by
// the client side only. Preventing the worker loop from running
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 539fa8b..5ee0f82 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -54,8 +54,6 @@
int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
DataMQ;
- // Ensure that this value is not used by any of StreamDescriptor.CommandCode enums
- static constexpr int32_t COMMAND_EXIT = -1;
// Ensure that this value is not used by any of StreamDescriptor.State enums
static constexpr int32_t STATE_CLOSED = -1;
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
index b415da4..df86c5b 100644
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
@@ -67,6 +67,7 @@
using aidl::android::media::audio::common::AudioPortExt;
using aidl::android::media::audio::common::AudioSource;
using aidl::android::media::audio::common::AudioUsage;
+using aidl::android::media::audio::common::Void;
using android::hardware::audio::common::isBitPositionFlagSet;
using android::hardware::audio::common::StreamLogic;
using android::hardware::audio::common::StreamWorker;
@@ -429,7 +430,9 @@
LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
return Status::ABORT;
}
- if (reply.fmqByteCount < 0 || reply.fmqByteCount > command.fmqByteCount) {
+ if (reply.fmqByteCount < 0 ||
+ (command.getTag() == StreamDescriptor::Command::Tag::burst &&
+ reply.fmqByteCount > command.get<StreamDescriptor::Command::Tag::burst>())) {
LOG(ERROR) << __func__
<< ": received invalid byte count in the reply: " << reply.fmqByteCount;
return Status::ABORT;
@@ -506,7 +509,9 @@
LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
return Status::ABORT;
}
- if (reply.fmqByteCount < 0 || reply.fmqByteCount > command.fmqByteCount) {
+ if (reply.fmqByteCount < 0 ||
+ (command.getTag() == StreamDescriptor::Command::Tag::burst &&
+ reply.fmqByteCount > command.get<StreamDescriptor::Command::Tag::burst>())) {
LOG(ERROR) << __func__
<< ": received invalid byte count in the reply: " << reply.fmqByteCount;
return Status::ABORT;
@@ -1419,18 +1424,15 @@
}
void SendInvalidCommandImpl(const AudioPortConfig& portConfig) {
- std::vector<StreamDescriptor::Command> commands(6);
- commands[0].code = StreamDescriptor::CommandCode(-1);
- commands[1].code = StreamDescriptor::CommandCode(
- static_cast<int32_t>(StreamDescriptor::CommandCode::START) - 1);
- commands[2].code = StreamDescriptor::CommandCode(std::numeric_limits<int32_t>::min());
- commands[3].code = StreamDescriptor::CommandCode(std::numeric_limits<int32_t>::max());
- // TODO: For proper testing of input streams, need to put the stream into
- // a state which accepts BURST commands.
- commands[4].code = StreamDescriptor::CommandCode::BURST;
- commands[4].fmqByteCount = -1;
- commands[5].code = StreamDescriptor::CommandCode::BURST;
- commands[5].fmqByteCount = std::numeric_limits<int32_t>::min();
+ std::vector<StreamDescriptor::Command> commands = {
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::hal_reserved_exit>(
+ 0),
+ // TODO: For proper testing of input streams, need to put the stream into
+ // a state which accepts BURST commands.
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(-1),
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(
+ std::numeric_limits<int32_t>::min()),
+ };
WithStream<Stream> stream(portConfig);
ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
StreamLogicDriverInvalidCommand driver(commands);
@@ -1496,7 +1498,7 @@
<< "when no offload info is provided for a compressed offload mix port";
}
-using CommandAndState = std::pair<StreamDescriptor::CommandCode, StreamDescriptor::State>;
+using CommandAndState = std::pair<StreamDescriptor::Command, StreamDescriptor::State>;
class StreamLogicDefaultDriver : public StreamLogicDriver {
public:
@@ -1511,15 +1513,17 @@
bool done() override { return mNextCommand >= mCommands.size(); }
StreamDescriptor::Command getNextCommand(int maxDataSize, int* actualSize) override {
- StreamDescriptor::Command command{};
- command.code = mCommands[mNextCommand++].first;
- const int dataSize = command.code == StreamDescriptor::CommandCode::BURST ? maxDataSize : 0;
- command.fmqByteCount = dataSize;
- if (actualSize != nullptr) {
- // In the output scenario, reduce slightly the fmqByteCount to verify
- // that the HAL module always consumes all data from the MQ.
- if (command.fmqByteCount > 1) command.fmqByteCount--;
- *actualSize = dataSize;
+ auto command = mCommands[mNextCommand++].first;
+ if (command.getTag() == StreamDescriptor::Command::Tag::burst) {
+ if (actualSize != nullptr) {
+ // In the output scenario, reduce slightly the fmqByteCount to verify
+ // that the HAL module always consumes all data from the MQ.
+ if (maxDataSize > 1) maxDataSize--;
+ *actualSize = maxDataSize;
+ }
+ command.set<StreamDescriptor::Command::Tag::burst>(maxDataSize);
+ } else {
+ if (actualSize != nullptr) *actualSize = 0;
}
return command;
}
@@ -1541,7 +1545,7 @@
.append(" to ")
.append(toString(reply.state))
.append(" caused by the command ")
- .append(toString(lastCommandState.first));
+ .append(lastCommandState.first.toString());
LOG(ERROR) << __func__ << ": " << s;
mUnexpectedTransition = std::move(s);
return false;
@@ -1835,112 +1839,90 @@
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamOut);
-static const NamedCommandSequence kReadOrWriteSeq = std::make_pair(
- std::string("ReadOrWrite"),
- std::vector<CommandAndState>{
- std::make_pair(StreamDescriptor::CommandCode::START, StreamDescriptor::State::IDLE),
- std::make_pair(StreamDescriptor::CommandCode::BURST,
- StreamDescriptor::State::ACTIVE),
- std::make_pair(StreamDescriptor::CommandCode::BURST,
- StreamDescriptor::State::ACTIVE),
- std::make_pair(StreamDescriptor::CommandCode::BURST,
- StreamDescriptor::State::ACTIVE)});
-static const NamedCommandSequence kDrainInSeq = std::make_pair(
- std::string("Drain"),
- std::vector<CommandAndState>{
- std::make_pair(StreamDescriptor::CommandCode::START, StreamDescriptor::State::IDLE),
- std::make_pair(StreamDescriptor::CommandCode::BURST,
- StreamDescriptor::State::ACTIVE),
- std::make_pair(StreamDescriptor::CommandCode::DRAIN,
- StreamDescriptor::State::DRAINING),
- std::make_pair(StreamDescriptor::CommandCode::START,
- StreamDescriptor::State::ACTIVE),
- std::make_pair(StreamDescriptor::CommandCode::DRAIN,
- StreamDescriptor::State::DRAINING),
- // TODO: This will need to be changed once DRAIN starts taking time.
- std::make_pair(StreamDescriptor::CommandCode::BURST,
- StreamDescriptor::State::STANDBY)});
-static const NamedCommandSequence kDrainOutSeq = std::make_pair(
- std::string("Drain"),
- std::vector<CommandAndState>{
- std::make_pair(StreamDescriptor::CommandCode::START, StreamDescriptor::State::IDLE),
- std::make_pair(StreamDescriptor::CommandCode::BURST,
- StreamDescriptor::State::ACTIVE),
- // TODO: This will need to be changed once DRAIN starts taking time.
- std::make_pair(StreamDescriptor::CommandCode::DRAIN,
- StreamDescriptor::State::IDLE)});
+static const StreamDescriptor::Command kStartCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::start>(Void{});
+static const StreamDescriptor::Command kBurstCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(0);
+static const StreamDescriptor::Command kDrainCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(Void{});
+static const StreamDescriptor::Command kStandbyCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::standby>(Void{});
+static const StreamDescriptor::Command kPauseCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::pause>(Void{});
+static const StreamDescriptor::Command kFlushCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::flush>(Void{});
+static const NamedCommandSequence kReadOrWriteSeq =
+ std::make_pair(std::string("ReadOrWrite"),
+ std::vector<CommandAndState>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE)});
+static const NamedCommandSequence kDrainInSeq =
+ std::make_pair(std::string("Drain"),
+ std::vector<CommandAndState>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kDrainCommand, StreamDescriptor::State::DRAINING),
+ std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kDrainCommand, StreamDescriptor::State::DRAINING),
+ // TODO: This will need to be changed once DRAIN starts taking time.
+ std::make_pair(kBurstCommand, StreamDescriptor::State::STANDBY)});
+static const NamedCommandSequence kDrainOutSeq =
+ std::make_pair(std::string("Drain"),
+ std::vector<CommandAndState>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ // TODO: This will need to be changed once DRAIN starts taking time.
+ std::make_pair(kDrainCommand, StreamDescriptor::State::IDLE)});
// TODO: This will need to be changed once DRAIN starts taking time so we can pause it.
static const NamedCommandSequence kDrainPauseOutSeq = std::make_pair(
std::string("DrainPause"),
- std::vector<CommandAndState>{
- std::make_pair(StreamDescriptor::CommandCode::START, StreamDescriptor::State::IDLE),
- std::make_pair(StreamDescriptor::CommandCode::BURST,
- StreamDescriptor::State::ACTIVE),
- std::make_pair(StreamDescriptor::CommandCode::DRAIN,
- StreamDescriptor::State::IDLE)});
-static const NamedCommandSequence kStandbySeq = std::make_pair(
- std::string("Standby"),
- std::vector<CommandAndState>{
- std::make_pair(StreamDescriptor::CommandCode::START, StreamDescriptor::State::IDLE),
- std::make_pair(StreamDescriptor::CommandCode::STANDBY,
- StreamDescriptor::State::STANDBY),
- // Perform a read or write in order to advance observable position
- // (this is verified by tests).
- std::make_pair(StreamDescriptor::CommandCode::START, StreamDescriptor::State::IDLE),
- std::make_pair(StreamDescriptor::CommandCode::BURST,
- StreamDescriptor::State::ACTIVE)});
-static const NamedCommandSequence kPauseInSeq = std::make_pair(
- std::string("Pause"),
- std::vector<CommandAndState>{
- std::make_pair(StreamDescriptor::CommandCode::START, StreamDescriptor::State::IDLE),
- std::make_pair(StreamDescriptor::CommandCode::BURST,
- StreamDescriptor::State::ACTIVE),
- std::make_pair(StreamDescriptor::CommandCode::PAUSE,
- StreamDescriptor::State::PAUSED),
- std::make_pair(StreamDescriptor::CommandCode::BURST,
- StreamDescriptor::State::ACTIVE),
- std::make_pair(StreamDescriptor::CommandCode::PAUSE,
- StreamDescriptor::State::PAUSED),
- std::make_pair(StreamDescriptor::CommandCode::FLUSH,
- StreamDescriptor::State::STANDBY)});
-static const NamedCommandSequence kPauseOutSeq = std::make_pair(
- std::string("Pause"),
- std::vector<CommandAndState>{
- std::make_pair(StreamDescriptor::CommandCode::START, StreamDescriptor::State::IDLE),
- std::make_pair(StreamDescriptor::CommandCode::BURST,
- StreamDescriptor::State::ACTIVE),
- std::make_pair(StreamDescriptor::CommandCode::PAUSE,
- StreamDescriptor::State::PAUSED),
- std::make_pair(StreamDescriptor::CommandCode::START,
- StreamDescriptor::State::ACTIVE),
- std::make_pair(StreamDescriptor::CommandCode::PAUSE,
- StreamDescriptor::State::PAUSED),
- std::make_pair(StreamDescriptor::CommandCode::BURST,
- StreamDescriptor::State::PAUSED),
- std::make_pair(StreamDescriptor::CommandCode::START,
- StreamDescriptor::State::ACTIVE),
- std::make_pair(StreamDescriptor::CommandCode::PAUSE,
- StreamDescriptor::State::PAUSED)});
-static const NamedCommandSequence kFlushInSeq = std::make_pair(
- std::string("Flush"),
- std::vector<CommandAndState>{
- std::make_pair(StreamDescriptor::CommandCode::START, StreamDescriptor::State::IDLE),
- std::make_pair(StreamDescriptor::CommandCode::BURST,
- StreamDescriptor::State::ACTIVE),
- std::make_pair(StreamDescriptor::CommandCode::PAUSE,
- StreamDescriptor::State::PAUSED),
- std::make_pair(StreamDescriptor::CommandCode::FLUSH,
- StreamDescriptor::State::STANDBY)});
+ std::vector<CommandAndState>{std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kDrainCommand, StreamDescriptor::State::IDLE)});
+static const NamedCommandSequence kStandbySeq =
+ std::make_pair(std::string("Standby"),
+ std::vector<CommandAndState>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kStandbyCommand, StreamDescriptor::State::STANDBY),
+ // Perform a read or write in order to advance observable position
+ // (this is verified by tests).
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE)});
+static const NamedCommandSequence kPauseInSeq =
+ std::make_pair(std::string("Pause"),
+ std::vector<CommandAndState>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kFlushCommand, StreamDescriptor::State::STANDBY)});
+static const NamedCommandSequence kPauseOutSeq =
+ std::make_pair(std::string("Pause"),
+ std::vector<CommandAndState>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED)});
+static const NamedCommandSequence kFlushInSeq =
+ std::make_pair(std::string("Flush"),
+ std::vector<CommandAndState>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kFlushCommand, StreamDescriptor::State::STANDBY)});
static const NamedCommandSequence kFlushOutSeq = std::make_pair(
std::string("Flush"),
- std::vector<CommandAndState>{
- std::make_pair(StreamDescriptor::CommandCode::START, StreamDescriptor::State::IDLE),
- std::make_pair(StreamDescriptor::CommandCode::BURST,
- StreamDescriptor::State::ACTIVE),
- std::make_pair(StreamDescriptor::CommandCode::PAUSE,
- StreamDescriptor::State::PAUSED),
- std::make_pair(StreamDescriptor::CommandCode::FLUSH,
- StreamDescriptor::State::IDLE)});
+ std::vector<CommandAndState>{std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kFlushCommand, StreamDescriptor::State::IDLE)});
std::string GetStreamIoTestName(const testing::TestParamInfo<StreamIoTestParameters>& info) {
return android::PrintInstanceNameToString(
testing::TestParamInfo<std::string>{std::get<PARAM_MODULE_NAME>(info.param),