Mumble VoIP Support Request

Discussion of the Challenge Quake3 engine

Mumble VoIP Support Request

Postby VoulCaine on Tue Mar 09, 2010 4:59 pm

Mumble is a voice chat application for gaming. It runs on Linux, Mac OS X and Windows. Its server application runs on almost any system and can be easily configured.

It has a very flexible and user-friendly interface, requires less resources. As opposed to other VoIP apps, it offers a brand-new feature named 'Positioning Audio' supporting many modern competetive games like CSS, CoD, etc via multiple plugins.

We've implemented 'Link plugin for Mumble' support into CNQ3 v1.46. So players can experience full voice connection with the gaming process. Mumble has a very flexible configuration of how player should hear his teammates (even for balancing voice server and game server pings). Link plugin is designed for positioning voices of your actual teammates. So if you talk to another guy playing another match, you won't be confused.

This feature is surely not a must-have one. As voice communication is a replacement for \say_team commands, voice positioning replaces team-overplay hud elements. But all these features are questioned by player's use.

I wonder if this feature can be implemented into CNQ3 by official.

Source: http://www.overplay.cc/files/cnq3/mumble_link_source.rar
Client: http://www.overplay.cc/files/cnq3/cnq3-v1.46_mumble.rar

Source code can still contain some issues due to our weak expierence. But the client works well.

mumble_link.h
Code: Select all
/* * *
/* * *
* This code is for link with mumble plugin, and must be embedded in CNQ3.
*
* Assembled by DaTa, with help of CAiNE.
*
* Licensed with GPL v2, see enclosed ./COPYING.txt.
*
* Sources of information:
*    http://mumble.sourceforge.net/HackPositionalAudio
*    http://mumble.sourceforge.net/Link
*    http://svn.icculus.org/quake3/trunk/code/client/libmumblelink.c?view=markup idia of unlinking and more correct points of call link functions
*
* Functional:
*    Just turn on mumble, enable positional plugin, connect to server and join team.
*
* Cvars:
*    mum_enable   - (default 1)         for switch linking on/off.
*    mum_scale   - (default 1.0, cheat)   scale factor for coordinates, must be same for all player.
*    mum_debug   - (default 0)         switch debug info output on/off on Update() event.
*
* Commands:
*    mum_relink   - force relink, mum_enable must be 1.
*       This is the only way for switch-on linking in-game, in case, for example, if client forgot to turn-on mumble.
*    mum_state   - print current link state to client.
*
* Implementation on cnq3 guide:
*    ../client/cl_cgame.cpp
*       After:
*          #include "client.h"
*          #include "../qcommon/vm_local.h"
*          #include "../qcommon/vm_shim.h"
*       add:
*          #include "../mumble_link/mumble_link.h"
*      
*       In the end of function CL_FirstSnapshot() add:
*          mumbleLink.Link();
*    
*    ../client/cl_main.cpp
*       After:
*          #include "client.h"
*       add:
*          #include "../mumble_link/mumble_link.h"
*      In the end of function CL_Init() add:
*          mumbleLink.AddCvars();
*          mumbleLink.AddCommands();
*       In the end of function CL_Frame() add:
*          mumbleLink.Update();
*       
*       In the end of function CL_Disconnect() add:
*          mumbleLink.Unlink();
*       
*    Finally, add ./mumble_link/mumble_link.cpp (dont forget about mumble_link.h) to cnq3 project.
*/

#pragma once

#ifndef MUMBLE_LINK_H
#define MUMBLE_LINK_H

#include <wchar.h>            //wchar_t

#ifdef WIN32
   #include <windows.h>      //UINT32, DWORD, HANDLE
#else
   #include <stdint.h>         //uint32_t
   typedef uint32_t UINT32, DWORD;
#endif

#include "../qcommon/q_shared.h"   //qbool
#include "../qcommon/qcommon.h"      //cvar_t

void Mum_AddCommands();

class MumbleLink
{
   public:
      MumbleLink(): m_linkedMem(0) {}
      
      void AddCvars();
      void AddCommands();
      
      qbool   Link();
      void   Unlink();
      void   Update();
      
