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