Example #1
0
static void friendlist_onAv(ToxWindow *self, ToxAv *av)
{
    int id = toxav_get_peer_id(av, 0);
    id++;
    if ( id >= max_friends_index)
        return;
    
    Tox* m = toxav_get_tox(av);
    
    if (friends[id].chatwin == -1) {
        if (get_num_active_windows() < MAX_WINDOWS_NUM) {
            friends[id].chatwin = add_window(m, new_chat(m, friends[id].num));
        } else {
            uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
            tox_get_name(m, id, nick);
            nick[TOXIC_MAX_NAME_LENGTH] = '\0';
            wprintw(prompt->window, "Audio action from: %s!\n", nick);
            
            prep_prompt_win();
            wattron(prompt->window, COLOR_PAIR(RED));
            wprintw(prompt->window, "* Warning: Too many windows are open.\n");
            wattron(prompt->window, COLOR_PAIR(RED));
            
            alert_window(prompt, WINDOW_ALERT_0, true);
        }
    }
}
Example #2
0
static void friendlist_onAv(ToxWindow *self, ToxAv *av, int call_index)
{
    int id = toxav_get_peer_id(av, call_index, 0);

    if ( id != av_ErrorUnknown && id >= Friends.max_idx)
        return;

    Tox *m = toxav_get_tox(av);

    if (Friends.list[id].chatwin == -1) {
        if (get_num_active_windows() < MAX_WINDOWS_NUM) {
            if (toxav_get_call_state(av, call_index) == av_CallStarting) { /* Only open windows when call is incoming */
                Friends.list[id].chatwin = add_window(m, new_chat(m, Friends.list[id].num));
            }            
        } else {
            char nick[TOX_MAX_NAME_LENGTH];
            get_nick_truncate(m, nick, Friends.list[id].num);
            line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio action from: %s!", nick);

            const char *errmsg = "* Warning: Too many windows are open.";
            line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);
            
            sound_notify(prompt, error, NT_WNDALERT_1, NULL);
        }
    }
}
Example #3
0
static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
{
    assert(0);
    if( friend_number >= Friends.max_idx)
        return;

    assert(0);
    Tox *m = toxav_get_tox(av);

    if (Friends.list[friend_number].chatwin == -1) {
        if (get_num_active_windows() < MAX_WINDOWS_NUM) {
            if(state != TOXAV_FRIEND_CALL_STATE_FINISHED) {
                Friends.list[friend_number].chatwin = add_window(m, new_chat(m, Friends.list[friend_number].num));
                set_active_window(Friends.list[friend_number].chatwin);
            }
        } else {
            char nick[TOX_MAX_NAME_LENGTH];
            get_nick_truncate(m, nick, Friends.list[friend_number].num);
            line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio action from: %s!", nick);

            const char *errmsg = "* Warning: Too many windows are open.";
            line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);

            sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
        }
    }
}
Example #4
0
void Core::sendGroupCallAudio(int groupId, ToxAv* toxav)
{
    if (!groupCalls[groupId].active)
        return;

    if (groupCalls[groupId].muteMic || !Audio::isInputReady())
    {
        groupCalls[groupId].sendAudioTimer->start();
        return;
    }

    const int framesize = (groupCalls[groupId].codecSettings.audio_frame_duration * groupCalls[groupId].codecSettings.audio_sample_rate) / 1000 * av_DefaultSettings.audio_channels;
    const int bufsize = framesize * 2 * av_DefaultSettings.audio_channels;
    uint8_t buf[bufsize];

    if (Audio::tryCaptureSamples(buf, framesize))
    {
        if (toxav_group_send_audio(toxav_get_tox(toxav), groupId, (int16_t*)buf,
                framesize, av_DefaultSettings.audio_channels, av_DefaultSettings.audio_sample_rate) < 0)
        {
            qDebug() << "Core: toxav_group_send_audio error";
            groupCalls[groupId].sendAudioTimer->start();
            return;
        }
    }
    groupCalls[groupId].sendAudioTimer->start();
}
Example #5
0
static void friendlist_onAv(ToxWindow *self, ToxAv *av, int call_index)
{
    int id = toxav_get_peer_id(av, call_index, 0);

    /*id++;*/
    if ( id != ErrorInternal && id >= max_friends_index)
        return;

    Tox *m = toxav_get_tox(av);

    if (friends[id].chatwin == -1) {
        if (get_num_active_windows() < MAX_WINDOWS_NUM) {
            friends[id].chatwin = add_window(m, new_chat(m, friends[id].num));
        } else {
            uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
            int n_len = tox_get_name(m, id, nick);

            n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH - 1);
            nick[n_len] = '\0';

            uint8_t msg[MAX_STR_SIZE];
            snprintf(msg, sizeof(msg), "Audio action from: %s!", nick);
            line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);

            uint8_t *errmsg = "* Warning: Too many windows are open.";
            line_info_add(prompt, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);

            alert_window(prompt, WINDOW_ALERT_0, true);
        }
    }
}
Example #6
0
bool CoreAV::sendGroupCallAudio(int groupId, const int16_t *pcm, size_t samples, uint8_t chans, uint32_t rate)
{
    if (!groupCalls.contains(groupId))
        return false;

    ToxGroupCall& call = groupCalls[groupId];

    if (call.inactive || call.muteMic)
        return true;

    if (toxav_group_send_audio(toxav_get_tox(toxav), groupId, pcm, samples, chans, rate) != 0)
        qDebug() << "toxav_group_send_audio error";

    return true;
}
Example #7
0
bool CoreAV::sendGroupCallAudio(int groupId, const int16_t* pcm, size_t samples, uint8_t chans,
                                uint32_t rate) const
{
    std::map<int, ToxGroupCall>::const_iterator it = groupCalls.find(groupId);
    if (it == groupCalls.end()) {
        return false;
    }

    if (!it->second.isActive() || it->second.getMuteMic()) {
        return true;
    }

    if (toxav_group_send_audio(toxav_get_tox(toxav), groupId, pcm, samples, chans, rate) != 0)
        qDebug() << "toxav_group_send_audio error";

    return true;
}
Example #8
0
void utox_audio_thread(void *args) {
    ToxAV *av = args;
    const char *device_list, *output_device = NULL;
    void *audio_device = NULL;

    _Bool call[MAX_CALLS] = {0}, preview = 0;
    _Bool groups_audio[MAX_NUM_GROUPS] = {0};

    int perframe = (UTOX_DEFAULT_FRAME_A * UTOX_DEFAULT_SAMPLE_RATE_A) / 1000;
    uint8_t buf[perframe * 2 * UTOX_DEFAULT_AUDIO_CHANNELS]; //, dest[perframe * 2 * UTOX_DEFAULT_AUDIO_CHANNELS];
    memset(buf, 0, sizeof(buf));

    uint8_t audio_count = 0;
    _Bool record_on = 0;
#ifdef AUDIO_FILTERING
    debug("Audio Filtering");
#ifdef ALC_LOOPBACK_CAPTURE_SAMPLES
    debug(" and Echo cancellation");
#endif
    debug(" enabled in this build\n");
#endif

    debug("frame size: %u\n", perframe);

    device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
    if (device_list) {
        audio_device = (void*)device_list;
        debug("uTox audio input device list:\n");
        while(*device_list) {
            debug("\t%s\n", device_list);
            postmessage(AUDIO_IN_DEVICE, UI_STRING_ID_INVALID, 0, (void*)device_list);
            device_list += strlen(device_list) + 1;
        }
    }

    postmessage(AUDIO_IN_DEVICE, STR_AUDIO_IN_NONE, 0, NULL);
    audio_detect();

    if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT")) {
        device_list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
    } else {
        device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
    }

    if(device_list) {
        output_device = device_list;
        debug("uTox audio output device list:\n");
        while(*device_list) {
            debug("\t%s\n", device_list);
            postmessage(AUDIO_OUT_DEVICE, 0, 0, (void*)device_list);
            device_list += strlen(device_list) + 1;
        }
    }

    device_out = alcOpenDevice(output_device);
    if(!device_out) {
        debug("alcOpenDevice() failed\n");
        return;
    }

    int attrlist[] = {  ALC_FREQUENCY, UTOX_DEFAULT_SAMPLE_RATE_A,
                        ALC_INVALID
                     };

    context = alcCreateContext(device_out, attrlist);
    if(!alcMakeContextCurrent(context)) {
        debug("alcMakeContextCurrent() failed\n");
        alcCloseDevice(device_out);
        return;
    }

    alGenSources(countof(source), source);
    /* TODO hacky fix. This source list should be a VLA with a way to link sources to friends.
     * NO SRSLY don't leave this like this! */
    static ALuint ringSrc[UTOX_MAX_NUM_FRIENDS];
    alGenSources(UTOX_MAX_NUM_FRIENDS, ringSrc);

    /* Create buffer to store samples */
    ALuint RingBuffer;
    alGenBuffers(1, &RingBuffer);

    {   /* wrapped to keep this data on the stack... I think... */
        float frequency1 = 441.f;
        float frequency2 = 882.f;
        int seconds = 4;
        unsigned sample_rate = 22050;
        size_t buf_size = seconds * sample_rate * 2; //16 bit (2 bytes per sample)
        int16_t *samples = malloc(buf_size * sizeof(int16_t));
        if (!samples)
            return;

        /*Generate an electronic ringer sound that quickly alternates between two frequencies*/
        int index = 0;
        for(index = 0; index < buf_size; ++index) {
            if ((index / (sample_rate)) % 4 < 2 ) {//4 second ring cycle, first 2 secondsring, the rest(2 seconds) is silence
                if((index / 1000) % 2 == 1) {
                    samples[index] = 5000 * sin((2.0 * 3.1415926 * frequency1) / sample_rate * index); //5000=amplitude(volume level). It can be from zero to 32700
                } else {
                    samples[index] = 5000 * sin((2.0 * 3.1415926 * frequency2) / sample_rate * index);
                }
            } else {
                samples[index] = 0;
            }
        }

        alBufferData(RingBuffer, AL_FORMAT_MONO16, samples, buf_size, sample_rate);
        free(samples);
    }

    {
        unsigned int i;
        for (i = 0; i < UTOX_MAX_NUM_FRIENDS; ++i) {
            alSourcei(ringSrc[i], AL_LOOPING, AL_TRUE);
            alSourcei(ringSrc[i], AL_BUFFER, RingBuffer);
        }
    }
    Filter_Audio *f_a = NULL;

    audio_thread_init = 1;

    int16_t *preview_buffer = NULL;
    unsigned int preview_buffer_index = 0;
