Difference between revisions of "Voice"

From Second Life Wiki
Jump to navigation Jump to search
(→‎Logging: anchor links for actions and events)
Line 256: Line 256:


====Actions====
====Actions====
These are the Vivox SDK commands used by the SecondLife viewer.
These are examples of the Vivox SDK commands used by the SecondLife viewer.





Revision as of 18:47, 13 September 2007

Voice is a feature that made its debut on its own grid and beta viewer in March of 2007[1].

Frequently Asked Questions

There's an exhaustive Voice FAQ which provides answers to many questions about the new voice feature.

Groups

The Voice Mentors group and Voice in SL: A Community Forum are advocacy and help groups for users having problems adjusting to the new system.

Settings

You can set your preferences directly in your Documents and Settings\<user>\Application Data\SecondLife\user_settings\settings.xml file, or you can set them from the viewer.

Some settings can be made through the UI panels, but all can be set from the Client menu.

If you haven't already done so, you enable the Client menu using Ctrl-Alt-D (not to be confused with Ctrl-Alt-Delete). Then select

Client -> Debug Settings

to get the Debug Settings window. In the selection box, hit the triangle to bring up the list of debug variables and select the setting that you wish to change.

Here is a list of settings relating to Voice chat together with their default values and descriptions.


AudioLevelMic
1.0
Audio level of microphone input
AudioLevelVoice
1.0
Audio level of voice chat
EnablePushToTalk
TRUE
Must hold down a key or moouse button when talking into your microphone
EnableVoiceChat
FALSE
Enable talking to other residents with a microphone
FloaterActiveSpeakersRect
0 300 250 0
Rectangle for active speakers window
OverdrivenColor
1.0 0.0 0.0 1.0
Color of various indicators when resident is speaking too loud.
PushToTalkButton
MiddleMouse
Which button or keyboard key is used for push-to-talk
PushToTalkToggle
FALSE
Should the push-to-talk button behave as a toggle
SpeakingColor
0.0 1.0 0.0 1.0
Color of various indicators when resident is speaking on a voice channel.
VivoxDebugLevel
-1
Logging level to use when launching the vivox daemon
VivoxDebugServerName
bhd.vivox.com
Hostname of the vivox account server to use for voice when not connected to Agni.
VoiceCallsFriendsOnly
FALSE
Only accept voice calls from residents on your friends list
VoiceEarLocation
0
Location of the virtual ear for voice
VoiceImageLevel0
041ee5a0-cb6a-9ac5-6e49-41e9320507d5
Texture UUID for voice image level 0
VoiceImageLevel1
29de489d-0491-fb00-7dab-f9e686d31e83
Texture UUID for voice image level 1
VoiceImageLevel2
29de489d-0491-fb00-7dab-f9e686d31e83
Texture UUID for voice image level 2
VoiceImageLevel3
29de489d-0491-fb00-7dab-f9e686d31e83
Texture UUID for voice image level 3
VoiceImageLevel4
29de489d-0491-fb00-7dab-f9e686d31e83
Texture UUID for voice image level 4
VoiceImageLevel5
29de489d-0491-fb00-7dab-f9e686d31e83
Texture UUID for voice image level 5
VoiceImageLevel6
29de489d-0491-fb00-7dab-f9e686d31e83
Texture UUID for voice image level 6
VoiceInputAudioDevice
Default
Audio input device to use for voice
VoiceOutputAudioDevice
Default
Audio output device to use for voice
WarnFirstVoice
FALSE
Enables FirstVoice warning dialog

Technical

Voice in Second Life uses Vivox technology that is based on RTP (using the oRTP library), SIP (using the amsip library from Antisip), OpenAL, TinyXPath, OpenSSL, and libcurl for the transmission of voice data. The positional 3D audio is achieved with technology from DiamondWare. These technologies are contained in external daemon software that is started and stopped by the Second Life client.

The SecondLife viewer handles configuration, control, and display functions, but the voice streams (from the microphone and from the Vivox voice server) do not enter the viewer. Unfortunately the source code for the external SLVoice daemon is not available due to contractual obligations between Linden Labs and Vivox.

