15 July 2010

Using Ventrilo Client on Linux with Wine

Categories:  Wine  Linux  IM  Gentoo

How to force Ventrilo client to work well on Linux box using Wine

Linux users do not have many team voice messaging clients to choose from. In fact there is only proprietary TeamSpeak3 which is working nicely. The most popular Ventrilo voice communication application is still not available for Linux. The official Ventrilo page says Linux client is in development (this information is present on their page for about 3 years). I lost hope that they will finally finish working on Linux client. However I found the way to use Ventrilo on my system using Wine free Windows API implementation for *nix systems. I put a lot of work in testing, and I succeed but this wasn't an easy task to achieve. If you have found a better way to run Ventrilo client software on Linux please let me know about it.

Before I will explain how I manage to use Ventrilo along side with other programs on my Linux box I will try to briefly explain what are the requirements to achieve this goal. My solution is not 100% perfect as it will require at least 2 separate sound devices (one for input and one for output). Fortunately I have two sound cards in my system and also additional microphone in my Logitech QuicCam Pro USB Web Camera. My solution also require you to use pure alsa sound system. As a Gentoo Linux user I have never used a pulseaudio sound system, and I have no idea will this solution work with pulseaudio. If you know anything about it please let me know. Now I will try to explain how I forced Vetrilo to work nicely on my Linux. I will explain this in a step by step process, starting from installation and going thought every problem I faced. I must worn you that if you are not a Gentoo Linux based distribution user repeating my solution may be painful as this will require some manual source code patching and source code compilation. For Gentoo Linux user I created ebuilds which will take care of additional patching and compilation.

Ventrilo Instalation on Linux

Before installing Ventrilo on Linux you have to make sure that you will not do it in a standard Wine prefix that is used by other applications (for example games that you want to run along side to Ventrilo). First thing to do will be installing Ventrlio in separate Wine prefix called wine-ventrilo. You can do it by running following command:

WINEPREFIX=~/.wine-ventrilo wine /path_to_downloaded_client/ventrilo-3.0.5-Windows-i386.exe

This will create a new wine prefix and lunch the installer of the program. Install the program, then make sure you will download and placed required GSM audio codec in your new wine-prefix. The codec file is named msgsm32.acm and it can be downloaded from here. Place this file into ~/.wine-ventrilo/drive_c/windows/system catalog. Next edit ~/.wine-ventrilo/drive_c/windows/system.ini and add the following line under the drivers32 section: MSACM.msgsm610=msgsm32.acm. You can additionally install SpeechSDK51.exe if you want to use TTS function by running following command:

WINEPREFIX=~/.wine-ventrilo wine /path_to_downloaded_file/SpeechSDK51.exe

Problem 1 Choosing right sound system

The official WineHQ AppDB Ventrilo program page says that you should choose an ALSA sound system in Emulation mode. I spend hours of testing all possible settings with ALSA and Jack and no matter what configuration I used in winecfg, Jack sound server and Ventrilo I coudn't force any of my input devices to work. I checked microphone attached to first and second sound card and my USB microphone in camera but with ALSA and Jack they were always muted, no input sound at all (output sound was working fine though). So both ALSA and Jack wasn't the right solution for me. However I found out then when I was setting the OSS sound system in winecfg my input devices (all of them) were working fine. So next thing to do is starting winecfg and setting up the OSS sound system. Make sure you will fire up winecfg in your newly created wineprefix by running following command:

WINEPREFIX=~/.wine-ventrilo winecfg

Next choose the OSS sound system in winecfg. For hardware acceleration choose Full. Consult the screenshot below.


Previous installation of Ventrilo in a separate wine prefix will allow us to run it separately from other programs (games). This way for other applications we may still use ALSA or Jack sound system.

Problem 2 Muted PCM sound device with Wine and OSS sound system

