package harddrake::sound;
# lists filled with Danny Tholen help, enhanced by Thierry Vignaud
#
# No ALSA for OSS's 
#    o tv cards: btaudio,
#    o isa cards: msnd_pinnacle, pas2, 
# No OSS for ALSA's
#    o pci cards: snd-ali5451, snd-als4000, snd-es968, snd-fm801,
#      snd-hdsp, snd-via8233
#    o isa cards: snd-als100, snd-azt2320, snd-cmi8330, snd-cs4231,
#      snd-cs4236, snd-dt0197h, snd-es18xx,snd-es1688, snd-ice1712,
#      snd-korg1212, snd-rme32, snd-rme96
#    o usb cards: snd-usb-audio

# TODO: 
#    o ensure sound isn't user (either dsp/midi/sequencer/mixer)
#    o fix sound/alsa services

use strict;
use common;
use interactive;
use run_program;
use modules;
use standalone;
use list_modules;

my $has_nvaudio = -x '/lib/modules/' . c::kernel_version() . '/';

my %alsa2oss = 
    (
     "snd-ad1816a" => [ "ad1816" ], # isa
     "snd-ad1848"  => [ "ad1848" ], # isa
     "snd-ali5451" => [ "unknown" ],
     "snd-als100"  => [ "unknown" ], # isa
     "snd-als4000" => [ "unknown" ],
     "snd-azt2320" => [ "unknown" ], # isa
     "snd-azt3328" => [ "unknown" ], # isa
     "snd-cmi8330" => [ "unknown" ], # isa
     "snd-cmipci"  => [ "cmpci" ],
     "snd-cs4231"  => [ "unknown" ], # isa
     "snd-cs4232"  => [ "cs4232" ],  # isa
     "snd-cs4236"  => [ "unknown" ], # isa
     "snd-cs4281"  => [ "cs4281" ],
     "snd-cs46xx"  => [ "cs46xx" ],
     "snd-dt0197h" => [ "unknown" ], # isa
     "snd-emu10k1" => [ "audigy", "emu10k1" ],
     "snd-ens1370" => [ "es1370" ],
     "snd-ens1371" => [ "es1371" ],
     "snd-es1688"  => [ "unknown" ], # isa
     "snd-es18xx"  => [ "unknown" ], # isa
     "snd-es1938"  => [ "esssolo1" ],
     "snd-es1968"  => [ "maestro" ], # isa
     "snd-es968"   => [ "unknown" ],
     "snd-fm801"   => [ "unknown" ],
     "snd-gusclassic" => [ "gus" ], # isa
     "snd-gusextreme" => [ "gus" ], # isa
     "snd-gusmax"  => [ "gus" ],    # isa
     "snd-hdsp" => [ "unknown" ],
     "snd-ice1712" => [ "unknown" ], # isa
     "snd-intel8x0" => [ "i810_audio", "nvaudio" ],
     "snd-interwave" => [ "gus" ],  # isa
     "snd-korg1212" => [ "unknown" ], # isa
     "snd-maestro3" => [ "maestro3" ],
     "snd-mpu401"  => [ "mpu401" ],
     "snd-nm256"   => [ "nm256_audio" ],
     "snd-opl3sa2" => [ "opl3", "opl3sa", "opl3sa2" ], # isa
     "snd-opti93x" => [ "mad16" ],
     "snd-rme32"   => [ "unknown" ], # isa
     "snd-rme96"   => [ "unknown" ], # isa
     "snd-rme9652g" => [ "rme96xx" ],
     "snd-sb16"    => ["sscape", "sb"],
     "snd-sb8"     => [ "sb" ],
     "snd-sbawe"   => [ "awe_wave" ],
     "snd-sgalaxy" => [ "sgalaxy" ], # isa
     "snd-sonicvibes" => [ "sonicvibes" ],
     "snd-sscape" => [ "unknown" ], # isa
     "snd-trident" => [ "trident" ],
     "snd-usb-audio" => [ "unknown" ], # usb
     "snd-via686"  => [ "via82cxxx_audio" ],
     "snd-via8233" => [ "unknown" ],
     "snd-wavefront" => [ "wavefront" ], # isa
     "snd-ymfpci"  => [ "ymfpci" ]
     );


my %oss2alsa = 
    (
     "ad1816"  => [ "snd-ad1816a" ],
     "ad1848"  => [ "snd-ad1848" ],
     "audigy"  => [ "snd-emu10k1" ],
     "awe_wave" => [ "snd-sbawe" ],
     "btaudio" => [ "unknown" ],
     "cmpci"   => [ "snd-cmipci" ],
     "cs4232"  => [ "snd-cs4232" ],
     "cs4281"  => [ "snd-cs4281" ],
     "cs46xx"  => [ "snd-cs46xx" ],
     "emu10k1" => [ "snd-emu10k1" ],
     "es1370"  => [ "snd-ens1370" ],
     "es1371"  => [ "snd-ens1371" ],
     "esssolo1" => [ "snd-es1938" ],
     "gus"     => ["snd-interwave", "snd-gusclassic", "snd-gusmax", "snd-gusextreme"],
     "i810_audio" => [ "snd-intel8x0" ],
     "mad16"   => [ "snd-opti93x" ],
     "maestro" => [ "snd-es1968" ],
     "maestro3" => [ "snd-maestro3" ],
     "mpu401"  => [ "snd-mpu401" ],
     "msnd_pinnacle" => [ "unknown" ],
     "msnd_pinnacle" =>  [ "unknown" ],
     "nm256_audio" => [ "snd-nm256" ],
     "nvaudio" => [ "snd-intel8x0" ],
     "opl3"    => [ "snd-opl3sa2" ],
     "opl3sa"  => [ "snd-opl3sa2" ],
     "opl3sa2" => [ "snd-opl3sa2" ],
     "pas2"    => [ "unknown" ],
     "rme96xx" => [ "snd-rme9652.o.g" ],
     "sb"      => ["snd-sb8", "snd-sb16"],
     "sgalaxy" => [ "snd-sgalaxy" ],
     "sonicvibes" => [ "snd-sonicvibes" ],
     "sscape"  => [ "snd-sb16" ],
     "trident" => [ "snd-trident" ],
     "via82cxxx_audio" => [ "snd-via686" ],
     "wavefront" => [ "snd-wavefront" ],
     "ymfpci"  => [ "snd-ymfpci" ]
     );

