Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b2b0ce95 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "AIDL effect: add draining state support" into main

parents fcdcb3c0 240c1d41
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -37,4 +37,5 @@ enum State {
  INIT,
  IDLE,
  PROCESSING,
  DRAINING,
}
+24 −10
Original line number Diff line number Diff line
@@ -33,25 +33,39 @@ enum CommandId {
    /**
     * Start effect engine processing.
     * An effect instance must start processing data and transfer to PROCESSING state if it is in
     * IDLE state and have all necessary information. Otherwise it must:
     * 1. Throw a EX_ILLEGAL_STATE exception if effect is not in IDLE state, or
     * 2. Throw a EX_TRANSACTION_FAILED for all other errors.
     * IDLE or DRAINING state and has all necessary information. Otherwise, it must:
     * 1. Throw an EX_ILLEGAL_STATE exception if the effect is not in IDLE or DRAINING state, or
     * 2. Throw an EX_TRANSACTION_FAILED for all other errors.
     *
     * Depending on parameters set to the effect instance, effect may do process or reverse
     * process after START command.
     * If an effect instance in DRAINING state receives a START command, it must transit back to
     * PROCESSING state.
     */
    START = 0,
    /**
     * Stop effect engine processing with all resource kept.
     * The currently processed audio data will be discarded if the effect engine is in PROCESSING
     * state.
     * Effect instance must do nothing and return ok when it receive STOP command in IDLE state.
     * Stop effect engine processing with all resources kept.
     * If the effect is in **PROCESSING** state:
     *   - It must transition to **IDLE** state if no intermediate operations are required.
     *   - It must transition to **DRAINING** state if draining (e.g., fading) is required.
     *     - The instance must automatically transition to **IDLE** after draining.
     *     - It must ignore any new `STOP` commands during **DRAINING**.
     *     - `START` commands during **DRAINING** must transition the instance back to
     *       **PROCESSING**.
     * If the effect instance is already in **IDLE** state, it must do nothing and return success.
     *
     * If the effect instance transitions to DRAINING state:
     * 1. It must automatically transition to IDLE after completing draining tasks.
     * 2. It must ignore any new STOP commands received during the DRAINING state.
     * 3. START commands during DRAINING must immediately transfer the instance back to PROCESSING.
     *
     */
    STOP = 1,
    /**
     * Keep all parameter settings but reset the buffer content, stop engine processing, and transit
     * instance state to IDLE if its in PROCESSING state.
     * the instance state to IDLE if it is in PROCESSING state.
     * Effect instance must be able to handle RESET command at IDLE and PROCESSING states.
     *
     * If the implementation includes intermediate operations such as draining, the RESET command
     * must bypass DRAINING and immediately transition the state to IDLE.
     */
    RESET = 2,

+54 −12
Original line number Diff line number Diff line
@@ -24,18 +24,18 @@ package android.hardware.audio.effect;
 * it should transfer to IDLE state after handle the command successfully. Effect instance should
 * consume minimal resource and transfer to INIT state after it was close().
 *
 * Refer to State.gv for detailed state diagram.
 * Refer to the state machine diagram `state.gv` for a detailed state diagram.
 */
@VintfStability
@Backing(type="byte")
enum State {

    /**
     * An effect instance is in INIT state by default after it was created with
     * IFactory.createEffect(). When an effect instance is in INIT state, it should have instance
     * context initialized, and ready to handle IEffect.setParameter(), IEffect.open() as well as
     * all getter interfaces.
     *
     * **Requirements in INIT state:**
     * In INIT state, effect instance must:
     * 1. Not handle any IEffect.command() and return EX_ILLEGAL_STATE with any Command.Id.
     * 2. Be able to handle all parameter setting with IEffect.setParameter().
@@ -43,28 +43,32 @@ enum State {
     * IEffect.getState().
     * 4. Be able to handle IEffect.open() successfully after configuration.
     *
     * Client is expected to do necessary configuration with IEffect.setParameter(), get all
     * resource ready with IEffect.open(), and make sure effect instance transfer to IDLE state
     * before sending commands with IEffect.command() interface. Effect instance must transfer
     * from INIT to IDLE state after handle IEffect.open() call successfully.
     * **State Transitions:**
     * - Transitions to **IDLE** after successful `IEffect.open()`.
     * - Remains in **INIT** on `IEffect.getState()` and `IEffect.getDescriptor()`.
     * - Transitions to the final state on `IFactory.destroyEffect()`.
     */
    INIT,

    /**
     * An effect instance transfer to IDLE state after it was open successfully with IEffect.open()
     * in INIT state, or after it was stop/reset with Command.Id.STOP/RESET in PROCESSING state.
     *
     * In IDLE state, effect instance must:
     * **Requirements in IDLE state:**
     * 1. Be able to start effect processing engine with IEffect.command(Command.Id.START) call.
     * 2. Be able to handle all parameter setting with IEffect.setParameter().
     * 3. Be able to handle all getter interface calls like IEffect.getParameter() and
     * IEffect.getState().
     *
     * The following state transfer can happen in IDLE state:
     * 1. Transfer to PROCESSING if instance receive an START command and start processing data
     * successfully.
     * 2. Transfer to INIT if instance receive a close() call.
     * **State Transitions:**
     * - Transitions to **PROCESSING** on `IEffect.command(CommandId.START)` after starting
     *   processing data successfully.
     * - Transitions to **INIT** on `IEffect.close()`.
     * - Remains in **IDLE** on `IEffect.getParameter()`, `IEffect.setParameter()`,
     *   `IEffect.getDescriptor()`, `IEffect.command(CommandId.RESET)`, and `IEffect.reopen()`.
     */
    IDLE,

    /**
     * An effect instance is in PROCESSING state after it receive an START command and start
     * processing data successfully. Effect instance will transfer from PROCESSING to IDLE state if
@@ -75,12 +79,50 @@ enum State {
     * the case of a close() call received when instance in PROCESSING state, it should try to stop
     * processing and transfer to IDLE first before close().
     *
     * In PROCESSING state, effect instance must:
     * **Requirements in PROCESSING state:**
     * 1. Return EX_ILLEGAL_STATE if it's not able to handle any parameter settings at runtime.
     * 2. Be able to handle STOP and RESET for IEffect.command() interface, and return
     * EX_ILLEGAL_STATE for all other commands.
     * 3. Must be able to handle all get* interface calls like IEffect.getParameter() and
     * IEffect.getState().
     *
     * **State Transitions:**
     * - Transitions to **IDLE** on `IEffect.command(CommandId.STOP)` ( if no draining is required
     *   or implemented) or `IEffect.command(CommandId.RESET)`.
     * - Transitions to **DRAINING** on `IEffect.command(CommandId.STOP)` if draining is required.
     * - Remains in **PROCESSING** on `IEffect.getParameter()`, `IEffect.setParameter()`,
     *   `IEffect.getDescriptor()`, and `IEffect.reopen()`.
     *
     * **Notes:**
     * - Clients should avoid calling `IEffect.close()` directly in this state; instead, they should
     *   stop processing with `CommandId.STOP` before closing.
     * - If `IEffect.close()` is called in this state, the effect instance should stop processing,
     *   transition to **IDLE**, and then close.
     */
    PROCESSING,

    /**
     * DRAINING is an optional transitional state where the effect instance completes processing
     * remaining input buffers or finalizes operations (e.g., fading) before stopping completely.
     * This state is typically entered after a `CommandId.STOP` command in the PROCESSING state when
     * draining is required.
     *
     * **Requirements in DRAINING state:**
     * 1. Must handle `CommandId.START` and transition back to **PROCESSING**.
     * 2. Must handle getter interface calls like `IEffect.getParameter()` and `IEffect.getState()`.
     * 3. Must automatically transition to **IDLE** after draining is complete.
     *
     * **State Transitions:**
     * - Transitions to **PROCESSING** on `IEffect.command(CommandId.START)`.
     * - Transitions to **IDLE** on `IEffect.command(CommandId.RESET)`.
     * - Transitions to **IDLE** automatically after draining is complete.
     * - Remains in **DRAINING** on `IEffect.getParameter()`, `IEffect.setParameter()`,
     *   `IEffect.getDescriptor()`, and `IEffect.reopen()`.
     *
     * **Notes:**
     * - If not implemented, the effect instance may transition directly from **PROCESSING** to
     *   **IDLE** without this intermediate state.
     * - Any `CommandId.STOP` commands received during **DRAINING** should be ignored.
     */
    DRAINING,
}
+50 −20
Original line number Diff line number Diff line
@@ -13,26 +13,56 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// To render: "dot -Tpng state.gv -o state.png"

digraph effect_state_machine {
    node[shape = point style = filled fillcolor = black width = 0.5] I;
    node[shape = doublecircle] F;
    node[shape = oval width = 1];
    node[fillcolor = lightgreen] INIT;
    node[fillcolor = lightblue] IDLE;
    node[fillcolor = lightyellow] PROCESSING;

    I -> INIT[label = "IFactory.createEffect" labelfontcolor = "navy"];

    rankdir=LR; // Left to Right layout

    label="Effect State Machine";
    fontsize=20;
    labelloc=top;

    node [fontname="Helvetica", fontsize=12, style=filled];

    // Initial state node
    I [shape=point, fillcolor=black, width=0.2];

    // Final state node
    F [shape=doublecircle, fillcolor=white, width=0.2];

    // Define other nodes with colors
    INIT [shape=ellipse, fillcolor=lightgreen];
    IDLE [shape=ellipse, fillcolor=lightblue];
    PROCESSING [shape=ellipse, fillcolor=lightyellow];
    DRAINING [shape=ellipse, fillcolor=lightgrey];

    // Transitions
    I -> INIT [label="IFactory.createEffect", fontcolor="navy"];

    INIT -> F [label="IFactory.destroyEffect"];
    INIT -> IDLE[label = "IEffect.open()" labelfontcolor = "lime"];
    IDLE -> PROCESSING[label = "IEffect.command(START"];

    INIT -> IDLE [label="IEffect.open()", fontcolor="lime"];

    IDLE -> PROCESSING [label="IEffect.command(START)"];

    PROCESSING -> IDLE [label="IEffect.command(STOP)\nIEffect.command(RESET)"];

    PROCESSING -> DRAINING [label="IEffect.command(STOP)", fontcolor="orange"];

    DRAINING -> IDLE [label="Draining complete\n(IEffect.command(RESET)\nautomatic)"];

    DRAINING -> PROCESSING [label="IEffect.command(START)\n(Interrupt draining)"];

    IDLE -> INIT [label="IEffect.close()"];

    // Self-loops
    INIT -> INIT [label="IEffect.getState\nIEffect.getDescriptor"];

    IDLE -> IDLE [label="IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor\nIEffect.command(RESET)\nIEffect.reopen"];
    PROCESSING
            -> PROCESSING
                    [label = "IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor\nIEffect.reopen"];

    PROCESSING -> PROCESSING [label="IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor\nIEffect.reopen"];

    DRAINING -> DRAINING [label="IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor\nIEffect.reopen\nFading"];

}
+14 −0
Original line number Diff line number Diff line
@@ -258,4 +258,18 @@ RetCode EffectContext::reset() {
    return RetCode::SUCCESS;
}

RetCode EffectContext::startDraining() {
    mIsDraining = true;
    return RetCode::SUCCESS;
}

RetCode EffectContext::finishDraining() {
    mIsDraining = false;
    return RetCode::SUCCESS;
}

bool EffectContext::isDraining() {
    return mIsDraining;
}

}  // namespace aidl::android::hardware::audio::effect
Loading