Since Wine 1.1.6 there is a known bug which is cosing the PCM sound device to be muted shortly after a program using OSS sound system is started in wine environment. More information about this bug you will find by following this link. This bug is not noticeable to most of the wine users as they are useing ALSA sound system. I already wrote that I couldn't force input devices to work in Ventrilo with ALSA that is why this bug is extremely annoying for me. Every time I started Ventrilo my sound system was totally muted. If you will read information on bug report page you will notice that there is a solution to this bug. This solution requires a user to remove two lines of code that are cosing the bug from wine source code and recompile the wine package. Based on this information I created a patch for wine sources. Below you can see this patch:

View the source of prevent_oss_muting.patch
  1. --- wine/a/wine-1.1.6/dlls/dsound/primary.c 2008-10-10 16:57:22.000000000 +0200
  2. +++ wine/b/wine-1.1.6/dlls/dsound/primary.c 2009-05-18 19:37:01.000000000 +0200
  3. @@ -169,8 +169,6 @@
  4. return err;
  5. }
  6. }
  7. - if (device->hwbuf)
  8. - IDsDriverBuffer_SetVolumePan(device->hwbuf, &device->volpan);
  10. DSOUND_RecalcPrimary(device);
  11. device->prebuf = ds_snd_queue_max;

You can access the patch file on my svn server by following this link.

As I'm a Gentoo Linux user I also updated a wine ebuild to make patching wine easier. Using this ebuild I can install on my system wine that is free of mentioned above bug. I decided to put this ebuild into my private overlay so if you are a user of distribution based on Gentoo Linux you can add my overlay to your system and compile wine using my ebuilds. This will prevent PCM OSS muting. I'm constantly updating ebuilds of wine with every new release and I will be doing this until the bug will be removed or I will find another way to force Ventrilo to work on my Linux. More information how to add my overlay and how to use my wine ebuild you will find by following this link. If you are not using Gentoo Linux based distribution you can patch and compile the wine sources manually. The less painful solution is to remember that every time you fire up Ventrilo you have to open the sound mixer and unmute the PCM sound device.

Problem 3 Making Push to talk button work

Most likely you will use Ventrilo along side with another application for example some kind of game, and you will want to play this game and talk to your friends using Ventrilo push to talk function. This will not work when the Ventrilo window will lost it's focus. As wine is a separate environment from you Linux desktop Wine programs are completely unaware of the fact that you are pressing some keys on your keyboard and mouse, unless the program window has a system focus. There is a simple program which will help you to solve this issue. It will pass A to Ventrilo program window every time you will press some keys on your mouse and keyboard. You can download this program from here and compile it manually. After compiling the program make sure you will run Ventrilo and setup A as push to talk button. Consult the screenshot below.

Ventrilo PTT

Next thing to do is to bind the PTT button to this little helper program. To identify the correct button code we need to run the program passing our input device (mouse or keybord) as first parameter. You can do it by running following command:

ventriloctrl /dev/input/by-id/usb-Logitech_USB_Receiver-event-mouse

As you can see I'm passing my mouse event device. You can easily identify your device when you will go into /dev/input/by-id/ catalog. Then press a desired button and the program will print out it's event code to the screen. Remember this code because we will use it in our Ventrilo luncher script. Next thing is creating a luncher script for Ventrilo and PTT helper applicaton. My script ventrilo.sh is looking like this:

  1. #!/bin/bash
  2. env WINEPREFIX="~/.wine-ventrilo" wine "C:\Program Files\Ventrilo\Ventrilo.exe" &
  3. sleep 30
  4. /usr/bin/ventriloctrl /dev/input/by-id/usb-Logitech_USB_Receiver-event-mouse 274

My script is lunching the Ventrilo program using correct WINEPREFIX then waiting a while and lunching the helper program. Remember the helper program will not work without Ventrilo window registered on the system. I would strongly suggest using clearly named device nodes provided in /dev/input/by-id catalog as core /dev/input/event* nodes may change between boots of the system. They will change if you are plugging additional usb input devices to your system. Make sure you will make this program executable by running following command:

