| /* Copyright 2016 The Chromium OS Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include <syslog.h> |
| |
| #include "cras_ramp.h" |
| |
| |
| /* |
| * State of cras_ramp: |
| * CRAS_RAMP_STATE_IDLE: No ramping is started, or a ramping is already done. |
| * CRAS_RAMP_STATE_UP: Ramping up from 0 to 1. |
| * CRAS_RAMP_STATE_DOWN: Ramping down from certain scaler to 0. |
| */ |
| enum CRAS_RAMP_STATE { |
| CRAS_RAMP_STATE_IDLE, |
| CRAS_RAMP_STATE_UP, |
| CRAS_RAMP_STATE_DOWN, |
| }; |
| |
| /* |
| * Struct to hold ramping information. |
| * Members: |
| * state: Current state. One of CRAS_RAMP_STATE. |
| * ramped_frames: Number of frames that have passed after starting ramping. |
| * duration_frames: The targeted number of frames for whole ramping duration. |
| * increment: The scaler increment that should be added to scaler for |
| * every frame. |
| * start_scaler: The initial scaler. |
| * cb: Callback function to call after ramping is done. |
| * cb_data: Data passed to cb. |
| */ |
| struct cras_ramp { |
| enum CRAS_RAMP_STATE state; |
| int ramped_frames; |
| int duration_frames; |
| float increment; |
| float start_scaler; |
| void (*cb)(void *data); |
| void *cb_data; |
| }; |
| |
| void cras_ramp_destroy(struct cras_ramp* ramp) |
| { |
| free(ramp); |
| } |
| |
| struct cras_ramp* cras_ramp_create() |
| { |
| struct cras_ramp* ramp; |
| ramp = (struct cras_ramp*)malloc(sizeof(*ramp)); |
| if (ramp == NULL) { |
| return NULL; |
| } |
| cras_ramp_reset(ramp); |
| return ramp; |
| } |
| |
| int cras_ramp_reset(struct cras_ramp *ramp) { |
| ramp->state = CRAS_RAMP_STATE_IDLE; |
| ramp->ramped_frames = 0; |
| ramp->duration_frames = 0; |
| ramp->increment = 0; |
| ramp->start_scaler = 1.0; |
| return 0; |
| } |
| |
| int cras_ramp_start(struct cras_ramp *ramp, int is_up, int duration_frames, |
| cras_ramp_cb cb, void *cb_data) |
| { |
| struct cras_ramp_action action; |
| |
| /* Get current scaler position so it can serve as new start scaler. */ |
| action = cras_ramp_get_current_action(ramp); |
| if (action.type == CRAS_RAMP_ACTION_INVALID) |
| return -EINVAL; |
| |
| /* Set initial scaler to current scaler so ramping up/down can be |
| * smoothly switched. */ |
| if (is_up) { |
| ramp->state = CRAS_RAMP_STATE_UP; |
| if (action.type == CRAS_RAMP_ACTION_NONE) |
| ramp->start_scaler = 0; |
| else |
| ramp->start_scaler = action.scaler; |
| ramp->increment = (1 - ramp->start_scaler) / duration_frames; |
| } else { |
| ramp->state = CRAS_RAMP_STATE_DOWN; |
| if (action.type == CRAS_RAMP_ACTION_NONE) |
| ramp->start_scaler = 1; |
| else |
| ramp->start_scaler = action.scaler; |
| |
| ramp->increment = -ramp->start_scaler / duration_frames; |
| } |
| ramp->ramped_frames = 0; |
| ramp->duration_frames = duration_frames; |
| ramp->cb = cb; |
| ramp->cb_data = cb_data; |
| return 0; |
| } |
| |
| struct cras_ramp_action cras_ramp_get_current_action(const struct cras_ramp *ramp) |
| { |
| struct cras_ramp_action action; |
| |
| if (ramp->ramped_frames < 0) { |
| action.type = CRAS_RAMP_ACTION_INVALID; |
| action.scaler = 1.0; |
| action.increment = 0.0; |
| return action; |
| } |
| |
| switch (ramp->state) { |
| case CRAS_RAMP_STATE_IDLE: |
| action.type = CRAS_RAMP_ACTION_NONE; |
| action.scaler = 1.0; |
| action.increment = 0.0; |
| break; |
| case CRAS_RAMP_STATE_DOWN: |
| action.type = CRAS_RAMP_ACTION_PARTIAL; |
| action.scaler = ramp->start_scaler + |
| ramp->ramped_frames * ramp->increment; |
| action.increment = ramp->increment; |
| break; |
| case CRAS_RAMP_STATE_UP: |
| action.type = CRAS_RAMP_ACTION_PARTIAL; |
| action.scaler = ramp->start_scaler + |
| ramp->ramped_frames * ramp->increment; |
| action.increment = ramp->increment; |
| break; |
| } |
| return action; |
| } |
| |
| int cras_ramp_update_ramped_frames( |
| struct cras_ramp *ramp, int num_frames) |
| { |
| if (ramp->state == CRAS_RAMP_STATE_IDLE) |
| return -EINVAL; |
| ramp->ramped_frames += num_frames; |
| if (ramp->ramped_frames >= ramp->duration_frames) { |
| ramp->state = CRAS_RAMP_STATE_IDLE; |
| if (ramp->cb) |
| ramp->cb(ramp->cb_data); |
| } |
| return 0; |
| } |