Initial release.

This commit is contained in:
Kevin Baensch 2020-07-01 15:59:31 +02:00
parent 699b3a0760
commit 72bd841f05
Signed by: derped
GPG key ID: C0F1D326C7626543
8 changed files with 335 additions and 0 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
result result
*.qcow2

55
README.md Normal file
View file

@ -0,0 +1,55 @@
NixOS-speak
===
## Aims
NixOS as of now is [not accessible to blind people](https://github.com/NixOS/nixpkgs/issues/30760), this projects aim is to mend this issue.
## Getting Started
### Getting the installation image
As of now an existing installation of Nix is needed (see [Installing a Binary Distribution](https://nixos.org/nix/manual/#ch-installing-binary)).
If there are enough people interested I may end up providing pre-built images.
After installing nix just clone this repo and run
```nix
nix-build release.nix -A image.<target>
```
The currently available targets are:
- minimal
- mate
### Integrate this module into your existing NixOS configuration
Installing the speak submodule is as simple as adding:
```nix
{ config, ... }:
{
imports = [
(fetchTarball git.ophanim.de/derped/NixOS-Speak/archive/master.tar.gz)
];
config.speak = {
enable = true;
config.speakup = {
synth = "soft";
key_echo = "0";
punc_level = "0";
reading_punc = "0";
soft = {
rate = "7";
vol = "0";
};
};
};
}
```
to your configuration.
## Status/Progress
Current Feature Progress (more will be added later):
- TTY
- ✓ espeak
- ✓ espeakup
- Desktop
- ❌ orca
- ❌ speechd

7
default.nix Normal file
View file

@ -0,0 +1,7 @@
{ ... }:
{
imports = [
./options/espeak.nix
];
}

17
extra/exampleConfig.nix Normal file
View file

@ -0,0 +1,17 @@
{ config, ... }:
{
imports = [ ./.. ];
config.speak = {
enable = true;
# runAsRoot = false;
config.speakup = {
soft = {
direct = "1";
rate = "7";
};
};
};
config.sound.enable = true;
}

54
extra/mate.nix Normal file
View file

@ -0,0 +1,54 @@
{ config, lib, pkgs, ... }:
with lib;
let
addToXDGDirs = p: ''
if [ -d "${p}/share/gsettings-schemas/${p.name}" ]; then
export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}${p}/share/gsettings-schemas/${p.name}
fi
if [ -d "${p}/lib/girepository-1.0" ]; then
export GI_TYPELIB_PATH=$GI_TYPELIB_PATH''${GI_TYPELIB_PATH:+:}${p}/lib/girepository-1.0
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH''${LD_LIBRARY_PATH:+:}${p}/lib
fi
'';
in {
environment.systemPackages = with pkgs; [
orca
glib.bin
];
services.gnome3.at-spi2-core.enable = true;
services.xserver = {
desktopManager.mate.enable = true;
displayManager = {
gdm = {
enable = true;
autoSuspend = false;
autoLogin = {
enable = true;
user = "nixos";
};
};
sessionCommands = ''
if test "$XDG_CURRENT_DESKTOP" = "MATE"; then
export XDG_MENU_PREFIX=mate-
# Let caja find extensions
export CAJA_EXTENSION_DIRS=$CAJA_EXTENSION_DIRS''${CAJA_EXTENSION_DIRS:+:}${config.system.path}/lib/caja/extensions-2.0
# Let caja extensions find gsettings schemas
${concatMapStrings (p: ''
if [ -d "${p}/lib/caja/extensions-2.0" ]; then
${addToXDGDirs p}
fi
'') config.environment.systemPackages}
# Add mate-control-center paths to some XDG variables because its schemas are needed by mate-settings-daemon, and mate-settings-daemon is a dependency for mate-control-center (that is, they are mutually recursive)
${addToXDGDirs pkgs.mate.mate-control-center}
# Auto start orca screen-reader
GSETTINGS_BACKEND=dconf ${pkgs.glib.bin}/bin/gsettings set org.gnome.desktop.a11y.applications screen-reader-enabled true
GSETTINGS_BACKEND=dconf ${pkgs.glib.bin}/bin/gsettings set org.mate.interface accessibility true
GSETTINGS_BACKEND=dconf ${pkgs.glib.bin}/bin/gsettings set org.mate.applications-at-visual startup true
export GTK_MODULES=gail:atk-bridge
fi
'';
};
};
}

116
options/espeak.nix Normal file
View file

@ -0,0 +1,116 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config;
speak = cfg.speak;
in rec {
options.speak = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Enable NixOS speak module.
'';
};
installPackages = mkOption {
type = types.bool;
default = true;
description = ''
Add spech related packages to environment.
'';
};
user = mkOption {
type = types.str;
default = "root";
description = ''
User which runs services like espeakup and speech-dispatcher.
User needs to be in audio group.
'';
};
config = {
speakup = mkOption {
type = types.attrs;
default = {};
example = ''
{
synth = "soft";
punc_level = "0";
reading_punc = "0";
soft = {
rate = "6";
};
}
'';
};
};
};
config = mkIf speak.enable rec {
boot.kernelModules = [ "speakup_soft" ];
nixpkgs.config.packageOverrides = {
espeakup = pkgs.callPackage ../pkgs/espeakup.nix {};
};
# needed for orca
services.gnome3.at-spi2-core.enable = mkDefault (cfg.services.xserver.enable);
# allow users in the audio group to use and configure speakup_soft
services.udev.extraRules = ''
KERNEL=="synth", SUBSYSTEM=="misc", GROUP="audio", MODE="0660"
KERNEL=="softsynth", SUBSYSTEM=="misc", GROUP="audio", MODE="0660"
KERNEL=="softsynthu", SUBSYSTEM=="misc", GROUP="audio", MODE="0660"
'';
# See https://aur.archlinux.org/cgit/aur.git/tree/espeakup.service?h=espeakup-git
systemd.services = {
speakup-configure = let
# This whole thing still feels a little bit awkward
pathList = collect (v: isList v) (mapAttrsRecursive (p: v: p) speak.config.speakup);
mkCommand = p: v: "echo ${v} > /sys/accessibility/speakup/${p}";
commandList = (map (l: (mkCommand (concatStringsSep "/" l) (attrByPath l "0" speak.config.speakup))) pathList);
in {
enable = true;
description = "configure speakup.";
wantedBy = [ "default.target" ];
wants = [ "systemd-udev-settle.service" ];
after = [ "systemd-udev-settle.service" "sound.target" ];
script = (concatStringsSep "\n" commandList);
serviceConfig.Type = "oneshot";
};
espeakup = {
enable = (speak.user == "root");
description = "Software speech output system wide settings.";
wantedBy = [ "default.target" ];
wants = [ "systemd-udev-settle.service" ];
after = [ "systemd-udev-settle.service" "sound.target" ];
serviceConfig = {
Type = "forking";
ExecStart = "${pkgs.espeakup}/bin/espeakup";
ExecStop = "${pkgs.utillinux.bin}/bin/kill -HUP $MAINPID";
Restart= "always";
};
};
};
systemd.user.services.espeakup = {
enable = (speak.user != "root");
description = "Software speech output system wide settings.";
wantedBy = [ "default.target" ];
wants = [ "systemd-udev-settle.service" ];
after = [ "systemd-udev-settle.service" "sound.target" ];
serviceConfig = {
Type = "forking";
ExecStart = "${pkgs.espeakup}/bin/espeakup";
ExecStop = "${pkgs.utillinux.bin}/bin/kill -HUP $MAINPID";
Restart= "always";
};
};
environment.systemPackages = optionals speak.installPackages (with pkgs; [
(lowPrio espeak-classic) espeak-ng
espeakup
]);
};
}