chmod +x /path_to_script/ventrilo.sh

Now I was able to use Ventrilo with PTT while playing the game. This was still not perfect solution I faced one more problem.

Problem 4 Most Ventrilo servers were moving me from active channel to AFK channel

This problem was repeated every time I forgot to use PTT function. Why? For the same reason that PTT is not working without a helper application. If I do not press a PTT button Ventrilo is not reciving any keyboard events and the server is assuming I'm AFK. The helper application is not perfect. It could for example pass every event to Ventrilo window. I solved this by creating a patch to ventriloctrl application. You can see this patch below:

View the source of prevent_oss_muting.patch
  1. --- a/ventriloctrl-0.5/ventriloctrl.c 2008-08-23 10:23:03.000000000 +0200
  2. +++ b/ventriloctrl-0.5/ventriloctrl.c 2009-06-20 01:40:40.000000000 +0200
  3. @@ -16,6 +16,7 @@
  4. /* Configuration */
  5. #define SIMULATEKEY XK_A // Simulate Key Press
  6. #define VENTRILO "Ventrilo" // Ventrilo Window Name
  7. +#define OTHERKEY XK_B //Key send to Ventrillo if other key is being pressed
  9. /* Global Variables */
  10. Display *display;
  11. @@ -54,14 +55,14 @@
  12. {
  13. // Variables
  14. int i;
  15. -
  16. +
  17. // Get the "Window" Tree
  18. Window root;
  19. Window parent;
  20. Window *children = 0;
  21. unsigned int childrenCount = 0;
  22. XQueryTree(display, parentWindow, &root, &parent, &children, &childrenCount);
  23. -
  24. +
  25. // Crawl the "Window" Tree
  26. char *window_name = 0;
  27. Window *window = 0;
  28. @@ -74,7 +75,7 @@
  29. }
  30. XFree(window_name);
  31. }
  32. -
  33. +
  34. // Crawl the Child and Look For "windowName"
  35. window = find_window(display, children[i], windowName);
  36. if (window != 0) {
  37. @@ -82,10 +83,10 @@
  38. return window;
  39. }
  40. }
  41. -
  42. +
  43. // Free the Children! lol
  44. if (children != 0) XFree(children);
  45. -
  46. +
  47. // Return
  48. return 0;
  49. }
  50. @@ -94,42 +95,43 @@
  51. {
  52. // Usage
  53. printf("\n");
  54. -
  55. +
  56. // Initialize "Display"
  57. display = XOpenDisplay(0);
  58. if (display == NULL) {
  59. printf("Error: Could not open display!\n");
  60. return 1;
  61. }
  62. -
  63. +
  64. // Initialize Root "Window"
  65. window = XDefaultRootWindow(display);
  66. if (!window) {
  67. printf("Error: Could not grab root window!\n");
  68. return 2;
  69. }
  70. -
  71. +
  72. // Initialize Ventrilo "Window"
  73. windowVentrilo = find_window(display, window, VENTRILO);
  74. if (!windowVentrilo) {
  75. printf("Error: Could not find Ventrilo window!\n");
  76. return 3;
  77. }
  78. -
  79. +
  80. // Convert Key String to Number
  81. unsigned int key = atoi(argv[2]);
  82. unsigned int simulatekey = XKeysymToKeycode(display, SIMULATEKEY);
  83. -
  84. + unsigned int otherkey = XKeysymToKeycode(display, OTHERKEY);
  85. +
  86. // Open the Input
  87. int device = open(argv[1], O_RDONLY);
  88. -
  89. +
  90. // Loop
  91. struct input_event ev;
  92. XKeyEvent event;
  93. while (ventrilo_still_running()) {
  94. // Read from the Input
  95. read(device, &ev, sizeof(struct input_event));
  96. -
  97. +
  98. // Check Input
  99. if (ev.type == 1 && ev.code == key) {
  100. // Simulate Key Press/Release
  101. @@ -141,8 +143,18 @@
  102. }
  103. XFlush(display);
  104. }
  105. + else if (ev.type == 1 && ev.code != key) {
  106. + // Send other key (this should prevent putting the user on afk status)
  107. + event = create_key_event(display, *windowVentrilo, window, ev.value, otherkey, 0);
  108. + if (ev.value == 1) {
  109. + XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *) &event);
  110. + } else {
  111. + XSendEvent(event.display, event.window, True, KeyReleaseMask, (XEvent *) &event);
  112. + }
  113. + XFlush(display);
  114. + }
  115. }
  116. -
  117. +
  118. // Return
  119. return 0;
  120. }
  121. @@ -156,20 +168,20 @@
  122. printf("then execute the command listed.\n");
  123. printf("Press Ctrl+C when finished.\n");
  124. printf("\n");
  125. -
  126. +
  127. // Open the Input
  128. int device = open(argv[1], O_RDONLY);
  129. -
  130. +
  131. // Loop
  132. struct input_event ev;
  133. while (1) {
  134. // Read from the Input
  135. read(device, &ev, sizeof(struct input_event));
  136. -
  137. +
  138. // Print the Command
  139. if (ev.type == 1 && ev.value == 1) printf("%s %s %i\n", argv[0], argv[1], ev.code);
  140. }
  141. -
  142. +
  143. // Return
  144. return 0;
  145. }
  146. @@ -180,7 +192,7 @@
  147. // Programs
  148. if(argc == 2) return findkey(argc, argv); // Find Key
  149. if(argc == 3) return ventriloctl(argc, argv); // Ventrilo Ctrl
  150. -
  151. +
  152. // Usage
  153. printf("\n");
  154. printf("Usage: %s <device> [key]\n", argv[0]);
  155. @@ -188,7 +200,7 @@
  156. printf("Running this program without 'key' specified\n");
  157. printf("will run the 'FindKey' sub-program.\n");
  158. printf("\n");
  159. -
  160. +
  161. // Return
  162. return 0;
  163. }

