1 /* Copyright 2016 The Chromium OS Authors. All rights reserved.
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  */
5 
6 #include <syslog.h>
7 
8 #include "cras_ramp.h"
9 
10 
11 /*
12  * State of cras_ramp:
13  *   CRAS_RAMP_STATE_IDLE: No ramping is started, or a ramping is already done.
14  *   CRAS_RAMP_STATE_UP: Ramping up from 0 to 1.
15  *   CRAS_RAMP_STATE_DOWN: Ramping down from certain scaler to 0.
16  */
17 enum CRAS_RAMP_STATE {
18 	CRAS_RAMP_STATE_IDLE,
19 	CRAS_RAMP_STATE_UP,
20 	CRAS_RAMP_STATE_DOWN,
21 };
22 
23 /*
24  * Struct to hold ramping information.
25  * Members:
26  *   state: Current state. One of CRAS_RAMP_STATE.
27  *   ramped_frames: Number of frames that have passed after starting ramping.
28  *   duration_frames: The targeted number of frames for whole ramping duration.
29  *   increment: The scaler increment that should be added to scaler for
30  *              every frame.
31  *   start_scaler: The initial scaler.
32  *   cb: Callback function to call after ramping is done.
33  *   cb_data: Data passed to cb.
34  */
35 struct cras_ramp {
36 	enum CRAS_RAMP_STATE state;
37 	int ramped_frames;
38 	int duration_frames;
39 	float increment;
40 	float start_scaler;
41 	void (*cb)(void *data);
42 	void *cb_data;
43 };
44 
cras_ramp_destroy(struct cras_ramp * ramp)45 void cras_ramp_destroy(struct cras_ramp* ramp)
46 {
47 	free(ramp);
48 }
49 
cras_ramp_create()50 struct cras_ramp* cras_ramp_create()
51 {
52 	struct cras_ramp* ramp;
53 	ramp = (struct cras_ramp*)malloc(sizeof(*ramp));
54 	if (ramp == NULL) {
55 		return NULL;
56 	}
57 	cras_ramp_reset(ramp);
58 	return ramp;
59 }
60 
cras_ramp_reset(struct cras_ramp * ramp)61 int cras_ramp_reset(struct cras_ramp *ramp) {
62 	ramp->state = CRAS_RAMP_STATE_IDLE;
63 	ramp->ramped_frames = 0;
64 	ramp->duration_frames = 0;
65 	ramp->increment = 0;
66 	ramp->start_scaler = 1.0;
67 	return 0;
68 }
69 
cras_ramp_start(struct cras_ramp * ramp,int is_up,int duration_frames,cras_ramp_cb cb,void * cb_data)70 int cras_ramp_start(struct cras_ramp *ramp, int is_up, int duration_frames,
71 		    cras_ramp_cb cb, void *cb_data)
72 {
73 	struct cras_ramp_action action;
74 
75 	/* Get current scaler position so it can serve as new start scaler. */
76 	action = cras_ramp_get_current_action(ramp);
77 	if (action.type == CRAS_RAMP_ACTION_INVALID)
78 		return -EINVAL;
79 
80         /* Set initial scaler to current scaler so ramping up/down can be
81          * smoothly switched. */
82 	if (is_up) {
83 		ramp->state = CRAS_RAMP_STATE_UP;
84 		if (action.type == CRAS_RAMP_ACTION_NONE)
85 			ramp->start_scaler = 0;
86 		else
87 			ramp->start_scaler = action.scaler;
88 		ramp->increment = (1 - ramp->start_scaler) / duration_frames;
89 	} else {
90 		ramp->state = CRAS_RAMP_STATE_DOWN;
91 		if (action.type == CRAS_RAMP_ACTION_NONE)
92 			ramp->start_scaler = 1;
93 		else
94 			ramp->start_scaler = action.scaler;
95 
96 		ramp->increment = -ramp->start_scaler / duration_frames;
97 	}
98 	ramp->ramped_frames = 0;
99 	ramp->duration_frames = duration_frames;
100 	ramp->cb = cb;
101 	ramp->cb_data = cb_data;
102 	return 0;
103 }
104 
cras_ramp_get_current_action(const struct cras_ramp * ramp)105 struct cras_ramp_action cras_ramp_get_current_action(const struct cras_ramp *ramp)
106 {
107 	struct cras_ramp_action action;
108 
109 	if (ramp->ramped_frames < 0) {
110 		action.type = CRAS_RAMP_ACTION_INVALID;
111 		action.scaler = 1.0;
112 		action.increment = 0.0;
113 		return action;
114 	}
115 
116 	switch (ramp->state) {
117 	case CRAS_RAMP_STATE_IDLE:
118 		action.type = CRAS_RAMP_ACTION_NONE;
119 		action.scaler = 1.0;
120 		action.increment = 0.0;
121 		break;
122 	case CRAS_RAMP_STATE_DOWN:
123 		action.type = CRAS_RAMP_ACTION_PARTIAL;
124 		action.scaler = ramp->start_scaler +
125 				ramp->ramped_frames * ramp->increment;
126 		action.increment = ramp->increment;
127 		break;
128 	case CRAS_RAMP_STATE_UP:
129 		action.type = CRAS_RAMP_ACTION_PARTIAL;
130 		action.scaler = ramp->start_scaler +
131 				ramp->ramped_frames * ramp->increment;
132 		action.increment = ramp->increment;
133 		break;
134 	}
135 	return action;
136 }
137 
cras_ramp_update_ramped_frames(struct cras_ramp * ramp,int num_frames)138 int cras_ramp_update_ramped_frames(
139 		struct cras_ramp *ramp, int num_frames)
140 {
141 	if (ramp->state == CRAS_RAMP_STATE_IDLE)
142 		return -EINVAL;
143 	ramp->ramped_frames += num_frames;
144 	if (ramp->ramped_frames >= ramp->duration_frames) {
145 		ramp->state = CRAS_RAMP_STATE_IDLE;
146 		if (ramp->cb)
147 			ramp->cb(ramp->cb_data);
148 	}
149 	return 0;
150 }
151