my @blacklist = qw(cs46xx cs4281);
my $blacklisted = 0;

sub rooted { run_program::rooted($::prefix, @_) }

sub unload { modules::unload(@_) if $::isStandalone || $blacklisted }

sub load { modules::load(@_) if $::isStandalone || $blacklisted }

sub get_alternative {
    my ($driver) = @_;
    $alsa2oss{$driver} || $oss2alsa{$driver};
}


sub do_switch {
    my ($old_driver, $new_driver) = @_;
    standalone::explanations("removing old $old_driver\n");
    rooted("service sound stop") unless $blacklisted;
    rooted("service alsa stop") if $old_driver =~ /^snd-/ && !$blacklisted;
    unload($old_driver); #    run_program("/sbin/modprobe -r $driver"); # just in case ...
    modules::remove_module($old_driver); # completed by the next add_alias()
    modules::add_alias("sound-slot-$::i", $new_driver);
    modules::write_conf();
    if ($new_driver =~ /^snd-/) {
        rooted("service alsa start") unless $blacklisted;
        rooted("/sbin/chkconfig --add alsa");
        load($new_driver); # service alsa is buggy
    } else { run_program::run("/sbin/chkconfig --del alsa") }
    standalone::explanations("loading new $new_driver\n");
    rooted("/sbin/chkconfig --add sound"); # just in case ...
    rooted("service sound start") unless $blacklisted;
}

sub switch {
    my ($in, $device) = @_;
    my $driver = $device->{current_driver};
    $driver ||= $device->{driver};

    foreach (@blacklist) { $blacklisted = 1 if $driver eq $_ }
    my $alternative = get_alternative($driver);
    if ($alternative) {
        my $new_driver = $alternative->[0];
        if ($new_driver eq 'unknown') {
            $in->ask_warn(N("No alternative driver"),
                          N("There's no known OSS/ALSA alternative driver for your sound card (%s) which currently uses \"%s\"",
                            $device->{description}, $driver));
        } elsif ($in->ask_from(N("Sound configuration"),
                               N("Here you can select an alternative driver (either OSS or ALSA) for your sound card (%s).",
                                 $device->{description}) .
                               N("\n\nYour card currently use the %s\"%s\" driver (default driver for your card is \"%s\")", ($driver =~ /^snd-/ ? "ALSA " : "OSS "), $driver, $device->{driver}),
                               [
                                { label => N("Driver:"), val => \$new_driver, list => $alternative, default => $new_driver, sort =>1, format => sub {
                                    my %des = modules::category2modules_and_description('multimedia/sound');
                                    "$_[0] (" . $des{$_[0]} . ')'
                                    }, allow_empty_list => 1 },
                                {
                                    val => N("Help"), disabled => sub {},
                                    clicked => sub {  
                                        $in->ask_warn(N("Switching between ALSA and OSS help"),
                                                      N("OSS (Open Sound System) was the first sound API. It's an OS independant sound API (it's available on most unices systems) but it's a very basic and limited API.
What's more, OSS drivers all reinvent the wheel.

ALSA (Advanced Linux Sound Architecture) is a modularized architecture which
supports quite a large range of ISA, USB and PCI cards.\n
It also provides a much higher API than OSS.\n
To use alsa, one can either use:
- the old compatibility OSS api
- the new ALSA api that provides many enhanced features but requires using the ALSA library.
"))
                                        }
                                }
                                ]))
        {
            return if $new_driver eq $driver;
            standalone::explanations("switching audio driver from '$driver' to '$new_driver'\n");
            $in->ask_warn(N("Warning"), N("The old \"%s\" driver is blacklisted.\n
It has been reported to oopses the kernel on unloading.\n
The new \"%s\" driver'll only be used on next bootstrap.", $driver, $new_driver)) if $blacklisted;
            my $wait = $in->wait_message(N("Please wait"), N("Please Wait... Applying the configuration"));
            do_switch($driver, $new_driver);
            undef $wait;
        }
    } elsif ($driver eq "unknown") {
        $in->ask_warn(N("No known driver"), 
                      N("There's no known driver for your sound card (%s)",
                        $device->{description}));
    } else {
        $in->ask_warn(N("Unkown driver"), 
                      N("The \"%s\" driver for your sound card is unlisted\n
Please send the output of the \"lspcidrake -v\" command to
<install at mandrakesoft dot com>
with subject: unlisted sound driver \"%s\""),
                      $driver, $driver);
    }
}

sub config {
    my ($in, $device) = @_;
    switch($in, $device);
}

1;