mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 22:04:26 +00:00
Merge "audio: Make StreamDescriptor::Command a union" am: 2b68543625 am: 224a3b1755
Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/2296167 Change-Id: I29a46c3c67df1311d9e1d9ed88e2b85b2de16f45 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -55,19 +55,15 @@ parcelable StreamDescriptor {
|
||||
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 {
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.hardware.audio.core;
|
||||
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 @@ parcelable StreamDescriptor {
|
||||
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 @@ parcelable StreamDescriptor {
|
||||
* 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 @@ parcelable StreamDescriptor {
|
||||
*/
|
||||
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;
|
||||
/**
|
||||
|
||||
@@ -23,16 +23,16 @@ digraph stream_in_state_machine {
|
||||
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>"];
|
||||
|
||||
@@ -24,22 +24,22 @@ digraph stream_out_state_machine {
|
||||
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>"];
|
||||
|
||||
@@ -106,101 +106,116 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() {
|
||||
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 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
|
||||
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 @@ template <class Metadata, class StreamWorker>
|
||||
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
|
||||
|
||||
@@ -54,8 +54,6 @@ class StreamContext {
|
||||
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;
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ using aidl::android::media::audio::common::AudioPortDeviceExt;
|
||||
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;
|
||||
@@ -455,7 +456,9 @@ class StreamReaderLogic : public StreamCommonLogic {
|
||||
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;
|
||||
@@ -532,7 +535,9 @@ class StreamWriterLogic : public StreamCommonLogic {
|
||||
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;
|
||||
@@ -1551,18 +1556,15 @@ class AudioStream : public AudioCoreModule {
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -1628,7 +1630,7 @@ TEST_P(AudioStreamOut, RequireOffloadInfo) {
|
||||
<< "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:
|
||||
@@ -1643,15 +1645,17 @@ class StreamLogicDefaultDriver : public StreamLogicDriver {
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1673,7 +1677,7 @@ class StreamLogicDefaultDriver : public StreamLogicDriver {
|
||||
.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;
|
||||
@@ -1970,112 +1974,90 @@ INSTANTIATE_TEST_SUITE_P(AudioStreamOutTest, AudioStreamOut,
|
||||
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),
|
||||
|
||||
Reference in New Issue
Block a user