      //not need to add this to cnq3 source
      qbool   IsLinked();
      qbool   IsEnabled();
   private:
      struct LinkedMem
      {
         UINT32   uiVersion;
         DWORD   uiTick;
         float   fAvatarPosition[3];
         float   fAvatarFront[3];
         float   fAvatarTop[3];
         wchar_t   name[256];
         float   fCameraPosition[3];
         float   fCameraFront[3];
         float   fCameraTop[3];
         wchar_t   identity[256];
         UINT32   context_len;
         unsigned char context[256];
         wchar_t description[2048];
      }
         *m_linkedMem;
      
   #ifdef WIN32
      HANDLE   m_hMapObject;
   #endif
      
      cvar_t   *m_cvar_mum_enable;
      cvar_t   *m_cvar_mum_scale;
      cvar_t   *m_cvar_mum_debug;
      
      int      m_GetTeam();
      void   m_DisplayDebug();
};

extern MumbleLink mumbleLink;

#endif //MUMBLE_LINK_H
*/


mumble_link.cpp
Code: Select all
//details at:
#include "mumble_link.h"

#include <stdio.h>               //sprintf, snprintf
#include <stdlib.h>               //mbstowcs, atoi
#include <string.h>               //strlen

#include <wchar.h>               //wcsncpy

#ifdef _MSC_VER
   #pragma warning(disable : 4996)   //unsafe wcsncpy, sprintf
#endif

#ifdef WIN32
   #include <windows.h>         //OpenFileMappingW, MapViewOfFile, UnmapViewOfFile, CloseHandle, CloseHandle
#else
   #include <unistd.h>            //getuid
   #include <sys/mman.h>         //shm_open, mmap, munmap
#endif

#include "../qcommon/q_shared.h"   //Com_Printf, AngleVectors, MAX_MODELS, MAX_SOUNDS
#include "../qcommon/qcommon.h"      //BigShort, Cvar_Get, Cmd_AddCommand
#include "../client/client.h"      //cls, clc, cl

/*
Q3Radiant202 manual:
Player Dimensions
Model size: The player model’s actual size is a bounding box 30 units by 30 units square with a height of 56 units.
In the game world, eight units roughly equal one foot (30.5 cm).
From this, we deduce that the characters are a heroic 7 feet tall (2.13 meters).
*/
//#define UNIT_PER_METER   26.229508196721311475409836065574   //Q3Radiant manual
#define UNIT_PER_METER   26.246719160104986876640419947507      //Q3Radiant manual + wiki 0.3048m foot

MumbleLink mumbleLink;

void MumbleLink::AddCvars()
{
   m_cvar_mum_enable   = Cvar_Get("mum_enable",   "1",   CVAR_ARCHIVE);
   m_cvar_mum_scale   = Cvar_Get("mum_scale",      "1.0",   CVAR_CHEAT);//FIXME: remove?, affect all clients
   m_cvar_mum_debug   = Cvar_Get("mum_debug",    "0",   CVAR_TEMP);
}

static void Mum_State();
static void Mum_Relink();
void MumbleLink::AddCommands()
{
   Cmd_AddCommand("mum_relink", Mum_Relink);//cpp conversion at cnq3
   Cmd_AddCommand("mum_state", Mum_State);
}

qbool MumbleLink::Link()
{
   if(  !m_cvar_mum_enable->integer  )
      return qfalse;
   
   if(  m_linkedMem  )
      this->Unlink();
   
#ifdef WIN32
   m_hMapObject = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, L"MumbleLink");
   if(  !m_hMapObject  )
      goto label_failed_to_link;

   m_linkedMem = (LinkedMem *) MapViewOfFile(m_hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(LinkedMem));
   if(  !m_linkedMem  )
   {
      CloseHandle(m_hMapObject);
      m_hMapObject = NULL;
      goto label_failed_to_link;
   }
#else
   char szMemName[256];
   snprintf(szMemName, 256, "/MumbleLink.%d", getuid());
   
   int shmfd = shm_open(szMemName, O_RDWR, S_IRUSR|S_IWUSR);//opens existing descriptor

   if(  shmfd < 0  )
      goto label_failed_to_link;

   m_linkedMem = (LinkedMem *) mmap(0, sizeof(LinkedMem), PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0);

   if(  m_linkedMem == (void *)(-1)  )
   {
      m_linkedMem = 0;
      goto label_failed_to_link;
   }
