There are a number of approaches. The three workable approaches would be:
- Use a device called a "digital pot"; these behave electrically much like real pots, provided that all three terminals remain between the voltage rails. Note that many digital pots have fairly high wiper resistance, and fairly crummy resistance tolerance, but pretty good resistance matching; they are often used in cases where they are driven by low-impedance sources, and they are used to feed high-impedance inputs, so the exact resistance characteristics don't matter.
- Use a scaling digital-to-analog converter which can accept the analog signal as its reference. A scaling DAC behaves something like a digital pot which has one end tied to physical or virtual ground. The fact that one end is "tied to ground" may simplify the circuitry compared to a digital pot.
- Use an analog-to-digital converter to convert all incoming signals to digital form, then process them digitally (doing things like scaling them up and down by multiplying the numbers), and then output them all using a digital-to-analog converter.
- If the signal originates in digital form (as with a CD player), do processing including the volume adjustment digitally, as in #3 above, but skip the ADC since the signal starts in the digital domain anyhow.
Addendum
Another approach which may sometimes be useful is to filter the signal to be output to ensure it has no components above a certain frequency, pulse-width modulate it at a frequency at least twice as high as the highest frequency passed by the filter, and then filter it again to remove the PWM artifacts. The requirement for double filtering may limit the audio fidelity that may be achieved via this method, but it can be pretty simple to implement crudely.