static int do_level_callback() { static struct timeval last = {0,0}; struct timeval now; float input_db; float output_db; now = iax_tvnow(); if ( last.tv_sec != 0 && iaxci_usecdiff(&now, &last) < 100000 ) return 0; last = now; /* if input has not been processed in the last second, set to silent */ input_db = iaxci_usecdiff(&now, &timeLastInput) < 1000000 ? vol_to_db(input_level) : AUDIO_ENCODE_SILENCE_DB; /* if output has not been processed in the last second, set to silent */ output_db = iaxci_usecdiff(&now, &timeLastOutput) < 1000000 ? vol_to_db(output_level) : AUDIO_ENCODE_SILENCE_DB; iaxci_do_levels_callback(input_db, output_db); return 0; }
static int service_audio() { /* TODO: maybe we shouldn't allocate 8kB on the stack here. */ short buf [4096]; int want_send_audio = selected_call >= 0 && ((calls[selected_call].state & IAXC_CALL_STATE_OUTGOING) || (calls[selected_call].state & IAXC_CALL_STATE_COMPLETE)); //&& !(audio_prefs & IAXC_AUDIO_PREF_SEND_DISABLE); int want_local_audio = (audio_prefs & IAXC_AUDIO_PREF_RECV_LOCAL_RAW) || (audio_prefs & IAXC_AUDIO_PREF_RECV_LOCAL_ENCODED); //fprintf(stdout, "service_audio() => want_send_audio=%d/want_local_audio=%d\n", want_send_audio, want_local_audio); if ( want_local_audio || want_send_audio ) { for ( ;; ) { int to_read; int cmin; audio_driver.start(&audio_driver); /* use codec minimum if higher */ cmin = want_send_audio && calls[selected_call].encoder ? calls[selected_call].encoder->minimum_frame_size : 1; to_read = cmin > minimum_outgoing_framesize ? cmin : minimum_outgoing_framesize; /* Round up to the next multiple */ if ( to_read % cmin ) to_read += cmin - (to_read % cmin); if ( to_read > (int)(sizeof(buf) / sizeof(short)) ) { fprintf(stderr, "internal error: to_read > sizeof(buf)\n"); exit(1); } /* Currently pa gives us either all the bits we ask for or none */ if ( audio_driver.input(&audio_driver, buf, &to_read) ) { iaxci_usermsg(IAXC_ERROR, "ERROR reading audio\n"); break; } /* Frame was not available */ if ( !to_read ) break; if ( audio_prefs & IAXC_AUDIO_PREF_RECV_LOCAL_RAW ) iaxci_do_audio_callback(selected_call, 0, IAXC_SOURCE_LOCAL, 0, 0, to_read * 2, (unsigned char *)buf); if (( want_send_audio ) && (!(audio_prefs & IAXC_AUDIO_PREF_SEND_DISABLE))) audio_send_encoded_audio(&calls[selected_call], selected_call, buf, calls[selected_call].format & IAXC_AUDIO_FORMAT_MASK, to_read); } } else { static int i = 0; audio_driver.stop(&audio_driver); /*! \deprecated Q: Why do we continuously send IAXC_EVENT_LEVELS events when there is no selected call? A: So that certain users of iaxclient do not have to reset their vu meters when a call ends -- they can just count on getting level callbacks. This is a bit of a hack so any applications relying on this behavior should maybe be changed. */ if ( i++ % 50 == 0 ) iaxci_do_levels_callback(AUDIO_ENCODE_SILENCE_DB, AUDIO_ENCODE_SILENCE_DB); } return 0; }