Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
9a70c4d0
Commit
9a70c4d0
authored
Dec 31, 2008
by
Viliam Mateicka
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Moving mixers to audio outputs
parent
dd9af72a
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
672 additions
and
445 deletions
+672
-445
NEWS
NEWS
+1
-0
mpd.conf.5
doc/mpd.conf.5
+19
-5
mpdconf.example
doc/mpdconf.example
+6
-10
Makefile.am
src/Makefile.am
+2
-1
audio.c
src/audio.c
+55
-0
audio.h
src/audio.h
+5
-0
command.c
src/command.c
+3
-3
main.c
src/main.c
+2
-3
mixer.h
src/mixer.h
+33
-0
alsa_mixer.c
src/mixer/alsa_mixer.c
+206
-0
oss_mixer.c
src/mixer/oss_mixer.c
+197
-0
alsa_plugin.c
src/output/alsa_plugin.c
+21
-1
oss_plugin.c
src/output/oss_plugin.c
+19
-0
output_api.h
src/output_api.h
+12
-0
volume.c
src/volume.c
+86
-416
volume.h
src/volume.h
+5
-6
No files found.
NEWS
View file @
9a70c4d0
ver 0.15 - (200?/??/??)
* Rewritten mixer code to support multiple mixers
* Add audio archive extraction support:
- bzip2
- iso9660
...
...
doc/mpd.conf.5
View file @
9a70c4d0
...
...
@@ -157,18 +157,23 @@ Linear interpolator, very fast, poor quality.
For an up-to-date list of available converters, please see the libsamplerate
documentation (available online at <\fBhttp://www.mega-nerd.com/SRC/\fP>).
.TP
.B mixer_type <oss, alsa or software>
This specifies which mixer to use. The default depends on what audio output
support mpd was built with.
.B mixer_type <alsa, oss, software or hardware>
This specifies which mixer to use. The default is hardware and depends on
what audio output support mpd was built with. Options alsa and oss are
legacy and should not be used in new configs, but when set mixer_device
and mixer_control will apply.
.TP
.B mixer_device <mixer dev>
This specifies which mixer to use. The default for oss is "/dev/mixer"; the
default for alsa is "default".
default for alsa is "default". This option is deprecated and should not be
used. Look at the mix_device option of corresponding output device instead.
.TP
.B mixer_control <mixer ctrl>
This specifies which mixer control to use (sometimes referred to as the
"device"). Examples of mixer controls are PCM, Line1, Master, etc. An example
for OSS is "Pcm", and an example for alsa is "PCM".
for OSS is "Pcm", and an example for alsa is "PCM". This option is deprecated
and should not be used. Look at the mix_control option of corresponding
output device instead.
.TP
.B replaygain <album or track>
If specified, mpd will adjust the volume of songs played using ReplayGain tags
...
...
@@ -276,6 +281,15 @@ whatever audio format is passed to the audio output.
.B device <dev>
This specifies the device to use for audio output. The default is "default".
.TP
.B mix_device <mixer dev>
This specifies which mixer to use. The default for oss is "/dev/mixer"; the
default for alsa is "default".
.TP
.B mix_control <mixer ctrl>
This specifies which mixer control to use (sometimes referred to as the
"device"). Examples of mixer controls are PCM, Line1, Master, etc. An example
for OSS is "Pcm", and an example for alsa is "PCM".
.TP
.B use_mmap <yes or no>
Setting this allows you to use memory-mapped I/O. Certain hardware setups may
benefit from this, but most do not. Most users do not need to set this. The
...
...
doc/mpdconf.example
View file @
9a70c4d0
...
...
@@ -162,6 +162,8 @@ log_file "~/.mpd/log"
# name "My ALSA Device"
# device "hw:0,0" # optional
# format "44100:16:2" # optional
# mix_device "default" # optional
# mix_control "PCM" # optional
#}
#
# An example of an OSS output:
...
...
@@ -171,6 +173,8 @@ log_file "~/.mpd/log"
# name "My OSS Device"
# device "/dev/dsp" # optional
# format "44100:16:2" # optional
# mix_device "/dev/mixer" # optional
# mix_control "PCM" # optional
#}
#
# An example of a shout output (for streaming to Icecast):
...
...
@@ -232,17 +236,9 @@ log_file "~/.mpd/log"
# specified it may be autodetected at startup, depending on the dependencies
# which were compiled into the server.
#
# An example for controlling an ALSA mixer:
# An example for controlling an ALSA
or OSS
mixer:
#
#mixer_type "alsa"
#mixer_device "default"
#mixer_control "PCM"
#
# An example for controlling an OSS mixer:
#
#mixer_type "oss"
#mixer_device "/dev/mixer"
#mixer_control "PCM"
#mixer_type "hardware"
#
# This example is a general volume control mixer, it is used to adjust the
# volume of the audio sent to the audio output, and will work with all outputs.
...
...
src/Makefile.am
View file @
9a70c4d0
...
...
@@ -273,6 +273,7 @@ endif
if
HAVE_ALSA
mpd_SOURCES
+=
output/alsa_plugin.c
mpd_SOURCES
+=
mixer/alsa_mixer.c
endif
if
HAVE_AO
...
...
@@ -293,6 +294,7 @@ endif
if
HAVE_OSS
mpd_SOURCES
+=
output/oss_plugin.c
mpd_SOURCES
+=
mixer/oss_mixer.c
endif
if
HAVE_OSX
...
...
@@ -315,7 +317,6 @@ if HAVE_SHOUT_OGG
mpd_SOURCES
+=
output/shout_ogg.c
endif
mpd_CFLAGS
=
$(MPD_CFLAGS)
mpd_CPPFLAGS
=
\
$(CURL_CFLAGS)
\
...
...
src/audio.c
View file @
9a70c4d0
...
...
@@ -25,6 +25,7 @@
#include "client.h"
#include "idle.h"
#include "utils.h"
#include "mixer.h"
#include <glib.h>
...
...
@@ -428,3 +429,57 @@ errline:
}
}
bool
mixer_control_setvol
(
unsigned
int
device
,
int
volume
,
int
rel
)
{
struct
audio_output
*
output
;
if
(
device
>=
audioOutputArraySize
)
return
false
;
output
=
&
audioOutputArray
[
device
];
if
(
output
->
plugin
&&
output
->
plugin
->
control
)
{
if
(
rel
)
{
int
cur_volume
;
if
(
!
output
->
plugin
->
control
(
output
->
data
,
AC_MIXER_GETVOL
,
&
cur_volume
))
{
return
false
;
}
volume
=
volume
+
cur_volume
;
}
if
(
volume
>
100
)
volume
=
100
;
else
if
(
volume
<
0
)
volume
=
0
;
return
output
->
plugin
->
control
(
output
->
data
,
AC_MIXER_SETVOL
,
&
volume
);
}
return
false
;
}
bool
mixer_control_getvol
(
unsigned
int
device
,
int
*
volume
)
{
struct
audio_output
*
output
;
if
(
device
>=
audioOutputArraySize
)
return
false
;
output
=
&
audioOutputArray
[
device
];
if
(
output
->
plugin
&&
output
->
plugin
->
control
)
{
return
output
->
plugin
->
control
(
output
->
data
,
AC_MIXER_GETVOL
,
volume
);
}
return
false
;
}
bool
mixer_configure_legacy
(
char
*
name
,
ConfigParam
*
param
)
{
unsigned
i
;
struct
audio_output
*
output
;
for
(
i
=
0
;
i
<
audioOutputArraySize
;
++
i
)
{
output
=
&
audioOutputArray
[
i
];
if
(
output
&&
output
->
plugin
&&
!
strcmp
(
name
,
output
->
plugin
->
name
))
{
if
(
output
->
plugin
->
control
)
{
g_debug
(
"reconfiguring %s mixer
\n
"
,
name
);
return
output
->
plugin
->
control
(
output
->
data
,
AC_MIXER_CONFIGURE
,
param
);
}
}
}
return
false
;
}
src/audio.h
View file @
9a70c4d0
...
...
@@ -21,6 +21,7 @@
#include <stdbool.h>
#include <stdio.h>
#include "conf.h"
#define AUDIO_AO_DRIVER_DEFAULT "default"
...
...
@@ -70,4 +71,8 @@ void readAudioDevicesState(FILE *fp);
void
saveAudioDevicesState
(
FILE
*
fp
);
bool
mixer_control_setvol
(
unsigned
int
device
,
int
volume
,
int
rel
);
bool
mixer_control_getvol
(
unsigned
int
device
,
int
*
volume
);
bool
mixer_configure_legacy
(
char
*
name
,
ConfigParam
*
param
);
#endif
src/command.c
View file @
9a70c4d0
...
...
@@ -388,7 +388,7 @@ handle_status(struct client *client,
COMMAND_STATUS_PLAYLIST_LENGTH
": %i
\n
"
COMMAND_STATUS_CROSSFADE
": %i
\n
"
COMMAND_STATUS_STATE
": %s
\n
"
,
getVolumeLevel
(),
volume_level_get
(),
getPlaylistRepeatStatus
(),
getPlaylistRandomStatus
(),
getPlaylistVersion
(),
...
...
@@ -906,7 +906,7 @@ handle_volume(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if
(
!
check_int
(
client
,
&
change
,
argv
[
1
],
need_integer
))
return
COMMAND_RETURN_ERROR
;
ret
=
changeVolumeLevel
(
change
,
1
);
ret
=
volume_level_change
(
change
,
1
);
if
(
ret
==
-
1
)
command_error
(
client
,
ACK_ERROR_SYSTEM
,
"problems setting volume"
);
...
...
@@ -922,7 +922,7 @@ handle_setvol(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if
(
!
check_int
(
client
,
&
level
,
argv
[
1
],
need_integer
))
return
COMMAND_RETURN_ERROR
;
ret
=
changeVolumeLevel
(
level
,
0
);
ret
=
volume_level_change
(
level
,
0
);
if
(
ret
==
-
1
)
command_error
(
client
,
ACK_ERROR_SYSTEM
,
"problems setting volume"
);
...
...
src/main.c
View file @
9a70c4d0
...
...
@@ -264,7 +264,7 @@ int main(int argc, char *argv[])
dc_init
();
initAudioConfig
();
initAudioDriver
();
initVolume
();
volume_init
();
client_manager_init
();
replay_gain_global_init
();
initNormalization
();
...
...
@@ -278,7 +278,6 @@ int main(int argc, char *argv[])
initZeroconf
();
openVolumeDevice
();
decoder_thread_start
();
player_create
();
read_state_file
();
...
...
@@ -315,7 +314,7 @@ int main(int argc, char *argv[])
finishNormalization
();
finishAudioDriver
();
finishAudioConfig
();
finishVolume
();
volume_finish
();
mapper_finish
();
path_global_finish
();
finishPermissions
();
...
...
src/mixer.h
0 → 100644
View file @
9a70c4d0
#ifndef MPD_MIXER_H
#define MPD_MIXER_H
#include "conf.h"
/**
* alsa mixer
*/
struct
alsa_mixer
;
struct
alsa_mixer
*
alsa_mixer_init
(
void
);
void
alsa_mixer_finish
(
struct
alsa_mixer
*
am
);
void
alsa_mixer_configure
(
struct
alsa_mixer
*
am
,
ConfigParam
*
param
);
bool
alsa_mixer_open
(
struct
alsa_mixer
*
am
);
bool
alsa_mixer_control
(
struct
alsa_mixer
*
am
,
int
cmd
,
void
*
arg
);
void
alsa_mixer_close
(
struct
alsa_mixer
*
am
);
/**
* oss mixer
*/
struct
oss_mixer
;
struct
oss_mixer
*
oss_mixer_init
(
void
);
void
oss_mixer_finish
(
struct
oss_mixer
*
am
);
void
oss_mixer_configure
(
struct
oss_mixer
*
am
,
ConfigParam
*
param
);
bool
oss_mixer_open
(
struct
oss_mixer
*
am
);
bool
oss_mixer_control
(
struct
oss_mixer
*
am
,
int
cmd
,
void
*
arg
);
void
oss_mixer_close
(
struct
oss_mixer
*
am
);
#endif
src/mixer/alsa_mixer.c
0 → 100644
View file @
9a70c4d0
#include "../output_api.h"
#include "../mixer.h"
#include <glib.h>
#include <alsa/asoundlib.h>
#define VOLUME_MIXER_ALSA_DEFAULT "default"
#define VOLUME_MIXER_ALSA_CONTROL_DEFAULT "PCM"
struct
alsa_mixer
{
char
*
device
;
char
*
control
;
snd_mixer_t
*
handle
;
snd_mixer_elem_t
*
elem
;
long
volume_min
;
long
volume_max
;
int
volume_set
;
};
struct
alsa_mixer
*
alsa_mixer_init
(
void
)
{
struct
alsa_mixer
*
am
=
g_malloc
(
sizeof
(
struct
alsa_mixer
));
am
->
device
=
NULL
;
am
->
control
=
NULL
;
am
->
handle
=
NULL
;
am
->
elem
=
NULL
;
am
->
volume_min
=
0
;
am
->
volume_max
=
0
;
am
->
volume_set
=
-
1
;
return
am
;
}
void
alsa_mixer_finish
(
struct
alsa_mixer
*
am
)
{
g_free
(
am
);
}
void
alsa_mixer_configure
(
struct
alsa_mixer
*
am
,
ConfigParam
*
param
)
{
BlockParam
*
bp
;
if
((
bp
=
getBlockParam
(
param
,
"mix_device"
)))
am
->
device
=
bp
->
value
;
if
((
bp
=
getBlockParam
(
param
,
"mix_control"
)))
am
->
control
=
bp
->
value
;
}
void
alsa_mixer_close
(
struct
alsa_mixer
*
am
)
{
if
(
am
->
handle
)
snd_mixer_close
(
am
->
handle
);
am
->
handle
=
NULL
;
}
bool
alsa_mixer_open
(
struct
alsa_mixer
*
am
)
{
int
err
;
snd_mixer_elem_t
*
elem
;
const
char
*
control_name
=
VOLUME_MIXER_ALSA_CONTROL_DEFAULT
;
const
char
*
device
=
VOLUME_MIXER_ALSA_DEFAULT
;
if
(
am
->
device
)
{
device
=
am
->
device
;
}
err
=
snd_mixer_open
(
&
am
->
handle
,
0
);
snd_config_update_free_global
();
if
(
err
<
0
)
{
g_warning
(
"problems opening alsa mixer: %s
\n
"
,
snd_strerror
(
err
));
return
false
;
}
if
((
err
=
snd_mixer_attach
(
am
->
handle
,
device
))
<
0
)
{
g_warning
(
"problems attaching alsa mixer: %s
\n
"
,
snd_strerror
(
err
));
alsa_mixer_close
(
am
);
return
false
;
}
if
((
err
=
snd_mixer_selem_register
(
am
->
handle
,
NULL
,
NULL
))
<
0
)
{
g_warning
(
"problems snd_mixer_selem_register'ing: %s
\n
"
,
snd_strerror
(
err
));
alsa_mixer_close
(
am
);
return
false
;
}
if
((
err
=
snd_mixer_load
(
am
->
handle
))
<
0
)
{
g_warning
(
"problems snd_mixer_selem_register'ing: %s
\n
"
,
snd_strerror
(
err
));
alsa_mixer_close
(
am
);
return
false
;
}
elem
=
snd_mixer_first_elem
(
am
->
handle
);
if
(
am
->
control
)
{
control_name
=
am
->
control
;
}
while
(
elem
)
{
if
(
snd_mixer_elem_get_type
(
elem
)
==
SND_MIXER_ELEM_SIMPLE
)
{
if
(
strcasecmp
(
control_name
,
snd_mixer_selem_get_name
(
elem
))
==
0
)
{
break
;
}
}
elem
=
snd_mixer_elem_next
(
elem
);
}
if
(
elem
)
{
am
->
elem
=
elem
;
snd_mixer_selem_get_playback_volume_range
(
am
->
elem
,
&
am
->
volume_min
,
&
am
->
volume_max
);
return
true
;
}
g_warning
(
"can't find alsa mixer control
\"
%s
\"\n
"
,
control_name
);
alsa_mixer_close
(
am
);
return
false
;
}
bool
alsa_mixer_control
(
struct
alsa_mixer
*
am
,
int
cmd
,
void
*
arg
)
{
switch
(
cmd
)
{
case
AC_MIXER_CONFIGURE
:
alsa_mixer_configure
(
am
,
(
ConfigParam
*
)
arg
);
if
(
am
->
handle
)
alsa_mixer_close
(
am
);
return
true
;
case
AC_MIXER_GETVOL
:
{
int
err
;
int
ret
,
*
volume
=
arg
;
long
level
;
if
(
!
am
->
handle
&&
!
alsa_mixer_open
(
am
))
{
return
false
;
}
if
((
err
=
snd_mixer_handle_events
(
am
->
handle
))
<
0
)
{
g_warning
(
"problems getting alsa volume: %s (snd_mixer_%s)
\n
"
,
snd_strerror
(
err
),
"handle_events"
);
alsa_mixer_close
(
am
);
return
false
;
}
if
((
err
=
snd_mixer_selem_get_playback_volume
(
am
->
elem
,
SND_MIXER_SCHN_FRONT_LEFT
,
&
level
))
<
0
)
{
g_warning
(
"problems getting alsa volume: %s (snd_mixer_%s)
\n
"
,
snd_strerror
(
err
),
"selem_get_playback_volume"
);
alsa_mixer_close
(
am
);
return
false
;
}
ret
=
((
am
->
volume_set
/
100
.
0
)
*
(
am
->
volume_max
-
am
->
volume_min
)
+
am
->
volume_min
)
+
0
.
5
;
if
(
am
->
volume_set
>
0
&&
ret
==
level
)
{
ret
=
am
->
volume_set
;
}
else
{
ret
=
(
int
)(
100
*
(((
float
)(
level
-
am
->
volume_min
))
/
(
am
->
volume_max
-
am
->
volume_min
))
+
0
.
5
);
}
*
volume
=
ret
;
return
true
;
}
case
AC_MIXER_SETVOL
:
{
float
vol
;
long
level
;
int
*
volume
=
arg
;
int
err
;
if
(
!
am
->
handle
&&
!
alsa_mixer_open
(
am
))
{
return
false
;
}
vol
=
*
volume
;
am
->
volume_set
=
vol
+
0
.
5
;
am
->
volume_set
=
am
->
volume_set
>
100
?
100
:
(
am
->
volume_set
<
0
?
0
:
am
->
volume_set
);
level
=
(
long
)(((
vol
/
100
.
0
)
*
(
am
->
volume_max
-
am
->
volume_min
)
+
am
->
volume_min
)
+
0
.
5
);
level
=
level
>
am
->
volume_max
?
am
->
volume_max
:
level
;
level
=
level
<
am
->
volume_min
?
am
->
volume_min
:
level
;
if
((
err
=
snd_mixer_selem_set_playback_volume_all
(
am
->
elem
,
level
))
<
0
)
{
g_warning
(
"problems setting alsa volume: %s
\n
"
,
snd_strerror
(
err
));
alsa_mixer_close
(
am
);
return
false
;
}
return
true
;
}
default:
g_warning
(
"Unsuported alsa control
\n
"
);
break
;
}
return
false
;
}
src/mixer/oss_mixer.c
0 → 100644
View file @
9a70c4d0
#include <glib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include "../output_api.h"
#include "../mixer.h"
#if defined(__OpenBSD__) || defined(__NetBSD__)
# include <soundcard.h>
#else
/* !(defined(__OpenBSD__) || defined(__NetBSD__) */
# include <sys/soundcard.h>
#endif
/* !(defined(__OpenBSD__) || defined(__NetBSD__) */
#define VOLUME_MIXER_OSS_DEFAULT "/dev/mixer"
struct
oss_mixer
{
const
char
*
device
;
const
char
*
control
;
int
device_fd
;
int
volume_control
;
};
struct
oss_mixer
*
oss_mixer_init
(
void
);
void
oss_mixer_finish
(
struct
oss_mixer
*
am
);
void
oss_mixer_configure
(
struct
oss_mixer
*
am
,
ConfigParam
*
param
);
bool
oss_mixer_open
(
struct
oss_mixer
*
am
);
bool
oss_mixer_control
(
struct
oss_mixer
*
am
,
int
cmd
,
void
*
arg
);
void
oss_mixer_close
(
struct
oss_mixer
*
am
);
struct
oss_mixer
*
oss_mixer_init
(
void
)
{
struct
oss_mixer
*
om
=
g_malloc
(
sizeof
(
struct
oss_mixer
));
om
->
device
=
NULL
;
om
->
control
=
NULL
;
om
->
device_fd
=
-
1
;
om
->
volume_control
=
SOUND_MIXER_PCM
;
return
om
;
}
void
oss_mixer_finish
(
struct
oss_mixer
*
om
)
{
g_free
(
om
);
}
void
oss_mixer_configure
(
struct
oss_mixer
*
om
,
ConfigParam
*
param
)
{
BlockParam
*
bp
;
bp
=
getBlockParam
(
param
,
"mix_device"
);
if
(
bp
)
{
om
->
device
=
bp
->
value
;
}
bp
=
getBlockParam
(
param
,
"mix_control"
);
if
(
bp
)
{
om
->
control
=
bp
->
value
;
}
}
void
oss_mixer_close
(
struct
oss_mixer
*
om
)
{
if
(
om
->
device_fd
!=
-
1
)
while
(
close
(
om
->
device_fd
)
&&
errno
==
EINTR
)
;
om
->
device_fd
=
-
1
;
}
static
int
oss_find_mixer
(
const
char
*
name
)
{
const
char
*
labels
[
SOUND_MIXER_NRDEVICES
]
=
SOUND_DEVICE_LABELS
;
size_t
name_length
=
strlen
(
name
);
for
(
unsigned
i
=
0
;
i
<
SOUND_MIXER_NRDEVICES
;
i
++
)
{
if
(
strncasecmp
(
name
,
labels
[
i
],
name_length
)
==
0
&&
(
labels
[
i
][
name_length
]
==
0
||
labels
[
i
][
name_length
]
==
' '
))
return
i
;
}
return
-
1
;
}
bool
oss_mixer_open
(
struct
oss_mixer
*
om
)
{
const
char
*
device
=
VOLUME_MIXER_OSS_DEFAULT
;
if
(
om
->
device
)
{
device
=
om
->
device
;
}
if
((
om
->
device_fd
=
open
(
device
,
O_RDONLY
))
<
0
)
{
g_warning
(
"Unable to open oss mixer
\"
%s
\"\n
"
,
device
);
return
false
;
}
if
(
om
->
control
)
{
int
i
;
int
devmask
=
0
;
if
(
ioctl
(
om
->
device_fd
,
SOUND_MIXER_READ_DEVMASK
,
&
devmask
)
<
0
)
{
g_warning
(
"errors getting read_devmask for oss mixer
\n
"
);
oss_mixer_close
(
om
);
return
false
;
}
i
=
oss_find_mixer
(
om
->
control
);
if
(
i
<
0
)
{
g_warning
(
"mixer control
\"
%s
\"
not found
\n
"
,
om
->
control
);
oss_mixer_close
(
om
);
return
false
;
}
else
if
(
!
((
1
<<
i
)
&
devmask
))
{
g_warning
(
"mixer control
\"
%s
\"
not usable
\n
"
,
om
->
control
);
oss_mixer_close
(
om
);
return
false
;
}
om
->
volume_control
=
i
;
}
return
true
;
}
bool
oss_mixer_control
(
struct
oss_mixer
*
om
,
int
cmd
,
void
*
arg
)
{
switch
(
cmd
)
{
case
AC_MIXER_CONFIGURE
:
oss_mixer_configure
(
om
,
(
ConfigParam
*
)
arg
);
//if (om->device_fd >= 0)
oss_mixer_close
(
om
);
return
true
;
break
;
case
AC_MIXER_GETVOL
:
{
int
left
,
right
,
level
;
int
*
ret
;
if
(
om
->
device_fd
<
0
&&
!
oss_mixer_open
(
om
))
{
return
false
;
}
if
(
ioctl
(
om
->
device_fd
,
MIXER_READ
(
om
->
volume_control
),
&
level
)
<
0
)
{
oss_mixer_close
(
om
);
g_warning
(
"unable to read oss volume
\n
"
);
return
false
;
}
left
=
level
&
0xff
;
right
=
(
level
&
0xff00
)
>>
8
;
if
(
left
!=
right
)
{
g_warning
(
"volume for left and right is not the same,
\"
%i
\"
and "
"
\"
%i
\"\n
"
,
left
,
right
);
}
ret
=
(
int
*
)
arg
;
*
ret
=
left
;
return
true
;
}
case
AC_MIXER_SETVOL
:
{
int
new
;
int
level
;
int
*
value
=
arg
;
if
(
om
->
device_fd
<
0
&&
!
oss_mixer_open
(
om
))
{
return
false
;
}
new
=
*
value
;
if
(
new
<
0
)
{
new
=
0
;
}
else
if
(
new
>
100
)
{
new
=
100
;
}
level
=
(
new
<<
8
)
+
new
;
if
(
ioctl
(
om
->
device_fd
,
MIXER_WRITE
(
om
->
volume_control
),
&
level
)
<
0
)
{
g_warning
(
"unable to set oss volume
\n
"
);
oss_mixer_close
(
om
);
return
false
;
}
return
true
;
}
default:
g_warning
(
"Unsuported oss control
\n
"
);
break
;
}
return
false
;
}
src/output/alsa_plugin.c
View file @
9a70c4d0
...
...
@@ -18,6 +18,7 @@
#include "../output_api.h"
#include "../utils.h"
#include "../mixer.h"
#include <glib.h>
#include <alsa/asoundlib.h>
...
...
@@ -51,6 +52,9 @@ typedef struct _AlsaData {
unsigned
int
period_time
;
int
sampleSize
;
int
useMmap
;
struct
alsa_mixer
*
mixer
;
}
AlsaData
;
static
const
char
*
...
...
@@ -71,12 +75,15 @@ static AlsaData *newAlsaData(void)
ret
->
buffer_time
=
MPD_ALSA_BUFFER_TIME_US
;
ret
->
period_time
=
0
;
ret
->
mixer
=
alsa_mixer_init
();
return
ret
;
}
static
void
freeAlsaData
(
AlsaData
*
ad
)
{
g_free
(
ad
->
device
);
alsa_mixer_finish
(
ad
->
mixer
);
free
(
ad
);
}
...
...
@@ -125,8 +132,10 @@ static void *alsa_initDriver(mpd_unused struct audio_output *ao,
free_global_registered
=
1
;
}
if
(
param
)
if
(
param
)
{
alsa_configure
(
ad
,
param
);
alsa_mixer_configure
(
ad
->
mixer
,
param
);
}
return
ad
;
}
...
...
@@ -181,6 +190,8 @@ static bool alsa_openDevice(void *data, struct audio_format *audioFormat)
unsigned
int
period_time
,
period_time_ro
;
unsigned
int
buffer_time
;
alsa_mixer_open
(
ad
->
mixer
);
if
((
bitformat
=
get_bitformat
(
audioFormat
))
==
SND_PCM_FORMAT_UNKNOWN
)
g_warning
(
"ALSA device
\"
%s
\"
doesn't support %u bit audio
\n
"
,
alsa_device
(
ad
),
audioFormat
->
bits
);
...
...
@@ -403,6 +414,7 @@ static void alsa_closeDevice(void *data)
snd_pcm_close
(
ad
->
pcmHandle
);
ad
->
pcmHandle
=
NULL
;
}
alsa_mixer_close
(
ad
->
mixer
);
}
static
bool
...
...
@@ -436,6 +448,13 @@ alsa_playAudio(void *data, const char *playChunk, size_t size)
return
true
;
}
static
bool
alsa_control
(
void
*
data
,
int
cmd
,
void
*
arg
)
{
AlsaData
*
ad
=
data
;
return
alsa_mixer_control
(
ad
->
mixer
,
cmd
,
arg
);
}
const
struct
audio_output_plugin
alsaPlugin
=
{
.
name
=
"alsa"
,
.
test_default_device
=
alsa_testDefault
,
...
...
@@ -445,4 +464,5 @@ const struct audio_output_plugin alsaPlugin = {
.
play
=
alsa_playAudio
,
.
cancel
=
alsa_dropBufferedAudio
,
.
close
=
alsa_closeDevice
,
.
control
=
alsa_control
};
src/output/oss_plugin.c
View file @
9a70c4d0
...
...
@@ -20,6 +20,7 @@
*/
#include "../output_api.h"
#include "../mixer.h"
#include <glib.h>
#include <sys/stat.h>
...
...
@@ -53,6 +54,7 @@ typedef struct _OssData {
int
numSupported
[
3
];
int
*
unsupported
[
3
];
int
numUnsupported
[
3
];
struct
oss_mixer
*
mixer
;
}
OssData
;
enum
oss_support
{
...
...
@@ -273,6 +275,8 @@ static OssData *newOssData(void)
supportParam
(
ret
,
SNDCTL_DSP_CHANNELS
,
2
);
supportParam
(
ret
,
SNDCTL_DSP_SAMPLESIZE
,
16
);
ret
->
mixer
=
oss_mixer_init
();
return
ret
;
}
...
...
@@ -285,6 +289,8 @@ static void freeOssData(OssData * od)
g_free
(
od
->
unsupported
[
OSS_CHANNELS
]);
g_free
(
od
->
unsupported
[
OSS_BITS
]);
oss_mixer_finish
(
od
->
mixer
);
free
(
od
);
}
...
...
@@ -348,6 +354,7 @@ static void *oss_open_default(ConfigParam *param)
if
(
ret
[
i
]
==
0
)
{
OssData
*
od
=
newOssData
();
od
->
device
=
default_devices
[
i
];
oss_mixer_configure
(
od
->
mixer
,
param
);
return
od
;
}
}
...
...
@@ -388,6 +395,7 @@ static void *oss_initDriver(mpd_unused struct audio_output *audioOutput,
if
(
bp
)
{
OssData
*
od
=
newOssData
();
od
->
device
=
bp
->
value
;
oss_mixer_configure
(
od
->
mixer
,
param
);
return
od
;
}
}
...
...
@@ -513,6 +521,8 @@ oss_openDevice(void *data, struct audio_format *audioFormat)
od
->
audio_format
.
bits
,
od
->
audio_format
.
channels
,
od
->
audio_format
.
sample_rate
);
oss_mixer_open
(
od
->
mixer
);
return
ret
;
}
...
...
@@ -521,6 +531,7 @@ static void oss_closeDevice(void *data)
OssData
*
od
=
data
;
oss_close
(
od
);
oss_mixer_close
(
od
->
mixer
);
}
static
void
oss_dropBufferedAudio
(
void
*
data
)
...
...
@@ -559,6 +570,13 @@ oss_playAudio(void *data, const char *playChunk, size_t size)
return
true
;
}
static
bool
oss_control
(
void
*
data
,
int
cmd
,
void
*
arg
)
{
OssData
*
od
=
data
;
return
oss_mixer_control
(
od
->
mixer
,
cmd
,
arg
);
}
const
struct
audio_output_plugin
ossPlugin
=
{
.
name
=
"oss"
,
.
test_default_device
=
oss_testDefault
,
...
...
@@ -568,4 +586,5 @@ const struct audio_output_plugin ossPlugin = {
.
play
=
oss_playAudio
,
.
cancel
=
oss_dropBufferedAudio
,
.
close
=
oss_closeDevice
,
.
control
=
oss_control
,
};
src/output_api.h
View file @
9a70c4d0
...
...
@@ -101,6 +101,12 @@ struct audio_output_plugin {
void
(
*
close
)(
void
*
data
);
/**
* Control the device. Usualy used for implementing
* set and get mixer levels
*/
bool
(
*
control
)(
void
*
data
,
int
cmd
,
void
*
arg
);
/**
* Display metadata for the next chunk. Optional method,
* because not all devices can display metadata.
*/
...
...
@@ -118,6 +124,12 @@ enum audio_output_command {
AO_COMMAND_KILL
};
enum
audio_control_command
{
AC_MIXER_GETVOL
=
0
,
AC_MIXER_SETVOL
,
AC_MIXER_CONFIGURE
,
};
struct
audio_output
;
const
char
*
audio_output_get_name
(
const
struct
audio_output
*
ao
);
...
...
src/volume.c
View file @
9a70c4d0
...
...
@@ -15,475 +15,141 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "volume.h"
#include "conf.h"
#include "player_control.h"
#include "utils.h"
#include "idle.h"
#include "pcm_utils.h"
#include "config.h"
#include "audio.h"
#include <glib.h>
#include <math.h>
#include <string.h>
#ifdef HAVE_OSS
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#endif
#ifdef HAVE_ALSA
#include <alsa/asoundlib.h>
#endif
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "volume"
#define VOLUME_MIXER_TYPE_SOFTWARE 0
#define VOLUME_MIXER_TYPE_OSS 1
#define VOLUME_MIXER_TYPE_ALSA 2
#define VOLUME_MIXER_TYPE_HARDWARE 1
#define VOLUME_MIXER_SOFTWARE_DEFAULT ""
#define VOLUME_MIXER_OSS_DEFAULT "/dev/mixer"
#define VOLUME_MIXER_ALSA_DEFAULT "default"
#define VOLUME_MIXER_ALSA_CONTROL_DEFAULT "PCM"
#define SW_VOLUME_STATE "sw_volume: "
#ifdef HAVE_OSS
#define VOLUME_MIXER_TYPE_DEFAULT VOLUME_MIXER_TYPE_OSS
#define VOLUME_MIXER_DEVICE_DEFAULT VOLUME_MIXER_OSS_DEFAULT
#else
#ifdef HAVE_ALSA
#define VOLUME_MIXER_TYPE_DEFAULT VOLUME_MIXER_TYPE_ALSA
#define VOLUME_MIXER_DEVICE_DEFAULT VOLUME_MIXER_ALSA_DEFAULT
#else
#define VOLUME_MIXER_TYPE_DEFAULT VOLUME_MIXER_TYPE_SOFTWARE
#define VOLUME_MIXER_DEVICE_DEFAULT VOLUME_MIXER_SOFTWARE_DEFAULT
#endif
#endif
static
int
volume_mixerType
=
VOLUME_MIXER_TYPE_DEFAULT
;
static
const
char
*
volume_mixerDevice
=
VOLUME_MIXER_DEVICE_DEFAULT
;
static
int
volume_softwareSet
=
100
;
#ifdef HAVE_OSS
static
int
volume_ossFd
=
-
1
;
static
int
volume_ossControl
=
SOUND_MIXER_PCM
;
#endif
#ifdef HAVE_ALSA
static
snd_mixer_t
*
volume_alsaMixerHandle
;
static
snd_mixer_elem_t
*
volume_alsaElem
;
static
long
volume_alsaMin
;
static
long
volume_alsaMax
;
static
int
volume_alsaSet
=
-
1
;
#endif
#ifdef HAVE_OSS
static
void
closeOssMixer
(
void
)
{
while
(
close
(
volume_ossFd
)
&&
errno
==
EINTR
)
;
volume_ossFd
=
-
1
;
}
static
int
oss_find_mixer
(
const
char
*
name
)
{
const
char
*
labels
[
SOUND_MIXER_NRDEVICES
]
=
SOUND_DEVICE_LABELS
;
size_t
name_length
=
strlen
(
name
);
for
(
unsigned
i
=
0
;
i
<
SOUND_MIXER_NRDEVICES
;
i
++
)
{
if
(
strncasecmp
(
name
,
labels
[
i
],
name_length
)
==
0
&&
(
labels
[
i
][
name_length
]
==
0
||
labels
[
i
][
name_length
]
==
' '
))
return
i
;
}
const
struct
audio_output_plugin
*
default_mixer
;
static
int
volume_mixer_type
=
VOLUME_MIXER_TYPE_HARDWARE
;
static
int
volume_software_set
=
100
;
return
-
1
;
}
static
int
prepOssMixer
(
const
char
*
device
)
void
volume_finish
(
void
)
{
ConfigParam
*
param
;
if
((
volume_ossFd
=
open
(
device
,
O_RDONLY
))
<
0
)
{
g_warning
(
"unable to open oss mixer
\"
%s
\"
"
,
device
);
return
-
1
;
}
if
((
param
=
getConfigParam
(
CONF_MIXER_CONTROL
)))
{
int
i
;
int
devmask
=
0
;
if
(
ioctl
(
volume_ossFd
,
SOUND_MIXER_READ_DEVMASK
,
&
devmask
)
<
0
)
{
g_warning
(
"errors getting read_devmask for oss mixer"
);
closeOssMixer
();
return
-
1
;
}
i
=
oss_find_mixer
(
param
->
value
);
if
(
i
<
0
)
{
g_warning
(
"mixer control
\"
%s
\"
not found at line %i"
,
param
->
value
,
param
->
line
);
closeOssMixer
();
return
-
1
;
}
else
if
(
!
((
1
<<
i
)
&
devmask
))
{
g_warning
(
"mixer control
\"
%s
\"
not usable at line %i"
,
param
->
value
,
param
->
line
);
closeOssMixer
();
return
-
1
;
}
volume_ossControl
=
i
;
}
return
0
;
}
static
int
ensure_oss_open
(
void
)
static
void
mixer_reconfigure
(
char
*
driver
)
{
if
((
volume_ossFd
<
0
&&
prepOssMixer
(
volume_mixerDevice
)
<
0
))
return
-
1
;
return
0
;
}
static
int
getOssVolumeLevel
(
void
)
{
int
left
,
right
,
level
;
if
(
ensure_oss_open
()
<
0
)
return
-
1
;
if
(
ioctl
(
volume_ossFd
,
MIXER_READ
(
volume_ossControl
),
&
level
)
<
0
)
{
closeOssMixer
();
g_warning
(
"unable to read volume"
);
return
-
1
;
}
left
=
level
&
0xff
;
right
=
(
level
&
0xff00
)
>>
8
;
if
(
left
!=
right
)
{
g_warning
(
"volume for left and right is not the same,
\"
%i
\"
"
"and
\"
%i
\"
"
,
left
,
right
);
}
return
left
;
}
static
int
changeOssVolumeLevel
(
int
change
,
int
rel
)
{
int
current
;
int
new
;
int
level
;
if
(
rel
)
{
if
((
current
=
getOssVolumeLevel
())
<
0
)
return
-
1
;
new
=
current
+
change
;
}
else
{
if
(
ensure_oss_open
()
<
0
)
return
-
1
;
new
=
change
;
}
if
(
new
<
0
)
new
=
0
;
else
if
(
new
>
100
)
new
=
100
;
level
=
(
new
<<
8
)
+
new
;
if
(
ioctl
(
volume_ossFd
,
MIXER_WRITE
(
volume_ossControl
),
&
level
)
<
0
)
{
closeOssMixer
();
return
-
1
;
}
return
0
;
}
#endif
#ifdef HAVE_ALSA
static
void
closeAlsaMixer
(
void
)
{
snd_mixer_close
(
volume_alsaMixerHandle
);
volume_alsaMixerHandle
=
NULL
;
}
static
int
prepAlsaMixer
(
const
char
*
card
)
{
int
err
;
snd_mixer_elem_t
*
elem
;
const
char
*
controlName
=
VOLUME_MIXER_ALSA_CONTROL_DEFAULT
;
ConfigParam
*
param
;
err
=
snd_mixer_open
(
&
volume_alsaMixerHandle
,
0
);
snd_config_update_free_global
();
if
(
err
<
0
)
{
g_warning
(
"problems opening alsa mixer: %s"
,
snd_strerror
(
err
));
return
-
1
;
}
if
((
err
=
snd_mixer_attach
(
volume_alsaMixerHandle
,
card
))
<
0
)
{
closeAlsaMixer
();
g_warning
(
"problems attaching alsa mixer: %s"
,
snd_strerror
(
err
));
return
-
1
;
}
ConfigParam
*
newparam
,
*
param
;
if
((
err
=
snd_mixer_selem_register
(
volume_alsaMixerHandle
,
NULL
,
NULL
))
<
0
)
{
closeAlsaMixer
();
g_warning
(
"problems snd_mixer_selem_register'ing: %s"
,
snd_strerror
(
err
));
return
-
1
;
}
//create parameter list
newparam
=
newConfigParam
(
NULL
,
-
1
);
if
((
err
=
snd_mixer_load
(
volume_alsaMixerHandle
))
<
0
)
{
closeAlsaMixer
();
g_warning
(
"problems snd_mixer_selem_register'ing: %s"
,
snd_strerror
(
err
));
return
-
1
;
param
=
getConfigParam
(
CONF_MIXER_DEVICE
);
if
(
param
)
{
g_warning
(
"deprecated option mixer_device found, translating to %s config section
\n
"
,
driver
);
addBlockParam
(
newparam
,
"mix_device"
,
param
->
value
,
-
1
);
}
elem
=
snd_mixer_first_elem
(
volume_alsaMixerHandle
);
param
=
getConfigParam
(
CONF_MIXER_CONTROL
);
if
(
param
)
{
controlName
=
param
->
value
;
g_warning
(
"deprecated option mixer_control found, translating to %s config section
\n
"
,
driver
);
addBlockParam
(
newparam
,
"mix_control"
,
param
->
value
,
-
1
);
}
while
(
elem
)
{
if
(
snd_mixer_elem_get_type
(
elem
)
==
SND_MIXER_ELEM_SIMPLE
)
{
if
(
strcasecmp
(
controlName
,
snd_mixer_selem_get_name
(
elem
))
==
0
)
{
break
;
}
}
elem
=
snd_mixer_elem_next
(
elem
);
if
(
newparam
->
numberOfBlockParams
>
0
)
{
//call configure method of corrensponding mixer
if
(
!
mixer_configure_legacy
(
driver
,
newparam
))
{
g_error
(
"Using mixer_type '%s' with not enabled %s output"
,
driver
,
driver
);
}
if
(
elem
)
{
volume_alsaElem
=
elem
;
snd_mixer_selem_get_playback_volume_range
(
volume_alsaElem
,
&
volume_alsaMin
,
&
volume_alsaMax
);
return
0
;
}
g_warning
(
"can't find alsa mixer_control
\"
%s
\"
"
,
controlName
);
closeAlsaMixer
();
return
-
1
;
}
static
int
prep_alsa_get_level
(
long
*
level
)
void
volume_init
(
void
)
{
const
char
*
cmd
;
int
err
;
if
(
!
volume_alsaMixerHandle
&&
prepAlsaMixer
(
volume_mixerDevice
)
<
0
)
return
-
1
;
if
((
err
=
snd_mixer_handle_events
(
volume_alsaMixerHandle
))
<
0
)
{
cmd
=
"handle_events"
;
goto
error
;
ConfigParam
*
param
=
getConfigParam
(
CONF_MIXER_TYPE
);
//hw mixing is by default
if
(
param
)
{
if
(
strcmp
(
param
->
value
,
VOLUME_MIXER_SOFTWARE
)
==
0
)
{
volume_mixer_type
=
VOLUME_MIXER_TYPE_SOFTWARE
;
}
else
if
(
strcmp
(
param
->
value
,
VOLUME_MIXER_HARDWARE
)
==
0
)
{
//nothing to do
}
else
{
//fallback to old config behaviour
if
(
strcmp
(
param
->
value
,
VOLUME_MIXER_OSS
)
==
0
)
{
mixer_reconfigure
(
param
->
value
);
}
else
if
(
strcmp
(
param
->
value
,
VOLUME_MIXER_ALSA
)
==
0
)
{
mixer_reconfigure
(
param
->
value
);
}
else
{
g_error
(
"unknown mixer type %s at line %i
\n
"
,
param
->
value
,
param
->
line
);
}
if
((
err
=
snd_mixer_selem_get_playback_volume
(
volume_alsaElem
,
SND_MIXER_SCHN_FRONT_LEFT
,
level
))
<
0
)
{
cmd
=
"selem_get_playback_volume"
;
goto
error
;
}
return
0
;
error:
g_warning
(
"problems getting alsa volume: %s (snd_mixer_%s)"
,
snd_strerror
(
err
),
cmd
);
closeAlsaMixer
();
return
-
1
;
}
static
int
getAlsaVolumeLevel
(
void
)
{
int
ret
;
long
level
;
long
max
=
volume_alsaMax
;
long
min
=
volume_alsaMin
;
if
(
prep_alsa_get_level
(
&
level
)
<
0
)
return
-
1
;
ret
=
((
volume_alsaSet
/
100
.
0
)
*
(
max
-
min
)
+
min
)
+
0
.
5
;
if
(
volume_alsaSet
>
0
&&
ret
==
level
)
{
ret
=
volume_alsaSet
;
}
else
ret
=
(
int
)(
100
*
(((
float
)(
level
-
min
))
/
(
max
-
min
))
+
0
.
5
);
return
ret
;
}
static
int
changeAlsaVolumeLevel
(
int
change
,
int
rel
)
{
float
vol
;
long
level
;
long
test
;
long
max
=
volume_alsaMax
;
long
min
=
volume_alsaMin
;
int
err
;
if
(
prep_alsa_get_level
(
&
level
)
<
0
)
return
-
1
;
if
(
rel
)
{
test
=
((
volume_alsaSet
/
100
.
0
)
*
(
max
-
min
)
+
min
)
+
0
.
5
;
if
(
volume_alsaSet
>=
0
&&
level
==
test
)
{
vol
=
volume_alsaSet
;
}
else
vol
=
100
.
0
*
(((
float
)(
level
-
min
))
/
(
max
-
min
));
vol
+=
change
;
}
else
vol
=
change
;
volume_alsaSet
=
vol
+
0
.
5
;
volume_alsaSet
=
volume_alsaSet
>
100
?
100
:
(
volume_alsaSet
<
0
?
0
:
volume_alsaSet
);
level
=
(
long
)(((
vol
/
100
.
0
)
*
(
max
-
min
)
+
min
)
+
0
.
5
);
level
=
level
>
max
?
max
:
level
;
level
=
level
<
min
?
min
:
level
;
if
((
err
=
snd_mixer_selem_set_playback_volume_all
(
volume_alsaElem
,
level
))
<
0
)
{
g_warning
(
"problems setting alsa volume: %s"
,
snd_strerror
(
err
));
closeAlsaMixer
();
return
-
1
;
}
return
0
;
}
#endif
static
int
prepMixer
(
const
char
*
device
)
{
switch
(
volume_mixerType
)
{
#ifdef HAVE_ALSA
case
VOLUME_MIXER_TYPE_ALSA
:
return
prepAlsaMixer
(
device
);
#endif
#ifdef HAVE_OSS
case
VOLUME_MIXER_TYPE_OSS
:
return
prepOssMixer
(
device
);
#endif
}
return
0
;
}
void
finishVolume
(
void
)
static
int
hardware_volume_get
(
void
)
{
switch
(
volume_mixerType
)
{
#ifdef HAVE_ALSA
case
VOLUME_MIXER_TYPE_ALSA
:
closeAlsaMixer
();
break
;
#endif
#ifdef HAVE_OSS
case
VOLUME_MIXER_TYPE_OSS
:
closeOssMixer
();
break
;
#endif
}
}
int
device
,
count
;
int
volume
,
volume_total
,
volume_ok
;
void
initVolume
(
void
)
{
ConfigParam
*
param
=
getConfigParam
(
CONF_MIXER_TYPE
);
volume_total
=
0
;
volume_ok
=
0
;
if
(
param
)
{
if
(
0
)
;
#ifdef HAVE_ALSA
else
if
(
strcmp
(
param
->
value
,
VOLUME_MIXER_ALSA
)
==
0
)
{
volume_
mixerType
=
VOLUME_MIXER_TYPE_ALSA
;
volume_
mixerDevice
=
VOLUME_MIXER_ALSA_DEFAULT
;
count
=
audio_output_count
();
for
(
device
=
0
;
device
<
count
;
device
++
)
{
if
(
mixer_control_getvol
(
device
,
&
volume
))
{
g_debug
(
"device %d: volume: %d
\n
"
,
device
,
volume
);
volume_
total
+=
volume
;
volume_
ok
++
;
}
#endif
#ifdef HAVE_OSS
else
if
(
strcmp
(
param
->
value
,
VOLUME_MIXER_OSS
)
==
0
)
{
volume_mixerType
=
VOLUME_MIXER_TYPE_OSS
;
volume_mixerDevice
=
VOLUME_MIXER_OSS_DEFAULT
;
}
#endif
else
if
(
strcmp
(
param
->
value
,
VOLUME_MIXER_SOFTWARE
)
==
0
)
{
volume_mixerType
=
VOLUME_MIXER_TYPE_SOFTWARE
;
volume_mixerDevice
=
VOLUME_MIXER_SOFTWARE_DEFAULT
;
if
(
volume_ok
>
0
)
{
//return average
return
volume_total
/
volume_ok
;
}
else
{
g_error
(
"unknown mixer type %s at line %i"
,
param
->
value
,
param
->
line
);
}
}
param
=
getConfigParam
(
CONF_MIXER_DEVICE
);
if
(
param
)
{
volume_mixerDevice
=
param
->
value
;
}
}
void
openVolumeDevice
(
void
)
{
if
(
prepMixer
(
volume_mixerDevice
)
<
0
)
{
g_message
(
"using software volume"
);
volume_mixerType
=
VOLUME_MIXER_TYPE_SOFTWARE
;
return
-
1
;
}
}
static
int
getSoftwareVolume
(
void
)
static
int
software_volume_get
(
void
)
{
return
volume_software
S
et
;
return
volume_software
_s
et
;
}
int
getVolumeLevel
(
void
)
int
volume_level_get
(
void
)
{
switch
(
volume_mixerType
)
{
#ifdef HAVE_ALSA
case
VOLUME_MIXER_TYPE_ALSA
:
return
getAlsaVolumeLevel
();
#endif
#ifdef HAVE_OSS
case
VOLUME_MIXER_TYPE_OSS
:
return
getOssVolumeLevel
();
#endif
switch
(
volume_mixer_type
)
{
case
VOLUME_MIXER_TYPE_SOFTWARE
:
return
getSoftwareVolume
();
return
software_volume_get
();
case
VOLUME_MIXER_TYPE_HARDWARE
:
return
hardware_volume_get
();
default:
return
-
1
;
}
return
-
1
;
}
static
int
changeSoftwareVolum
e
(
int
change
,
int
rel
)
static
int
software_volume_chang
e
(
int
change
,
int
rel
)
{
int
new
=
change
;
if
(
rel
)
new
+=
volume_software
S
et
;
new
+=
volume_software
_s
et
;
if
(
new
>
100
)
new
=
100
;
else
if
(
new
<
0
)
new
=
0
;
volume_software
S
et
=
new
;
volume_software
_s
et
=
new
;
/*new = 100.0*(exp(new/50.0)-1)/(M_E*M_E-1)+0.5; */
if
(
new
>=
100
)
...
...
@@ -499,21 +165,26 @@ static int changeSoftwareVolume(int change, int rel)
return
0
;
}
int
changeVolumeLevel
(
int
change
,
int
rel
)
static
int
hardware_volume_change
(
int
change
,
int
rel
)
{
int
device
,
count
;
count
=
audio_output_count
();
for
(
device
=
0
;
device
<
count
;
device
++
)
{
mixer_control_setvol
(
device
,
change
,
rel
);
}
return
0
;
}
int
volume_level_change
(
int
change
,
int
rel
)
{
idle_add
(
IDLE_MIXER
);
switch
(
volume_mixerType
)
{
#ifdef HAVE_ALSA
case
VOLUME_MIXER_TYPE_ALSA
:
return
changeAlsaVolumeLevel
(
change
,
rel
);
#endif
#ifdef HAVE_OSS
case
VOLUME_MIXER_TYPE_OSS
:
return
changeOssVolumeLevel
(
change
,
rel
);
#endif
switch
(
volume_mixer_type
)
{
case
VOLUME_MIXER_TYPE_HARDWARE
:
return
hardware_volume_change
(
change
,
rel
);
case
VOLUME_MIXER_TYPE_SOFTWARE
:
return
changeSoftwareVolum
e
(
change
,
rel
);
return
software_volume_chang
e
(
change
,
rel
);
default:
return
0
;
}
...
...
@@ -525,7 +196,7 @@ void read_sw_volume_state(FILE *fp)
char
*
end
=
NULL
;
long
int
sv
;
if
(
volume_mixer
T
ype
!=
VOLUME_MIXER_TYPE_SOFTWARE
)
if
(
volume_mixer
_t
ype
!=
VOLUME_MIXER_TYPE_SOFTWARE
)
return
;
while
(
fgets
(
buf
,
sizeof
(
buf
),
fp
))
{
if
(
!
g_str_has_prefix
(
buf
,
SW_VOLUME_STATE
))
...
...
@@ -534,16 +205,15 @@ void read_sw_volume_state(FILE *fp)
g_strchomp
(
buf
);
sv
=
strtol
(
buf
+
strlen
(
SW_VOLUME_STATE
),
&
end
,
10
);
if
(
G_LIKELY
(
!*
end
))
changeSoftwareVolum
e
(
sv
,
0
);
software_volume_chang
e
(
sv
,
0
);
else
g_warning
(
"Can't parse software volume: %s"
,
buf
);
g_warning
(
"Can't parse software volume: %s
\n
"
,
buf
);
return
;
}
}
void
save_sw_volume_state
(
FILE
*
fp
)
{
if
(
volume_mixer
T
ype
==
VOLUME_MIXER_TYPE_SOFTWARE
)
fprintf
(
fp
,
SW_VOLUME_STATE
"%d
\n
"
,
volume_software
S
et
);
if
(
volume_mixer
_t
ype
==
VOLUME_MIXER_TYPE_SOFTWARE
)
fprintf
(
fp
,
SW_VOLUME_STATE
"%d
\n
"
,
volume_software
_s
et
);
}
src/volume.h
View file @
9a70c4d0
...
...
@@ -24,16 +24,15 @@
#define VOLUME_MIXER_OSS "oss"
#define VOLUME_MIXER_ALSA "alsa"
#define VOLUME_MIXER_SOFTWARE "software"
#define VOLUME_MIXER_HARDWARE "hardware"
void
initVolume
(
void
);
void
volume_init
(
void
);
void
openVolumeDevice
(
void
);
void
volume_finish
(
void
);
void
finishVolume
(
void
);
int
volume_level_get
(
void
);
int
getVolumeLevel
(
void
);
int
changeVolumeLevel
(
int
change
,
int
rel
);
int
volume_level_change
(
int
change
,
int
rel
);
void
read_sw_volume_state
(
FILE
*
fp
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment