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