#define PREVIEW_BUFFER_SIZE (UTOX_DEFAULT_SAMPLE_RATE_A / 2)

    while(1) {
        if(audio_thread_msg) {
            TOX_MSG *m = &audio_msg;
            if(!m->msg) {
                break;
            }

            switch(m->msg) {
            case AUDIO_SET_INPUT: {
                audio_device = m->data;

                if(record_on) {
                    alccapturestop(device_in);
                    alccaptureclose(device_in);
                }

                if(audio_count) {
                    device_in = alcopencapture(audio_device);
                    if(!device_in) {
                        record_on = 0;
                    } else {
                        alccapturestart(device_in);
                        record_on = 1;
                    }
                }

                debug("set audio in\n");
                break;
            }

            case AUDIO_SET_OUTPUT: {
                output_device = m->data;

                ALCdevice *device = alcOpenDevice(output_device);
                if(!device) {
                    debug("alcOpenDevice() failed\n");
                    break;
                }

                ALCcontext *con = alcCreateContext(device, NULL);
                if(!alcMakeContextCurrent(con)) {
                    debug("alcMakeContextCurrent() failed\n");
                    alcCloseDevice(device);
                    break;
                }

                alcDestroyContext(context);
                alcCloseDevice(device_out);
                context = con;
                device_out = device;

                alGenSources(countof(source), source);
                alGenSources(MAX_CALLS, ringSrc);

                Tox *tox = toxav_get_tox(av);
                uint32_t num_chats = tox_count_chatlist(tox);

                if (num_chats != 0) {
                    int32_t chats[num_chats];
                    uint32_t max = tox_get_chatlist(tox, chats, num_chats);

                    unsigned int i;
                    for (i = 0; i < max; ++i) {
                        if (tox_group_get_type(tox, chats[i]) == TOX_GROUPCHAT_TYPE_AV) {
                            GROUPCHAT *g = &group[chats[i]];
                            alGenSources(g->peers, g->source);
                        }
                    }
                }

                debug("set audio out\n");
                break;
            }

            case AUDIO_PREVIEW_START: {
                preview = 1;
                audio_count++;
                preview_buffer = calloc(PREVIEW_BUFFER_SIZE, 2);
                preview_buffer_index = 0;
                if(!record_on) {
                    device_in = alcopencapture(audio_device);
                    if(device_in) {
                        alccapturestart(device_in);
                        record_on = 1;
                        debug("Starting Audio Preview\n");
                    }
                }
                break;
            }

            case AUDIO_START: {
                audio_count++;
                if(!record_on) {
                    device_in = alcopencapture(audio_device);
                    if(device_in) {
                        alccapturestart(device_in);
                        record_on = 1;
                        debug("Listening to audio\n");
                        yieldcpu(20);
                    }
                }
                break;
            }

            case GROUP_AUDIO_CALL_START: {
                break; // TODO, new groups API
                audio_count++;
                groups_audio[m->param1] = 1;
                if(!record_on) {
                    device_in = alcopencapture(audio_device);
                    if(device_in) {
                        alccapturestart(device_in);
                        record_on = 1;
                        debug("Starting Audio GroupCall\n");
                    }
                }
                break;
            }

            case AUDIO_PREVIEW_END: {
                preview = 0;
                audio_count--;
                free(preview_buffer);
                preview_buffer = NULL;
                if(!audio_count && record_on) {
                    alccapturestop(device_in);
                    alccaptureclose(device_in);
                    record_on = 0;
                    debug("Audio Preview Stopped\n");
                }
                break;
            }

            case AUDIO_END: {
                if(!call[m->param1]) {
                    break;
                }
                call[m->param1] = 0;
                audio_count--;
                if(!audio_count && record_on) {
                    alccapturestop(device_in);
                    alccaptureclose(device_in);
                    record_on = 0;
                    debug("stop\n");
                }
                break;
            }

            case GROUP_AUDIO_CALL_END: {
                break; // TODO, new groups API
                if(!groups_audio[m->param1]) {
                    break;
                }
                audio_count--;
                groups_audio[m->param1] = 0;
                if(!audio_count && record_on) {
                    alccapturestop(device_in);
                    alccaptureclose(device_in);
                    record_on = 0;
                    debug("stop\n");
                }
                break;
            }

            case AUDIO_PLAY_RINGTONE: {
                if(!audible_notifications_enabled) {
                    break;
                }
                alSourcePlay(ringSrc[m->param1]);
                break;
            }

            case AUDIO_STOP_RINGTONE: {
                ALint state;
                alGetSourcei(ringSrc[m->param1], AL_SOURCE_STATE, &state);
                if(state == AL_PLAYING) {
                    alSourceStop(ringSrc[m->param1]);
                }
                break;
            }
            }

            audio_thread_msg = 0;
        }

        // TODO move this code to filter_audio.c
#ifdef AUDIO_FILTERING
        if (!f_a && audio_filtering_enabled) {
            f_a = new_filter_audio(UTOX_DEFAULT_SAMPLE_RATE_A);
            if (!f_a) {
                audio_filtering_enabled = 0;
                debug("filter audio failed\n");
            } else {
                debug("filter audio on\n");
            }
        } else if (f_a && !audio_filtering_enabled) {
            kill_filter_audio(f_a);
            f_a = NULL;
            debug("filter audio off\n");
        }
#else
        if (audio_filtering_enabled) {
            audio_filtering_enabled = 0;
        }
#endif

        _Bool sleep = 1;

        if(record_on) {
            ALint samples;
            _Bool frame = 0;
            /* If we have a device_in we're on linux so we can just call OpenAL, otherwise we're on something else so
             * we'll need to call audio_frame() to add to the buffer for us. */
            if (device_in == (void*)1) {
                frame = audio_frame((void*)buf);
                if (frame) {
                    /* We have an audio frame to use, continue without sleeping. */
                    sleep = 0;
                }
            } else {
                alcGetIntegerv(device_in, ALC_CAPTURE_SAMPLES, sizeof(samples), &samples);
                if(samples >= perframe) {
                    alcCaptureSamples(device_in, buf, perframe);
                    frame = 1;
                    if (samples >= perframe * 2) {
                        sleep = 0;
                    }
                }
            }

#ifdef AUDIO_FILTERING
#ifdef ALC_LOOPBACK_CAPTURE_SAMPLES
            if (f_a && audio_filtering_enabled) {
                alcGetIntegerv(device_out, ALC_LOOPBACK_CAPTURE_SAMPLES, sizeof(samples), &samples);
                if(samples >= perframe) {
                    int16_t buffer[perframe];
                    alcCaptureSamplesLoopback(device_out, buffer, perframe);
                    pass_audio_output(f_a, buffer, perframe);
                    set_echo_delay_ms(f_a, UTOX_DEFAULT_FRAME_A);
                    if (samples >= perframe * 2) {
                        sleep = 0;
                    }
                }
            }
#endif
#endif

            if (frame) {
                _Bool voice = 1;
#ifdef AUDIO_FILTERING
                if (f_a) {
                    int ret = filter_audio(f_a, (int16_t*)buf, perframe);

                    if (ret == -1) {
                        debug("filter audio error\n");
                    }

                    if (ret == 0) {
                        voice = 0;
                    }
                }
#endif

                /* If push to talk, we don't have to do anything */
                if (!check_ptt_key()) {
                    voice = 0; //PTT is up, send nothing.
                }

                if (preview) {
                    if (preview_buffer_index + perframe > PREVIEW_BUFFER_SIZE) {
                        preview_buffer_index = 0;
                    }

                    sourceplaybuffer(0, preview_buffer + preview_buffer_index, perframe, UTOX_DEFAULT_AUDIO_CHANNELS, UTOX_DEFAULT_SAMPLE_RATE_A);
                    if (voice) {
                        memcpy(preview_buffer + preview_buffer_index, buf, perframe * sizeof(int16_t));
                    } else {
                        memset(preview_buffer + preview_buffer_index, 0, perframe * sizeof(int16_t));
                    }
                    preview_buffer_index += perframe;
                }

                if (voice) {
                    int i, active_call_count = 0;
                    for(i = 0; i < UTOX_MAX_NUM_FRIENDS; i++) {
                        if( UTOX_SEND_AUDIO(i) ) {
                            active_call_count++;
                            TOXAV_ERR_SEND_FRAME error = 0;
                            toxav_audio_send_frame(av, friend[i].number, (const int16_t *)buf, perframe, UTOX_DEFAULT_AUDIO_CHANNELS, UTOX_DEFAULT_SAMPLE_RATE_A, &error);
                            if (error) {
                                debug("toxav_send_audio error friend == %i, error ==  %i\n", i, error);
                            } else {
                                // debug("Send a frame to friend %i\n",i);
                                if (active_call_count >= UTOX_MAX_CALLS) {
                                    debug("We're calling more peers than allowed by UTOX_MAX_CALLS, This is a bug\n");
                                    break;
                                }
                            }
                        }
                    }

                    // TODO REMOVED until new groups api can be implemented.
                    /*Tox *tox = toxav_get_tox(av);
                    uint32_t num_chats = tox_count_chatlist(tox);

                    if (num_chats != 0) {
                        int32_t chats[num_chats];
                        uint32_t max = tox_get_chatlist(tox, chats, num_chats);
                        for (i = 0; i < max; ++i) {
                            if (groups_audio[chats[i]]) {
                                toxav_group_send_audio(tox, chats[i], (int16_t *)buf, perframe, UTOX_DEFAULT_AUDIO_CHANNELS, UTOX_DEFAULT_SAMPLE_RATE_A);
                            }
                        }
                    }*/
                }
            }
        }

        if (sleep) {
            yieldcpu(5);
        }
    }

    utox_filter_audio_kill(f_a);

    //missing some cleanup ?
    alDeleteSources(MAX_CALLS, ringSrc);
    alDeleteSources(countof(source), source);
    alDeleteBuffers(1, &RingBuffer);

    if(device_in) {
        if(record_on) {
            alcCaptureStop(device_in);
        }
        alcCaptureCloseDevice(device_in);
    }

    alcMakeContextCurrent(NULL);
    alcDestroyContext(context);
    alcCloseDevice(device_out);

    audio_thread_msg = 0;
    audio_thread_init = 0;
    debug("UTOX AUDIO:\tClean thread exit!\n");
}