/* 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;
}