26
pkgs/espeakup.nix Normal file
View file

@ -0,0 +1,26 @@
{ stdenv, fetchFromGitHub
, espeak-classic }:
stdenv.mkDerivation rec {
name = "espeakup";
version = "0.80.${rev}";
rev = "e69d61b2d88d8dc679558dea03c48130127102ac";
buildInputs = [ espeak-classic ];
src = fetchFromGitHub {
owner = "williamh";
repo = name;
inherit rev;
sha256 = "0zs5asvxavbibpi98pnhl9y2yc701nxf7h17xm6a1q3liippvix1";
};
patchPhase = ''
substituteInPlace Makefile --replace "/usr/local" $out
'';
meta = with stdenv.lib; {
description = "espeakup is a program which makes it possible for speakup to use the espeak software synthesizer.";
homepage = "https://github.com/williamh/espeakup";
platforms = platforms.linux;
};
}

59
release.nix Normal file
View file

@ -0,0 +1,59 @@
# This file is heavily inspired by <nixpkgs/nixos/release.nix>
{ nixpkgs ? <nixpkgs> # builtins.fetchTarball https://github.com/NixOS/nixpkgs-channels/archive/nixos-20.03.tar.gz
, targetSystem ? builtins.currentSystem
, speak ? ./. #builtins.fetchGit ./.
, configuration ? ./extra/exampleConfig.nix #{ imports = [ (speak + builtins.toPath "/options/espeak.nix") ]; config.speak.enable = true; config.sound.enable = true; }
}:
with builtins;
with import (nixpkgs + (toPath "/lib"));
let
pkgs = import nixpkgs { system = targetSystem; };
tarball = pkgs.releaseTools.sourceTarball {
name = "speak-tarball";
src = speak;
};
modulePath = (nixpkgs + (toPath "/nixos/modules"));
makeTarget = target:
with import nixpkgs { system = targetSystem; };
((import (nixpkgs + (toPath "/nixos/lib/eval-config.nix")) {
system = targetSystem;
modules = target.modules ++ [ configuration ];
}).config.system.build);
makeSubTargets = target: {
isoImage = hydraJob (makeTarget (mergeAttrsConcatenateValues target {
modules = [
{ isoImage.isoBaseName = "nixos-${target.name}"; }
];
})).isoImage;
tarball = hydraJob (makeTarget (mergeAttrsConcatenateValues target {
modules = [ (modulePath + toPath "/installer/cd-dvd/system-tarball.nix") ];
})).tarball;
vm = (makeTarget (mergeAttrsConcatenateValues target {
modules = [ (modulePath + toPath "/virtualisation/qemu-vm.nix") { config.virtualisation.qemu.options = [ "-soundhw hda" ]; } ];
})).vm;
};
targets = rec {
minimal = {
name = "minimal";
modules = [
(modulePath + (toPath "/installer/cd-dvd/installation-cd-minimal.nix"))
(modulePath + (toPath "/installer/cd-dvd/channel.nix"))
];
};
mate = {
name = "mate";
modules = [
(modulePath + (toPath "/installer/cd-dvd/installation-cd-graphical-base.nix"))
./modules/mate.nix
(modulePath + (toPath "/installer/cd-dvd/channel.nix"))
];
};
};
allTargets = mapAttrs (name: value: (makeSubTargets value)) targets;
in {
inherit tarball;
image = allTargets;
pkgs.espeakup = hydraJob (pkgs.callPackage ./pkgs/espeakup.nix {});
}