You can access the patch file on my svn server by following this link.

This patch is doing a simple thing. Every time the provided as parameter event device is generating an event the program is passing this to Ventrilo window as keyboard letter B. The patch doesn't change the default program behavior so the PTT function will still work with A button. This way as long as I'm using my mouse ventriloctrl will be passing B key to Ventrilo window and server will not assume I'm AFK. I created an Gentoo Linux ebuld which is installing ventriloctrl application with provided above patch in my system. My ebuild is available in my private overlay so if you are a user of distribution based on Gentoo Linux you can add my overlay to your system and compile ventriloctrl using my ebuilds. If you are not a Gentoo Linux user you can patch and compile the ventriloctrl sources manually.

Setting up and running Ventrilo on Linux

To make sure every thing will be working nicely remember to always start the Ventrilo using luncher script provided above. Make also sure that you will lunch Ventrilo before any other wine application. OSS sound system (even it's ALSA emulation) will need an exclusive access to input sound device. When some other program will be using it it may not work. I'm not having any problems as I use my main Sound Blaster Audigy 4 as output device in Ventrilo with OSS and for other Wine applications with ALSA. For input device I use my USB camera microphone and this solution is working perfectly for me. I tested this many times, and I had no problems with talking to people.

When you will want to setup the sound device in Ventrilo you may not notice it's names on the list, but don't worry you should be able to select them as blank entries. As I know that my camera mic is device number 3 in my system I just select the last blank entry on the list. Remember first entry is default device. Here you can see a prove that this is working for me. Take a look at the monitor part of the window. Positive values are proving that an input sound is working.

Ventrilo Input



If you have found something wrong with the information provided above or maybe you just want to speak your mind about it, feel free to leave a comment.
All comments will show up on page after being approved. Sorry for such policy but I want to make sure that my site will be free of abusive or vulgar content. I don't mind being criticized just do it using right words.

Leave a comment