#endif
   
   m_linkedMem->uiVersion = 2;
   wcsncpy(m_linkedMem->name, L"Challenge Quake3", 256);
   wcsncpy(m_linkedMem->description, L"Challenge Quake3 - modified q3/ioq3 engine for CPMA mod.", 2048);
   
   Com_Printf( S_COLOR_YELLOW "[MUMBLE]" S_COLOR_GREEN " linked" S_COLOR_WHITE ".\n");
   
   return qtrue;
   
label_failed_to_link:
   Com_Printf( S_COLOR_YELLOW "[MUMBLE]" S_COLOR_WHITE "Failed to link(mumble is off). For linking, type" S_COLOR_YELLOW " mum_relink" S_COLOR_WHITE " command.\n");
   return qfalse;
}

void MumbleLink::Unlink()
{
   if(  !m_linkedMem  )
      return;
   
#ifdef WIN32
   UnmapViewOfFile(m_linkedMem);
   CloseHandle(m_hMapObject);
   m_hMapObject = NULL;
#else
   munmap(m_linkedMem, sizeof(LinkedMem));
#endif
   
   m_linkedMem = 0;
   
   Com_Printf( S_COLOR_YELLOW "[MUMBLE]" S_COLOR_RED " unlinked" S_COLOR_WHITE ".\n");
}

void MumbleLink::Update()
{
   if(  !m_linkedMem  )
      return;//unlinked
   
   if(  !m_cvar_mum_enable->integer  )//may be unlinked by cvar
   {
      this->Unlink();
      return;
   }
   
   LinkedMem &lm = *m_linkedMem;
   
   lm.uiTick++;
   
   if(  cls.state != CA_ACTIVE || clc.serverAddress.type != NA_IP || !cl.snap.valid  )//not connected or local or waiting for first snapshot
   {
      lm.fAvatarPosition[0] =
      lm.fAvatarPosition[1] =
      lm.fAvatarPosition[2] = 0.0;
      return;
   }
   
   lm.uiTick++;
   
   // Left handed coordinate system.
   // X positive towards "left".
   // Y positive towards "up".
   // Z positive towards "into screen".
   //
   // 1 unit = 1 meter
   // DaTa: for visual details, look at enclosed ./coords.jpg
   
   lm.fCameraPosition[0] = lm.fAvatarPosition[0] = cl.snap.ps.origin[0]/UNIT_PER_METER * m_cvar_mum_scale->value;
   lm.fCameraPosition[1] = lm.fAvatarPosition[1] = ( cl.snap.ps.origin[2] + cl.snap.ps.viewheight )/UNIT_PER_METER * m_cvar_mum_scale->value;
   lm.fCameraPosition[2] = lm.fAvatarPosition[2] = cl.snap.ps.origin[1]/UNIT_PER_METER * m_cvar_mum_scale->value;
   
   if(  lm.fAvatarPosition[1] == 0.0  )   //TODO: check
      lm.fAvatarPosition[1] = 0.001f;   //prevent disable the link plugin, z axis less lagy
      
   vec3_t forward, up;
   AngleVectors(cl.snap.ps.viewangles, forward, NULL, up);
   
   lm.fCameraFront[0] = lm.fAvatarFront[0] = forward[0];
   lm.fCameraFront[1] = lm.fAvatarFront[1] = forward[2];
   lm.fCameraFront[2] = lm.fAvatarFront[2] = forward[1];
   
   lm.fCameraTop[0] = lm.fAvatarTop[0] = up[0];
   lm.fCameraTop[1] = lm.fAvatarTop[1] = up[2];
   lm.fCameraTop[2] = lm.fAvatarTop[2] = up[1];
   
   // Identifier which uniquely identifies a certain player in a context (e.g. the ingame Name).
   //wprintf(lm.identity, L"%i", clc.clientNum);//3 chars, OH SH- doesnt work @ VC2008
   char szID[10];
   sprintf(szID, "%i", clc.clientNum);               //DaTa: some sort of crap
   mbstowcs(lm.identity, szID, sizeof(lm.identity));
   
   //hate unicode :(
   
   // Context should be equal for players which should be able to hear each other positional and
   // differ for those who shouldn't (e.g. it could contain the server+port and team)
   const netadr_t &sa = clc.serverAddress;
   //HACK: port is in big endian
   sprintf((char *)lm.context, "%i.%i.%i.%i:%hu:%i",
   sa.ip[0], sa.ip[1], sa.ip[2], sa.ip[3],
   BigShort(sa.port),
   m_GetTeam());   //~24 chars < 256;
   lm.context_len = strlen((char *)lm.context);
   
   //DEBUG
   if(  m_cvar_mum_debug->integer  )
      m_DisplayDebug();
}

qbool MumbleLink::IsLinked()
{
   return (qbool) m_linkedMem;
}

qbool MumbleLink::IsEnabled()
{
   return (qbool) m_cvar_mum_enable->integer;
}

#define   CS_MODELS            32
#define   CS_SOUNDS            (CS_MODELS+MAX_MODELS)
#define   CS_PLAYERS            (CS_SOUNDS+MAX_SOUNDS)
int MumbleLink::m_GetTeam()//HACK HACK HACK
{
   const char *pcszClientInfo = cl.gameState.stringData + cl.gameState.stringOffsets[CS_PLAYERS + clc.clientNum];
   return atoi(Info_ValueForKey(pcszClientInfo, "t"));//FIXME: find better way?
}

void MumbleLink::m_DisplayDebug()
{
   char szID[10];      
   wcstombs(szID, m_linkedMem->identity, sizeof(szID));
   
   Com_Printf( S_COLOR_YELLOW "[MUMBLE]" S_COLOR_WHITE " Pos %.3f %.3f %.3f; Fwd ang %.3f %.3f %.3f;\n",
   
   m_linkedMem->fAvatarPosition[0],
   m_linkedMem->fAvatarPosition[1],
   m_linkedMem->fAvatarPosition[2],
   
   m_linkedMem->fAvatarFront[0],
   m_linkedMem->fAvatarFront[1],
   m_linkedMem->fAvatarFront[2]);
   
   Com_Printf( S_COLOR_YELLOW "[MUMBLE]" S_COLOR_WHITE " ID %s; Context %s;\n", szID, (char *)m_linkedMem->context);
}

static void Mum_Relink()
{
   if(  !mumbleLink.IsEnabled()  )
   {
      Com_Printf( S_COLOR_YELLOW "[MUMBLE]" S_COLOR_WHITE " is " S_COLOR_RED "disabled" S_COLOR_WHITE ". To enable turn" S_COLOR_YELLOW " mum_enable" S_COLOR_WHITE " cvar on.\n");
   }
   
   mumbleLink.Link();
}

static void Mum_State()
{
   Com_Printf( S_COLOR_YELLOW "[MUMBLE]" S_COLOR_WHITE " is %s" S_COLOR_WHITE ".\n", mumbleLink.IsLinked() ? S_COLOR_GREEN "linked" : S_COLOR_RED "unlinked" );
}


P.S. This CNQ3 feature is nothing to do with the VoIP in-game functionality designed for ioQ3. It just adds a support for 'Positional Audio' originally designed by Mumble team.
VoulCaine
 
Posts: 15
Joined: Thu Mar 22, 2007 8:19 am

Re: Mumble VoIP Support Request

Postby alien on Mon Mar 15, 2010 12:50 pm

Link don't work.
"I was always convinced that tricks in Defrag movies are simple. Until I tried myself, I realized this was wrong."

| What is Defrag ? | How to install Defrag | Create Account | Maps | Communities |
User avatar
alien
 
Posts: 71
Joined: Thu Apr 19, 2007 9:59 pm
Location: Poland

Re: Mumble VoIP Support Request

Postby VoulCaine on Mon Mar 15, 2010 9:22 pm

Fixed.
VoulCaine
 
Posts: 15
Joined: Thu Mar 22, 2007 8:19 am


Return to Challenge Quake3 Discussion

Who is online

Users browsing this forum: No registered users and 1 guest

cron