The executables can be found in the Program Files\SecondLife directory of the runtime and in the linden\indra\newview\vivox-runtime\(platform) directory of the source distribution.

  • SLVoice.exe
    • Thin wrapper around the Vivox SDK
    • Launched when voice is enabled in SL
    • Runs a TCP server that listens and replies to commands and queries using an XML format
  • SLVoiceAgent.exe
    • Actually called the DiamondWare Thin Voice Client
    • Launched by SLVoice, but don't know under what conditions
    • Unclear how this fits in the communication chain
    • Not launched for normal proximity voice chat; don't know about group chat or P2P yet
  • vivoxsdk.dll
    • The Vivox SDK
    • Used by SLVoice.exe
    • Uses a solution from Antisip for SIP, RTP, and G.711
    • Uses OpenAL for playing and recording audio
    • Additionally implements the G.722.1/C (aka Siren14) codec
  • ortp.dll
    • Real-time Transport Protocol (RFC3550) stack under LGPL
    • Used by vivoxsdk.dll
    • Originally from Linphone
    • Distributed as part of amsip by Antisip
  • wrap_oal.dll
    • OpenAL, a cross-platform 3D audio API
    • Used by vivoxsdk.dll
  • alut.dll
  • ssleay32.dll and libeay32
    • From the OpenSSL Project, a collaborative effort to develop a robust, commercial-grade, full-featured, and Open Source toolkit implementing the Secure Sockets Layer (SSL v2/v3) and Transport Layer Security (TLS v1) protocols as well as a full-strength general purpose cryptography library.
    • Used by SLVoiceAgent.dll
  • tntk.dll and srtp.dll
    • Part of the DiamondWare distribution
    • Apparently not used


See also: Third Party Libraries


SLVoice

SLVoice is started from the viewer in SLVoiceClient::stateMachine() using:

SLVoice.exe -p tcp -h -c -ll <VivoxDebugLevel, default -1>

usage: SLVoice [flags]

valid flags are:

[-ll <log-level>] 0-5, or -1 for no logging
[-lf <log-folder>]
[-lp <log-file prefix>]
[-ls <log-file suffix>]
[-p tcp]
[-i <address>] application sends requests to this address
[-o <address>] gateway sends responses and events to this address
[-vo] vivox only functionality
[-ov] (undocumented and unused)
[-c] (undocumented but used)
[-h] (undocumented but used)
[-r] (undocumented and unused)

SLVoice.exe was called vivox-gw.exe in the beta release, so you may still see some references to the old name.

IP Address

The SecondLife viewer uses IP address 127.0.0.1 (localhost), port 44124 to communicate with SLVoice, the voice client gateway.

It is possible to connect to a client gateway running on another host. This is useful for testing. According to comments in the source code: to do this, launch the gateway on a nearby host,

SLVoice.exe -p tcp -i 0.0.0.0:44124

and modify the code in SLVoiceClient::stateMachine() to set the host IP address, mDaemonHost.

Logging

The logging for SLVoice is controlled by a viewer variable, VivoxDebugLevel. You can set it directly in your Documents and Settings\<user>\Application Data\SecondLife\user_settings\settings.xml file

<!--Logging level to use when launching the vivox daemon-->
<VivoxDebugLevel value="5 -lf myDirectory -lp myPrefix -ls .txt"/>

or you can set it from the viewer. To set it from the viewer, you have to enable the Client menu if you haven't already using Ctrl-Alt-D (not to be confused with Ctrl-Alt-Delete). Then select

Client -> Debug Settings

to get the Debug Settings window. In the selection box, hit the triangle to bring up the list of debug variables and select VivoxDebugLevel. In the text entry box, you'll see the current value. Above it is the description, "Logging level to use when launching the Vivox daemon." You can set the level as you like. If you want the output to go somewhere other than the default location, you can enter it in the box as well, for example,

5 -lf myDirectory -lp myPrefix -ls .txt

If <log-folder> is a relative path, it is relative to the directory that SecondLife is running in, ususally C:\Program Files\SecondLife

The default folder is c:/Documents and Settings/<user>/Local Settings/Application Data/Vivox/logs. The default prefix is SLVoice and the default suffix is .txt.

The log file is named <log-file prefix>-<yyyy>-<mm>-<dd><log-file suffix>

The default on September 3, 2007, for example, would be: SLVoice-2007-09-03.txt

The <log-level> must be at least 2 to see INFO messages and 4 to see TRACE messages.


Whenever log level is other than "-1", there is also a log file written to LL_PATH_LOGS, which is usually set to c:/Documents and Settings/<user>/Application Data/SecondLife/logs, with the <log-file prefix> "Connector," that contains log information for the Connector. This logging comes from vivoxsdk.dll which is used by SLVoice.exe. The content does not depend on the log level for SLVoice; the Connector.Create.1 request hardcodes the Connector log level at 10.


17:11:38.988, 0x00001414, INFO , disconnectHandler Client Connection Closed - shutting down
17:11:38.988, 0x00001414, INFO , shutdownGateway Terminating Gateway Process


SLVoice logs commands with added default values for fields not sent by the viewer, for example,

for Account.Login.1 the log includes fields
<AccountURI />
<ParticipantPropertyFrequency>10</ParticipantPropertyFrequency>
<EnableBuddiesAndPresence>false</EnableBuddiesAndPresence>
for Connector.Create.1
<AttemptStun>AttemptStunUnspecified</AttemptStun>
<MinimumPort>22860</MinimumPort>
<MaximumPort>22892</MaximumPort>
for Session.Create.1
<Password />
<JoinAudio>true</JoinAudio>
<JoinText>false</JoinText>
<PasswordHashAlgorithm>ClearText</PasswordHashAlgorithm>
for Session.Set3DPosition.1
<OrientationType>legacy</OrientationType>

Message Format

Actions

These are examples of the Vivox SDK commands used by the SecondLife viewer.


Account.ChannelGetList.1
Coded in llvoiceclient.cpp but not used


Account.Login.1
<Request requestId="3" action="Account.Login.1">
<ConnectorHandle>c1_m1000</ConnectorHandle>
<AccountName>abcdefghijklmnopqrstuvwxy</AccountName>
<AccountPassword>ABCDEFGHIJKLMNOPQRSTUVW</AccountPassword>
<AudioSessionAnswerMode>VerifyAnswer</AudioSessionAnswerMode>
<AccountURI />
<ParticipantPropertyFrequency>10</ParticipantPropertyFrequency>
<EnableBuddiesAndPresence>false</EnableBuddiesAndPresence>
</Request>
<Response requestId="3" action="Account.Login.1">
<ReturnCode>0</ReturnCode>
<Results>
<StatusCode>0</StatusCode>
<StatusString>OK</StatusString>
<AccountHandle>c1_m1000abcdefghijklmnopqrstuvwxy</AccountHandle>
</Results>
<InputXml>
<Request requestId="3" action="Account.Login.1">
<ConnectorHandle>c1_m1000</ConnectorHandle>
<AccountName>abcdefghijklmnopqrstuvwxy<AccountName>
<AccountPassword>ABCDEFGHIJKLMNOPQRSTUVW</AccountPassword>
<AudioSessionAnswerMode>VerifyAnswer</AudioSessionAnswerMode>
<AccountURI />
<ParticipantPropertyFrequency>10</ParticipantPropertyFrequency>
<EnableBuddiesAndPresence>false</EnableBuddiesAndPresence>
</Request>
</InputXml>
</Response>


Account.Logout.1
<Request requestId="557" action="Account.Logout.1">
<AccountHandle>c1_m1000abcdefghijklmnopqrstuvwxy</AccountHandle>
</Request>
The viewer doesn't get the response before the Connector shuts down


Aux.CaptureAudioStart.1
<Request requestId="171" action="Aux.CaptureAudioStart.1">
<Duration>10000</Duration>
</Request>
<Response requestId="171" action="Aux.CaptureAudioStart.1">
<ReturnCode>0</ReturnCode>
<Results>
<StatusCode>0</StatusCode>
<StatusString />
</Results>
<InputXml>
<Request requestId="171" action="Aux.CaptureAudioStart.1">
<Duration>10000</Duration>
</Request>
</InputXml>
</Response>


Aux.CaptureAudioStop.1
<Request requestId="174" action="Aux.CaptureAudioStop.1" />
<Response requestId="174" action="Aux.CaptureAudioStop.1">
<ReturnCode>0</ReturnCode>
<Results>
<StatusCode>0</StatusCode>
<StatusString />
</Results>
<InputXml>
<Request requestId="174" action="Aux.CaptureAudioStop.1" />
</InputXml>
</Response>


Aux.GetCaptureDevices.1
<Request requestId="0" action="Aux.GetCaptureDevices.1" />
<Response requestId="0" action="Aux.GetCaptureDevices.1">
<ReturnCode>0</ReturnCode>
<Results>
<StatusCode>0</StatusCode>
<StatusString />
<CaptureDevices>
<CaptureDevice>
<Device>Realtek HD Front Pink Jack</Device>
</CaptureDevice>
<CaptureDevice>
<Device>Realtek HD Digital input</Device>
</CaptureDevice>
<CaptureDevice>
<Device>Realtek HD Front Green Jack</Device>
</CaptureDevice>
<CaptureDevice>
<Device>Back Line in/Mic, Front Line in</Device>
</CaptureDevice>
</CaptureDevices>
<CurrentCaptureDevice>
<Device>Realtek HD Front Pink Jack</Device>
</CurrentCaptureDevice>
</Results>
<InputXml>
<Request requestId="0" action="Aux.GetCaptureDevices.1" />
</InputXml>
</Response>


Aux.GetRenderDevices.1
<Request requestId="1" action="Aux.GetRenderDevices.1" />
<Response requestId="1" action="Aux.GetRenderDevices.1">
<ReturnCode>0</ReturnCode>
<Results>
<StatusCode>0</StatusCode>
<StatusString />
<RenderDevices>
<RenderDevice>
<Device>Realtek HD Audio rear output</Device>
</RenderDevice>
</RenderDevices>
<CurrentRenderDevice>
<Device>Realtek HD Audio rear output</Device>
</CurrentRenderDevice>
</Results>
<InputXml>
<Request requestId="1" action="Aux.GetRenderDevices.1" />
</InputXml>
</Response>


Aux.RenderAudioStart.1
Coded in llvoiceclient.cpp but not used


Aux.RenderAudioStop.1
Coded in llvoiceclient.cpp but not used


Aux.SetCaptureDevice.1
<Request requestId="9" action="Aux.SetCaptureDevice.1">
<CaptureDeviceSpecifier>Realtek HD Front Green Jack</CaptureDeviceSpecifier>
</Request>
<Response requestId="9" action="Aux.SetCaptureDevice.1">
<ReturnCode>0</ReturnCode>
<Results>
<StatusCode>0</StatusCode>
<StatusString />
</Results>
<InputXml>
<Request requestId="9" action="Aux.SetCaptureDevice.1">
<CaptureDeviceSpecifier>Realtek HD Front Green Jack</CaptureDeviceSpecifier>
</Request>
</InputXml>
</Response>


Aux.SetMicLevel.1
<Request requestId="172" action="Aux.SetMicLevel.1">
<Level>50</Level>
</Request>
<Response requestId="172" action="Aux.SetMicLevel.1">
<ReturnCode>0</ReturnCode>
<Results>
<StatusCode>0</StatusCode>
<StatusString />
</Results>
<InputXml>
<Request requestId="172" action="Aux.SetMicLevel.1">
<Level>50</Level>
</Request>
</InputXml>
</Response>


Aux.SetRenderDevice.1
<Request requestId="31" action="Aux.SetRenderDevice.1">
<RenderDeviceSpecifier>Realtek HD Audio rear output</RenderDeviceSpecifier>
</Request>
<Response requestId="31" action="Aux.SetRenderDevice.1">
<ReturnCode>0</ReturnCode>
<Results>
<StatusCode>0</StatusCode>
<StatusString />
</Results>
<InputXml>
<Request requestId="31" action="Aux.SetRenderDevice.1">
<RenderDeviceSpecifier>Realtek HD Audio rear output</RenderDeviceSpecifier>
</Request>
</InputXml>
</Response>


