Hi,
I’ve set up a voice communication between 2 Panda C++ programs running on 2 different machines. In order to do so I’m using a streaming of microphone input over the LAN via UDP packets.
It sort of works, with anyway a couple of issues:
some delay & stuttering
a kind of unexplained loop in the audio-receive reader (it seems that former received samples in the buffer are being read again - after about 4s)
echo (I’ll take care about this one)
Since the documentation is somewhat difficult to grasp, I’m wondering what’s missing in set-up, buffering or whatever…
Here is the relevant part of the code:
// SET UP AUDIO STUFF
PT(MicrophoneAudio) mic = MicrophoneAudioDS::get_option(2); // micro 44100hz mono
PT(MicrophoneAudioCursorDS) mic_cursor = DCAST(MicrophoneAudioCursorDS,mic->open()); // audio cursor on micro stream
// create audiomanager
PT(AudioManager) AM = AudioManager::create_AudioManager();
PT(AsyncTask) audio_listen_task = new GenericAsyncTask("AudioUpdate", &audio_task, (void*) AM);
taskMgr->add(audio_listen_task);
// create audio send & rciv tasks
PT(AsyncTask) audio_send_task = new GenericAsyncTask("AudioSend", &audio_task_send, (void*) NULL);
taskMgr->add(audio_send_task);
PT(AsyncTask) audio_receive_task = new GenericAsyncTask("AudioReceive", &audio_task_receive, (void*) AM);
taskMgr->add(audio_receive_task);
// open remote sound stream
PT(UserDataAudio) remoteAudio = new UserDataAudio(44100,1,true); // remote sound input, 1 channel, remove after read
PT(AudioSound) remote_sound = AM->get_sound(remoteAudio,false); // positional = false, AudioManager::StreamMode::SM_???
remote_sound->init_type(); // is this needed? for what?
And the async processing
// PER FRAMe ASYNCHRONOUS TASKS
AsyncTask::DoneStatus audio_task_send(GenericAsyncTask* task, void* datanull){
#define MIC_FRAME_SIZE 2048 // mike buffers are 2048 samples (2bytes)
PN_int16 samples[MIC_FRAME_SIZE];
int nb_audio_samples_ready = mic_cursor->ready();
if (nb_audio_samples_ready < MIC_FRAME_SIZE) return AsyncTask::DS_cont;
// one mono mic sample is 2*bytes
while (nb_audio_samples_ready >= MIC_FRAME_SIZE) {
int nb_read = MIC_FRAME_SIZE;
mic_cursor->read_samples(nb_read,samples); // read samples from microphone
send_voice_on_UDP((char *)samples,nb_read);
nb_audio_samples_ready -= nb_read;
}
return AsyncTask::DS_cont;
}
AsyncTask::DoneStatus audio_task_receive(GenericAsyncTask* task, void* data){
char datagram[VOICE_PACKET_SIZE];
while (true) {
int bytes_received = recvfrom(RecvSocketVoice, (char *) datagram, VOICE_PACKET_SIZE, 0, (SOCKADDR *)&SenderAddr, &SenderAddrSize);
if (bytes_received < VOICE_PACKET_SIZE) break;
int nb_audio_samples = bytes_received/2; // since 1 mono sample = 16bits
remoteAudio->append((PN_int16 *) datagram, nb_audio_samples);
}
return AsyncTask::DS_cont;
}
AsyncTask::DoneStatus audio_task(GenericAsyncTask* task, void* data){
AudioManager *AMgr = (AudioManager*)data;
AMgr->update(); // local sound
return AsyncTask::DS_cont;
}
Being stuck with something that is 85% working and still not confident if done properly, I suspect some audio set-up is not correct.
In particular, what the use of:
AudioManager::StreamMode::SM_xx ??? (heuristic, stream, …)
remote_sound->init_type();
Is there a way to insure that the Audio reader really drops each sample once played?
Any hint is more than welcome!
Thanks fy support