/** * @brief Send audio frame to a friend * @param callId Id of friend in call list. * @param pcm An array of audio samples (Pulse-code modulation). * @param samples Number of samples in this frame. * @param chans Number of audio channels. * @param rate Audio sampling rate used in this frame. * @return False only on error, but not if there's nothing to send. */ bool CoreAV::sendCallAudio(uint32_t callId, const int16_t *pcm, size_t samples, uint8_t chans, uint32_t rate) { if (!calls.contains(callId)) return false; ToxFriendCall& call = calls[callId]; if (call.muteMic || call.inactive || !(call.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_A)) { return true; } // TOXAV_ERR_SEND_FRAME_SYNC means toxav failed to lock, retry 5 times in this case TOXAV_ERR_SEND_FRAME err; int retries = 0; do { if (!toxav_audio_send_frame(toxav, callId, pcm, samples, chans, rate, &err)) { if (err == TOXAV_ERR_SEND_FRAME_SYNC) { ++retries; QThread::usleep(500); } else { qDebug() << "toxav_audio_send_frame error: "<<err; } } } while (err == TOXAV_ERR_SEND_FRAME_SYNC && retries < 5); if (err == TOXAV_ERR_SEND_FRAME_SYNC) qDebug() << "toxav_audio_send_frame error: Lock busy, dropping frame"; return true; }
/** * @brief Send audio frame to a friend * @param callId Id of friend in call list. * @param pcm An array of audio samples (Pulse-code modulation). * @param samples Number of samples in this frame. * @param chans Number of audio channels. * @param rate Audio sampling rate used in this frame. * @return False only on error, but not if there's nothing to send. */ bool CoreAV::sendCallAudio(uint32_t callId, const int16_t* pcm, size_t samples, uint8_t chans, uint32_t rate) const { auto it = calls.find(callId); if (it == calls.end()) { return false; } ToxFriendCall const& call = it->second; if (call.getMuteMic() || !call.isActive() || !(call.getState() & TOXAV_FRIEND_CALL_STATE_ACCEPTING_A)) { return true; } // TOXAV_ERR_SEND_FRAME_SYNC means toxav failed to lock, retry 5 times in this case TOXAV_ERR_SEND_FRAME err; int retries = 0; do { if (!toxav_audio_send_frame(toxav, callId, pcm, samples, chans, rate, &err)) { if (err == TOXAV_ERR_SEND_FRAME_SYNC) { ++retries; QThread::usleep(500); } else { qDebug() << "toxav_audio_send_frame error: " << err; } } } while (err == TOXAV_ERR_SEND_FRAME_SYNC && retries < 5); if (err == TOXAV_ERR_SEND_FRAME_SYNC) { qDebug() << "toxav_audio_send_frame error: Lock busy, dropping frame"; } return true; }
void read_device_callback(const int16_t* captured, uint32_t size, void* data) { TOXAV_ERR_SEND_FRAME error; uint32_t friend_number = *((uint32_t*)data); /* TODO: Or pass an array of call_idx's */ int64_t sample_count = CallControl.audio_sample_rate * CallControl.audio_frame_duration / 1000; if ( sample_count <= 0 || toxav_audio_send_frame(CallControl.av, friend_number, captured, sample_count, CallControl.audio_channels, CallControl.audio_sample_rate, &error) == false ) {} }
static void *call_thread(void *pd) { ToxAV *AliceAV = ((thread_data *) pd)->AliceAV; ToxAV *BobAV = ((thread_data *) pd)->BobAV; CallControl *AliceCC = ((thread_data *) pd)->AliceCC; CallControl *BobCC = ((thread_data *) pd)->BobCC; uint32_t friend_number = ((thread_data *) pd)->friend_number; memset(AliceCC, 0, sizeof(CallControl)); memset(BobCC, 0, sizeof(CallControl)); { /* Call */ TOXAV_ERR_CALL rc; toxav_call(AliceAV, friend_number, 48, 3000, &rc); if (rc != TOXAV_ERR_CALL_OK) { printf("toxav_call failed: %d\n", rc); ck_assert(0); } } while (!BobCC->incoming) { c_sleep(10); } { /* Answer */ TOXAV_ERR_ANSWER rc; toxav_answer(BobAV, 0, 8, 500, &rc); if (rc != TOXAV_ERR_ANSWER_OK) { printf("toxav_answer failed: %d\n", rc); ck_assert(0); } } c_sleep(30); int16_t *PCM = (int16_t *)calloc(960, sizeof(int16_t)); uint8_t *video_y = (uint8_t *)calloc(800 * 600, sizeof(uint8_t)); uint8_t *video_u = (uint8_t *)calloc(800 * 600 / 4, sizeof(uint8_t)); uint8_t *video_v = (uint8_t *)calloc(800 * 600 / 4, sizeof(uint8_t)); time_t start_time = time(NULL); while (time(NULL) - start_time < 4) { toxav_iterate(AliceAV); toxav_iterate(BobAV); toxav_audio_send_frame(AliceAV, friend_number, PCM, 960, 1, 48000, NULL); toxav_audio_send_frame(BobAV, 0, PCM, 960, 1, 48000, NULL); toxav_video_send_frame(AliceAV, friend_number, 800, 600, video_y, video_u, video_v, NULL); toxav_video_send_frame(BobAV, 0, 800, 600, video_y, video_u, video_v, NULL); c_sleep(10); } { /* Hangup */ TOXAV_ERR_CALL_CONTROL rc; toxav_call_control(AliceAV, friend_number, TOXAV_CALL_CONTROL_CANCEL, &rc); if (rc != TOXAV_ERR_CALL_CONTROL_OK) { printf("toxav_call_control failed: %d %p %p\n", rc, (void *)AliceAV, (void *)BobAV); } } c_sleep(30); free(PCM); free(video_y); free(video_u); free(video_v); printf("Closing thread\n"); pthread_exit(NULL); }