Aux.SetSpeakerLevel.1
<Request requestId="173" action="Aux.SetSpeakerLevel.1">
<Level>50</Level>
</Request>
<Response requestId="173" action="Aux.SetSpeakerLevel.1">
<ReturnCode>0</ReturnCode>
<Results>
<StatusCode>0</StatusCode>
<StatusString />
</Results>
<InputXml>
<Request requestId="173" action="Aux.SetSpeakerLevel.1">
<Level>50</Level>
</Request>
</InputXml>
</Response>


Connector.Create.1
<Request requestId="2" action="Connector.Create.1">
<ClientName>V2 SDK</ClientName>
<AttemptStun>AttemptStunUnspecified</AttemptStun>
<AccountManagementServer>https://www.bhr.vivox.com/api2/</AccountManagementServer>
<MinimumPort>22860</MinimumPort>
<MaximumPort>22892</MaximumPort>
<Logging>
<Enabled>false</Enabled>
<Folder>C:\Documents and Settings\HP_Administrator\Application Data\SecondLife\logs</Folder>
<FileNamePrefix>Connector</FileNamePrefix>
<FileNameSuffix>.log</FileNameSuffix>
<LogLevel>10</LogLevel>
</Logging>
</Request>
<Response requestId="2" action="Connector.Create.1">
<ReturnCode>0</ReturnCode>
<Results>
<VersionID>2.0.2961.1968</VersionID>
<StatusCode>0</StatusCode>
<StatusString />
<ConnectorHandle>c1_m1000</ConnectorHandle>
</Results>
<InputXml>
<Request requestId="2" action="Connector.Create.1">
<ClientName>V2 SDK</ClientName>
<AttemptStun>AttemptStunUnspecified</AttemptStun>
<AccountManagementServer>https://www.bhr.vivox.com/api2/</AccountManagementServer>
<MinimumPort>22860</MinimumPort>
<MaximumPort>22892</MaximumPort>
<Logging>
<Enabled>false</Enabled>
<Folder>C:\Documents and Settings\HP_Administrator\Application Data\SecondLife\logs</Folder>
<FileNamePrefix>Connector</FileNamePrefix>
<FileNameSuffix>.log</FileNameSuffix>
<LogLevel>10</LogLevel>
</Logging>
</Request>
</InputXml>
</Response>
Connector.InitiateShutdown.1
<Request requestId="558" action="Connector.InitiateShutdown.1">
<ConnectorHandle>c1_m1000</ConnectorHandle>
</Request>
The viewer doesn't get a response


Connector.MuteLocalMic.1
<Request requestId="6" action="Connector.MuteLocalMic.1">
<ConnectorHandle>c1_m1000</ConnectorHandle>
<Value>true</Value>
</Request>
<Response requestId="6" action="Connector.MuteLocalMic.1">
<ReturnCode>0</ReturnCode>
<Results>
<StatusCode>0</StatusCode>
<StatusString />
</Results>
<InputXml>
<Request requestId="6" action="Connector.MuteLocalMic.1">
<ConnectorHandle>c1_m1000</ConnectorHandle>
<Value>true</Value>
</Request>
</InputXml>
</Response>


Connector.MuteLocalSpeaker.1
Used only if AudioLevelVoice is 0 at startup


Connector.SetLocalMicVolume.1
<Request requestId="8" action="Connector.SetLocalMicVolume.1">
<ConnectorHandle>c1_m1000</ConnectorHandle>
<Value>50</Value>
</Request>
<Response requestId="8" action="Connector.SetLocalMicVolume.1">
<ReturnCode>0</ReturnCode>
<Results>
<StatusCode>0</StatusCode>
<StatusString />
</Results>
<InputXml>
<Request requestId="8" action="Connector.SetLocalMicVolume.1">
<ConnectorHandle>c1_m1000</ConnectorHandle>
<Value>50</Value>
</Request>
</InputXml>
</Response>


