Page 1 of 2 12 LastLast
Results 1 to 10 of 18

Thread: Patch: (Linux) Remove dependence on PulseAudio

  1. #1
    Variable Bitrate
    Join Date
    Jun 2008
    Location
    Seattle, WA
    Posts
    366

    Patch: (Linux) Remove dependence on PulseAudio

    Currently, OM has a dependence on PulseAudio, but only for changing the volume. The audio isn't output through PA, but rather however GStreamer is configured to output sound (which could be ALSA, PA, JACK, etc.). Furthermore, on a standard installation, the PulseAudio volume control is just forwarded to the ALSA mixer anyway.

    On some distros, such as Debian (which is what I run), PulseAudio isn't even installed by default. I don't like having to install PA just for one application, especially when that application doesn't even make use of PA, but only uses it for a volume control (which as I said, just gets forwarded to ALSA anyway).

    The following patch removes OM's dependence on PA, and instead uses the ALSA mixer for adjusting the volume.

    (Sorry for the indenting issues, I think the tab size was set wrong.)

    Thanks!
    -- Kevin

    Code:
    Index: MainWindow.cs
    ===================================================================
    --- MainWindow.cs	(revision 627)
    +++ MainWindow.cs	(working copy)
    @@ -24,52 +24,135 @@
         PowerDevil pd;
     	UDisks disks; 
     	MultimediaKeys.MultimediaKeysService mediaKeys=new MultimediaKeys.MultimediaKeysService();
    -	
    -	void checkVolume (int instance)
    +
    +    void checkAllVolume()
    +    {
    +        Int32 card = -1;
    +        while(ASound.snd_card_next(ref card) == 0)
    +        {
    +            raiseSystemEvent(eFunction.systemVolumeChanged, getVolume(card).ToString(), card.ToString(), "");
    +        }
    +    }
    +
    +	int getVolume (int instance)
     	{
    -        
    -		Process p=new Process();
    -        try
    +        String strDevice = "hw:" + instance; // Could be "default", or hw:X where X is the soundcard number
    +
    +        UIntPtr mixer;
    +        if(ASound.snd_mixer_open(out mixer, 0) != 0)
    +            return -1;
    +        if(ASound.snd_mixer_attach(mixer, strDevice) != 0)
             {
    -            ProcessStartInfo info = new ProcessStartInfo("pacmd", "list-sinks volume");
    -            info.WindowStyle = ProcessWindowStyle.Hidden;
    -            info.UseShellExecute = false;
    -            info.RedirectStandardOutput = true;
    -            p.StartInfo = info;
    -            p.Start();
    -            p.WaitForExit();
    +            ASound.snd_mixer_close(mixer);
    +            return -1;
             }
    -        catch (Exception) { return; }
    -		string response=p.StandardOutput.ReadToEnd();
    -		string[] lines=response.Split(new char[]{'\r','\n','\t'});
    -		int i=0;
    -		string vol="0";
    -		foreach(string line in lines)
    -		{
    -			if (line.StartsWith("volume:"))
    -			{
    -				vol=line.Substring(11,3).Trim();
    -			}
    -			else if(line.StartsWith("muted:"))
    -			{
    -				if (line.Contains("yes"))
    -				{
    -					if (instance!=i)
    -						raiseSystemEvent(eFunction.systemVolumeChanged,"-1",i.ToString(),"");
    -					else
    -						sendIt("3|"+i.ToString()+"|-1");
    -				}
    -				else
    -				{
    -					if (instance!=i)
    -						raiseSystemEvent(eFunction.systemVolumeChanged,vol,i.ToString(),"");
    -					else
    -						sendIt("3|"+i.ToString()+"|"+vol);
    -					i++;
    -				}
    -			}
    -		}
    +        if(ASound.snd_mixer_selem_register(mixer, (UIntPtr)0, (UIntPtr)0) != 0)
    +        {
    +            ASound.snd_mixer_detach(mixer, strDevice);
    +            ASound.snd_mixer_close(mixer);
    +            return -1;
    +        }
    +        if(ASound.snd_mixer_load(mixer) != 0)
    +        {
    +            ASound.snd_mixer_detach(mixer, strDevice);
    +            ASound.snd_mixer_close(mixer);
    +            return -1;
    +        }
    +
    +        UIntPtr mixerelem = ASound.snd_mixer_first_elem(mixer);
    +
    +        while (mixerelem != (UIntPtr)0)
    +        {
    +            String name = ASound.snd_mixer_selem_get_name(mixerelem);
    +            if (name.ToLower().Equals("master"))
    +                break;
    +            mixerelem = ASound.snd_mixer_elem_next(mixerelem);
    +        }
    +
    +        int volumePercent = 0;
    +        if(mixerelem != (UIntPtr)0)
    +        {
    +            Int32 playbackSwitch;
    +            ASound.snd_mixer_selem_get_playback_switch(mixerelem, 0, out playbackSwitch);
    +
    +            bool bMuted = (playbackSwitch == 0);
    +            if(bMuted)
    +            {
    +                volumePercent = -1;
    +            }
    +            else
    +            {
    +                IntPtr min, max;
    +                ASound.snd_mixer_selem_get_playback_volume_range(mixerelem, out min, out max);
    +
    +                IntPtr volume;
    +                ASound.snd_mixer_selem_get_playback_volume(mixerelem, 0, out volume);
    +
    +                volumePercent = (int)volume * 100 / (int)max;
    +            }
    +        }
    +        ASound.snd_mixer_detach(mixer, strDevice);
    +        ASound.snd_mixer_close(mixer);
    +
    +        return volumePercent;
     	}
    +
    +    void setVolume (int instance, int volumePercent)
    +    {
    +        String strDevice = "hw:" + instance; // Could be "default", or hw:X where X is the soundcard number
    +
    +        UIntPtr mixer;
    +        if(ASound.snd_mixer_open(out mixer, 0) != 0)
    +            return;
    +        if(ASound.snd_mixer_attach(mixer, strDevice) != 0)
    +        {
    +            ASound.snd_mixer_close(mixer);
    +            return;
    +        }
    +        if(ASound.snd_mixer_selem_register(mixer, (UIntPtr)0, (UIntPtr)0) != 0)
    +        {
    +            ASound.snd_mixer_detach(mixer, strDevice);
    +            ASound.snd_mixer_close(mixer);
    +            return;
    +        }
    +        if(ASound.snd_mixer_load(mixer) != 0)
    +        {
    +            ASound.snd_mixer_detach(mixer, strDevice);
    +            ASound.snd_mixer_close(mixer);
    +            return;
    +        }
    +
    +        UIntPtr mixerelem = ASound.snd_mixer_first_elem(mixer);
    +
    +        while (mixerelem != (UIntPtr)0)
    +        {
    +            String name = ASound.snd_mixer_selem_get_name(mixerelem);
    +            if (name.ToLower().Equals("master"))
    +                break;
    +            mixerelem = ASound.snd_mixer_elem_next(mixerelem);
    +        }
    +
    +        if(mixerelem != (UIntPtr)0)
    +        {
    +            if(volumePercent < 0)
    +            {
    +                ASound.snd_mixer_selem_set_playback_switch_all(mixerelem, 0);
    +            }
    +            else
    +            {
    +                ASound.snd_mixer_selem_set_playback_switch_all(mixerelem, 1);
    +
    +                IntPtr min, max;
    +                ASound.snd_mixer_selem_get_playback_volume_range(mixerelem, out min, out max);
    +
    +                IntPtr volume = (IntPtr)((int)max * volumePercent / 100);
    +                ASound.snd_mixer_selem_set_playback_volume_all(mixerelem, volume);
    +            }
    +        }
    +        ASound.snd_mixer_detach(mixer, strDevice);
    +        ASound.snd_mixer_close(mixer);
    +    }
    +
         static string DM;
     	public MainWindow () : base(Gtk.WindowType.Toplevel)
     	{
    @@ -111,7 +194,7 @@
     		disks.DeviceAdded+=added;
     		disks.DeviceChanged+=changed;
             disks.DeviceRemoved+=remove;
    -		checkVolume(-1);
    +        checkAllVolume();
             if (DM == "gnome")
             {
                 mediaKeys.keyPressed += new MultimediaKeys.MultimediaKeysService.MediaPlayerKeyPressedHandler(handleKey);
    @@ -264,16 +347,21 @@
                 switch (parts[0])
                 {
     				case "-1":
    -			            Thread.Sleep(250);
    -					    checkVolume(-1);
    +                        Thread.Sleep(250);
    +			            checkAllVolume();
     					break;
                     case "3": //GetData - System Volume
    -					int ret;
    -                    if (int.TryParse(arg1,out ret))
    -					{
    -                        if(ret>=0)
    -							checkVolume(ret);
    -					}
    +                    int instance;
    +                    if (int.TryParse(arg1,out instance) && instance >= 0)
    +                    {
    +                        try
    +                        {
    +                            sendIt("3|" + arg1 + "|" + getVolume(instance));
    +                        }
    +                        catch (Exception)
    +                        {
    +                        }
    +                    }
                         break;
     				case "32": //Plugins Loaded
     					foreach(ObjectPath path in disks.EnumerateDevices())
    @@ -303,24 +391,7 @@
                         if (int.TryParse(arg2,out val))
     						if (int.TryParse(arg1,out val))
     						{
    -							Process p=new Process();
    -							ProcessStartInfo info;
    -							if (val==-1)
    -								info=new ProcessStartInfo("pacmd","set-sink-mute "+arg2+" true");
    -							else
    -								info=new ProcessStartInfo("pacmd","set-sink-mute "+arg2+" false");
    -							info.WindowStyle=ProcessWindowStyle.Hidden;
    -							Process q=new Process();
    -							q.StartInfo=info;
    -							q.Start();
    -							if (val==-2)
    -								checkVolume(-1);
    -							if(val<0)
    -								return;
    -							info=new ProcessStartInfo("pacmd","set-sink-volume "+arg2+" "+((int)(val*655.35)).ToString());
    -							info.WindowStyle=ProcessWindowStyle.Hidden;
    -							p.StartInfo=info;
    -							p.Start();
    +                            setVolume(int.Parse(arg2), val);
     						}
                         break;
                     case "35": //Eject Disc
    Index: OMLinHal.csproj
    ===================================================================
    --- OMLinHal.csproj	(revision 627)
    +++ OMLinHal.csproj	(working copy)
    @@ -62,6 +62,7 @@
         <Compile Include="UDiscs.cs" />
         <Compile Include="Props.cs" />
         <Compile Include="MediaKeys.cs" />
    +    <Compile Include="ASound.cs" />
       </ItemGroup>
       <ItemGroup>
         <ProjectReference Include="..\..\FrontEnd\OpenMobile.Framework\OpenMobile.Framework.csproj">
    Index: ASound.cs
    ===================================================================
    --- ASound.cs	(revision 0)
    +++ ASound.cs	(revision 0)
    @@ -0,0 +1,56 @@
    +using System;
    +using System.Runtime.InteropServices;
    +
    +public class ASound
    +{
    +    [DllImport("libasound.so", CallingConvention = CallingConvention.Cdecl)]
    +    public static extern Int32 snd_card_next(ref Int32 card);
    +
    +    [DllImport("libasound.so", CallingConvention = CallingConvention.Cdecl)]
    +    public static extern Int32 snd_mixer_open(out UIntPtr mixer, UInt32 mode);
    +
    +    [DllImport("libasound.so", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
    +    public static extern Int32 snd_mixer_attach(UIntPtr mixer, String name);
    +
    +    [DllImport("libasound.so", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
    +    public static extern Int32 snd_mixer_detach(UIntPtr mixer, String name);
    +
    +    [DllImport("libasound.so", CallingConvention = CallingConvention.Cdecl)]
    +    public static extern Int32 snd_mixer_close(UIntPtr mixer);
    +
    +    [DllImport("libasound.so", CallingConvention = CallingConvention.Cdecl)]
    +    public static extern Int32 snd_mixer_selem_register(UIntPtr mixer, UIntPtr options, UIntPtr classp);
    +
    +    [DllImport("libasound.so", CallingConvention = CallingConvention.Cdecl)]
    +    public static extern Int32 snd_mixer_load(UIntPtr mixer);
    +
    +    [DllImport("libasound.so", CallingConvention = CallingConvention.Cdecl)]
    +    public static extern UIntPtr snd_mixer_first_elem(UIntPtr mixer);
    +
    +    [DllImport("libasound.so", CallingConvention = CallingConvention.Cdecl)]
    +    public static extern UIntPtr snd_mixer_elem_next(UIntPtr elem);
    +
    +    [DllImport("libasound.so", CallingConvention = CallingConvention.Cdecl)]
    +    public static extern Int32 snd_mixer_selem_get_playback_volume_range(UIntPtr elem, out IntPtr min, out IntPtr max);
    +
    +    [DllImport("libasound.so", CallingConvention = CallingConvention.Cdecl)]
    +    public static extern Int32 snd_mixer_selem_set_playback_volume_all(UIntPtr mixer, IntPtr newValue);
    +
    +    [DllImport("libasound.so", CallingConvention = CallingConvention.Cdecl)]
    +    public static extern Int32 snd_mixer_selem_get_playback_volume(UIntPtr mixer, Int32 channel, out IntPtr val);
    +
    +    [DllImport("libasound.so", CallingConvention = CallingConvention.Cdecl)]
    +    public static extern Int32 snd_mixer_selem_set_playback_switch_all(UIntPtr mixer, Int32 newValue);
    +
    +    [DllImport("libasound.so", CallingConvention = CallingConvention.Cdecl)]
    +    public static extern Int32 snd_mixer_selem_get_playback_switch(UIntPtr mixer, Int32 channel, out Int32 val);
    +
    +    public static String snd_mixer_selem_get_name(UIntPtr elem)
    +    {
    +        IntPtr ret = _snd_mixer_selem_get_name(elem);
    +        return Marshal.PtrToStringAnsi(ret);
    +    }
    +
    +    [DllImport("libasound.so", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint="snd_mixer_selem_get_name")]
    +    private static extern IntPtr _snd_mixer_selem_get_name(UIntPtr elem);
    +}

  2. #2
    Variable Bitrate heezer7's Avatar
    Join Date
    May 2004
    Location
    IL, USA
    Posts
    284
    Removing pulse requirement sounds good to me. Even after all these years and all the hype, I have yet to have a time where PA has made things better vs worse.

  3. #3
    Variable Bitrate
    Join Date
    Jun 2008
    Location
    Seattle, WA
    Posts
    366
    I agree, I don't like PA. JACK (http://jackaudio.org/), on the other hand, would be incredibly useful to OM. I'm already routing all my audio through JACK, and using JackRack to host a few LADSPA plugins for doing audio processing (active crossover, and time alignment). Also, with Jack's ability to route audio from/to any input/output, including routing the output of one program to the input of another program, that would be a good way to implement the AudioRouter for Linux.

  4. #4
    Variable Bitrate heezer7's Avatar
    Join Date
    May 2004
    Location
    IL, USA
    Posts
    284
    Sounds awesome. I am a heavy linux user, but not up on programming under it to make use of linux specific items. An AudioRouter equivalent would be awesome.

    Sounds like you may be the guy I need to talk eventually about active under linux. VSTHost is about the only thing that would be stopping me from moving to linux some day. Can't say I have looked into the linux equivalents at all but have a 4 way active setup means I need it.

  5. #5
    Variable Bitrate
    Join Date
    Jun 2008
    Location
    Seattle, WA
    Posts
    366
    I was using RR on Windows until a couple months ago. I was using AudioMulch with a few VST plugins, along with Virtual Audio Cable. It's perfectly possible to get the same end result on Linux, using LADSPA plugins (the Linux equivalent of VST plugins). You don't have to use Jack or the JackRack to use LADSPA plugins on Linux, it just makes it easier. You can use LADSPA plugins with straight ALSA if you want (or PulseAudio). You can configure your .asoundrc file to load LADSPA plugins, but all the configuration is via text files, no nice graphical slider controls to adjust the parameters in realtime, which is what I like about JackRack.

  6. #6
    Variable Bitrate heezer7's Avatar
    Join Date
    May 2004
    Location
    IL, USA
    Posts
    284
    Awesome. I'll have to look into it all one of these days. I have used alsa to EQ the speakers on my desktop. Good to know there are options and they work for at least one other person out there. haha

  7. #7
    Variable Bitrate
    Join Date
    Jun 2008
    Location
    Seattle, WA
    Posts
    366
    BTW, I currently go back and forth between using RideRunner under Wine on Linux, and using OM. I also use Garmin Mobile PC under Wine. Both RR and GMPC work fine under Wine. I still use RR sometimes because OM isn't quite ready yet (but I'm doing my part to make it ready!)

  8. #8
    Variable Bitrate heezer7's Avatar
    Join Date
    May 2004
    Location
    IL, USA
    Posts
    284
    Personally not too worried about GPS here. I'll take my phone over the car apps the very rare times i need it. Nice having another linux nut around. I run it on my desktop, mythtv network, router, etc just haven't got around to helping OM make these last few jumps. So glad to see you are charging forward.

  9. #9
    Variable Bitrate
    Join Date
    Jun 2008
    Location
    Seattle, WA
    Posts
    366
    Hey, another MythTV nut! Cool!

  10. #10
    Variable Bitrate heezer7's Avatar
    Join Date
    May 2004
    Location
    IL, USA
    Posts
    284
    2 OTA, 1 HDPVR - Dish Network, 3 PXE Booting clients. How would we live without auto commercial skip?!?!?

Page 1 of 2 12 LastLast

Similar Threads

  1. pulseaudio defaults to mute at startup
    By govee in forum LinuxICE
    Replies: 5
    Last Post: 01-04-2010, 10:31 PM
  2. LSX 3.3 - commands language dependence?
    By efun in forum RR Skins
    Replies: 4
    Last Post: 01-02-2009, 03:03 AM
  3. V1.9.1 patch
    By coyote in forum MediaCar
    Replies: 8
    Last Post: 02-23-2007, 04:12 PM
  4. Patch: Linux 2.6.11.6 on Epia
    By rubicon in forum Linux
    Replies: 0
    Last Post: 04-06-2005, 10:25 PM
  5. Patch 1.9.1a
    By coyote in forum MediaCar
    Replies: 2
    Last Post: 03-09-2004, 12:19 PM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •