@@ -47,7 +47,7 @@ CConVar<int> g_cvarAdminImmunityTargetting("cs2f_admin_immunity", FCVAR_NONE, "M
4747CConVar<bool > g_cvarEnableMapSteamIds (" cs2f_map_steamids_enable" , FCVAR_NONE , " Whether to make Steam ID's available to maps" , false );
4848
4949ZEPlayerHandle::ZEPlayerHandle () :
50- m_Index(INVALID_ZEPLAYERHANDLE_INDEX ){};
50+ m_Index(INVALID_ZEPLAYERHANDLE_INDEX ) {};
5151
5252ZEPlayerHandle::ZEPlayerHandle (CPlayerSlot slot)
5353{
@@ -96,6 +96,51 @@ ZEPlayer* ZEPlayerHandle::Get() const
9696 return pZEPlayer;
9797}
9898
99+ std::vector<int16_t > ZEPlayer::GetVoiceChat ()
100+ {
101+ int error = 0 ;
102+ OpusDecoder* decoder = opus_decoder_create (VOICECHAT_SAMPLERATE , VOICECHAT_CHANNELS , &error);
103+ if (error != OPUS_OK || decoder == nullptr || m_dequeVoicechat.empty ())
104+ return std::vector<int16_t >();
105+
106+ std::vector<int16_t > pcm;
107+ // maximum packet duration (120ms; 5760 for 48kHz),
108+ const int frameBufLen = VOICECHAT_SAMPLERATE * 120 / 1000 ;
109+ std::vector<int16_t > frameBuf (frameBufLen * VOICECHAT_CHANNELS );
110+
111+ for (const auto & [_, packet] : m_dequeVoicechat)
112+ {
113+ const unsigned char * data =
114+ reinterpret_cast <const unsigned char *>(packet.data ());
115+ int dataLen = static_cast <int >(packet.size ());
116+
117+ int samples = opus_decode (
118+ decoder,
119+ data,
120+ dataLen,
121+ frameBuf.data (),
122+ frameBufLen,
123+ 0 );
124+
125+ if (samples < 0 )
126+ {
127+ Panic (" ZEPlayer::GetVoiceChat(): failed to parse opus: %s\n " , opus_strerror (samples));
128+
129+ break ;
130+ }
131+ else
132+ {
133+ pcm.insert (
134+ pcm.end (),
135+ frameBuf.begin (),
136+ frameBuf.begin () + samples * VOICECHAT_CHANNELS );
137+ }
138+ }
139+
140+ opus_decoder_destroy (decoder);
141+ return pcm;
142+ }
143+
99144void ZEPlayer::OnSpawn ()
100145{
101146 SetSpeedMod (1 .f );
@@ -759,6 +804,46 @@ void ZEPlayer::SetEntwatchHudSize(float flSize)
759804 pText->m_flFontSize = m_flEntwatchHudSize;
760805}
761806
807+ void ZEPlayer::OnVoiceFrame (const CMsgVoiceAudio& msg)
808+ {
809+ // Message("OnVoiceFrame(...) "
810+ // "slot=%d "
811+ // "time=%f "
812+ // "format=%d "
813+ // "voice_data_size=%zu "
814+ // "sequence_bytes=%d "
815+ // "section_number=%u "
816+ // "sample_rate=%u "
817+ // "uncompressed_sample_offset=%u "
818+ // "num_packets=%u "
819+ // "voice_level=%f\n",
820+ // m_slot,
821+ // GetGlobals()->curtime,
822+ // static_cast<int>(msg.format()),
823+ // msg.voice_data().size(),
824+ // msg.sequence_bytes(),
825+ // msg.section_number(),
826+ // msg.sample_rate(),
827+ // msg.uncompressed_sample_offset(),
828+ // msg.num_packets(),
829+ // msg.voice_level());
830+
831+ // assume some things about the incoming voice chat
832+ // - all data is somewhat realtime: packets can be out of order, causing corruption; allow it
833+ // - the client controls the voice_level and sequence_bytes fields
834+ if ((msg.format () != VOICEDATA_FORMAT_OPUS ) || (msg.num_packets () > UINT8_MAX ) || (msg.voice_data ().size () > UINT8_MAX ))
835+ return ;
836+
837+ // make a owned copy
838+ std::string voice_data = msg.voice_data ();
839+ float time = GetGlobals ()->curtime ;
840+ m_dequeVoicechat.push_back (std::make_pair (time, voice_data));
841+ while ((!m_dequeVoicechat.empty ()) && (m_dequeVoicechat.front ().first < (time - VOICECHAT_SECONDS )))
842+ m_dequeVoicechat.pop_front ();
843+
844+ return ;
845+ }
846+
762847void CPlayerManager::OnBotConnected (CPlayerSlot slot)
763848{
764849 m_vecPlayers[slot.Get ()] = new ZEPlayer (slot, true );
0 commit comments