Connector.SetLocalSpeakerVolume.1
<Request requestId="7" action="Connector.SetLocalSpeakerVolume.1">
<ConnectorHandle>c1_m1000</ConnectorHandle>
<Value>50</Value>
</Request>
<Response requestId="7" action="Connector.SetLocalSpeakerVolume.1">
<ReturnCode>0</ReturnCode>
<Results>
<StatusCode>0</StatusCode>
<StatusString />
</Results>
<InputXml>
<Request requestId="7" action="Connector.SetLocalSpeakerVolume.1">
<ConnectorHandle>c1_m1000</ConnectorHandle>
<Value>50</Value>
</Request>
</InputXml>
</Response>


Session.Connect.1
Used by p2p


Session.Create.1
<Request requestId="4" action="Session.Create.1">
<AccountHandle>c1_m1000abcdefghijklmnopqrstuvwxy</AccountHandle>
<URI>sip:confctl-505189@bhr.vivox.com</URI>
<Name />
<Password />
<JoinAudio>true</JoinAudio>
<JoinText>false</JoinText>
<PasswordHashAlgorithm>ClearText</PasswordHashAlgorithm>
</Request>
<Response requestId="4" action="Session.Create.1">
<ReturnCode>0</ReturnCode>
<Results>
<StatusCode>0</StatusCode>
<StatusString />
<SessionHandle>c1_m1000abcdefghijklmnopqrstuvwxy0</SessionHandle>
</Results>
<InputXml>
<Request requestId="4" action="Session.Create.1">
<AccountHandle>c1_m1000abcdefghijklmnopqrstuvwxy</AccountHandle>
<URI>sip:confctl-505189@bhr.vivox.com</URI>
<Name />
<Password />
<JoinAudio>true</JoinAudio>
<JoinText>false</JoinText>
<PasswordHashAlgorithm>ClearText</PasswordHashAlgorithm>
</Request>
</InputXml>
</Response>


Session.Set3DPosition.1
<Request requestId="114" action="Session.Set3DPosition.1">
<SessionHandle>c1_m1000abcdefghijklmnopqrstuvwxy1</SessionHandle>
<OrientationType>legacy</OrientationType>
<SpeakerPosition>
<Position>
<X>261451</X>
<Y>26.9568</Y>
<Z>-283000</Z>
</Position>
<Velocity>
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Velocity>
<AtOrientation>
<X>0.816965</X>
<Y>0</Y>
<Z>0.576688</Z>
</AtOrientation>
<UpOrientation>
<X>0</X>
<Y>1</Y>
<Z>0</Z>
</UpOrientation>
<LeftOrientation>
<X>0.576688</X>
<Y>0</Y>
<Z>-0.816965</Z>
</LeftOrientation>
</SpeakerPosition>
<ListenerPosition>
<Position>
<X>261448</X>
<Y>27.9639</Y>
<Z>-283001</Z>
</Position>
<Velocity>
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Velocity>
<AtOrientation>
<X>0.795791</X>
<Y>0</Y>
<Z>0.559283</Z>
</AtOrientation>
<UpOrientation>
<X>0</X>
<Y>1</Y>
<Z>0</Z>
</UpOrientation>
<LeftOrientation>
<X>0.574999</X>
<Y>0</Y>
<Z>-0.818154</Z>
</LeftOrientation>
</ListenerPosition>
</Request>
The viewer doesn't get a response


Session.SetParticipantVolumeForMe.1
Used by IM panel and active speaker volume


Session.Terminate.1
<Request requestId="25" action="Session.Terminate.1">
<SessionHandle>c1_m1000abcdefghijklmnopqrstuvwxy0</SessionHandle>
</Request>
<Response requestId="25" action="Session.Terminate.1">
<ReturnCode>0</ReturnCode>
<Results>
<StatusCode>0</StatusCode>
<StatusString />
</Results>
<InputXml>
<Request requestId="25" action="Session.Terminate.1">
<SessionHandle>c1_m1000abcdefghijklmnopqrstuvwxy0</SessionHandle>
</Request>
</InputXml>
</Response>