Beispiel #1
0
void CToxProto::LoadChatRoomList(void*)
{
	uint32_t count = tox_count_chatlist(toxThread->Tox());
	if (count == 0)
	{
		debugLogA(__FUNCTION__": your group chat list is empty");
		return;
	}
	int32_t *groupChats = (int32_t*)mir_alloc(count * sizeof(int32_t));
	tox_get_chatlist(toxThread->Tox(), groupChats, count);
	for (uint32_t i = 0; i < count; i++)
	{
		int32_t groupNumber = groupChats[i];
		int type = tox_group_get_type(toxThread->Tox(), groupNumber);
		if (type == TOX_GROUPCHAT_TYPE_AV)
		{
			continue;
		}
		MCONTACT hContact = AddChatRoom(groupNumber);
		if (hContact)
		{
			uint8_t title[TOX_MAX_NAME_LENGTH] = { 0 };
			tox_group_get_title(toxThread->Tox(), groupNumber, title, TOX_MAX_NAME_LENGTH);
			setWString(hContact, "Nick", ptrT(mir_utf8decodeT((char*)title)));
		}
	}
	mir_free(groupChats);
}
Beispiel #2
0
Datei: tox.c Projekt: Boerde/uTox
void tox_message(uint8_t tox_message_id, uint16_t param1, uint16_t param2, void *data)
{
    switch(tox_message_id) {
    case DHT_CONNECTED: {
        /* param1: connection status (1 = connected, 0 = disconnected)
         */
        tox_connected = param1;
        redraw();
        break;
    }

    case DNS_RESULT: {
        /* param1: result (0 = failure, 1 = success)
         * data: resolved tox id (if successful)
         */
        if(param1) {
            friend_addid(data, edit_addmsg.data, edit_addmsg.length);
        } else {
            addfriend_status = ADDF_BADNAME;
        }
        free(data);

        redraw();
        break;
    }

    case OPEN_FILES: {
        tox_postmessage(TOX_SENDFILES, param1, param2, data);
        break;
    }

    case SAVE_FILE: {
        tox_postmessage(TOX_ACCEPTFILE, param1, param2, data);
        break;
    }

    case NEW_AUDIO_IN_DEVICE: {
        if(UI_STRING_ID_INVALID == param1) {
            list_dropdown_add_hardcoded(&dropdown_audio_in, data, data);
        } else {
            list_dropdown_add_localized(&dropdown_audio_in, param1, data);
        }

        if (loaded_audio_in_device != 0 && (dropdown_audio_in.dropcount - 1) == loaded_audio_in_device) {
            toxaudio_postmessage(AUDIO_SET_INPUT, 0, 0, data);
            dropdown_audio_in.selected = loaded_audio_in_device;
            loaded_audio_in_device = 0;
        }

        break;
    }

    case NEW_AUDIO_OUT_DEVICE: {
        list_dropdown_add_hardcoded(&dropdown_audio_out, data, data);

        if (loaded_audio_out_device != 0 && (dropdown_audio_out.dropcount - 1) == loaded_audio_out_device) {
            toxaudio_postmessage(AUDIO_SET_OUTPUT, 0, 0, data);
            dropdown_audio_out.selected = loaded_audio_out_device;
            loaded_audio_out_device = 0;
        }

        break;
    }

    case NEW_VIDEO_DEVICE: {
        if(UI_STRING_ID_INVALID == param1) {
            // Device name is a hardcoded string.
            // data is a pointer to a buffer, that contains device handle pointer,
            // followed by device name string.
            list_dropdown_add_hardcoded(&dropdown_video, data + sizeof(void*), *(void**)data);
        } else {
            // Device name is localized with param1 containing UI_STRING_ID.
            // data is device handle pointer.
            list_dropdown_add_localized(&dropdown_video, param1, data);
        }
        //param2 == true, if this device will be chosen by video detecting code.
        if(param2) {
            dropdown_video.selected = dropdown_video.over = (dropdown_video.dropcount - 1);
        }
        break;
    }

    case FRIEND_REQUEST: {
        /* data: pointer to FRIENDREQ structure
         */
        list_addfriendreq(data);
        break;
    }

    case FRIEND_ADD: {
        /* confirmation that friend has been added to friend list (add) */
        if(param1) {
            /* friend was not added */
            addfriend_status = param2;
        } else {
            /* friend was added */
            edit_addid.length = 0;
            edit_addmsg.length = 0;

            FRIEND *f = &friend[param2];
            friends++;

            f->msg.scroll = 1.0;

            memcpy(f->cid, data, sizeof(f->cid));

            friend_setname(f, NULL, 0);

            list_addfriend(f);

            addfriend_status = ADDF_SENT;

        }

        free(data);
        redraw();
        break;
    }

    case FRIEND_ACCEPT: {
        /* confirmation that friend has been added to friend list (accept) */
        if(!param1) {
            FRIEND *f = &friend[param2];
            FRIENDREQ *req = data;
            friends++;

            memcpy(f->cid, req->id, sizeof(f->cid));
            friend_setname(f, NULL, 0);

            list_addfriend2(f, req);
            redraw();
        }

        free(data);
        break;
    }

    case FRIEND_DEL: {
        friend_free(data);
        friends--;
        break;
    }

    case FRIEND_MESSAGE: {
        friend_addmessage(&friend[param1], data);
        redraw();
        break;
    }

#define updatefriend(fp) redraw();//list_draw(); if(sitem && fp == sitem->data) {ui_drawmain();}
#define updategroup(gp) redraw();//list_draw(); if(sitem && gp == sitem->data) {ui_drawmain();}

    case FRIEND_NAME: {
        FRIEND *f = &friend[param1];
        friend_setname(f, data, param2);
        updatefriend(f);
        break;
    }

    case FRIEND_STATUS_MESSAGE: {
        FRIEND *f = &friend[param1];
        free(f->status_message);
        f->status_length = param2;
        f->status_message = data;
        updatefriend(f);
        break;
    }

    case FRIEND_STATUS: {
        FRIEND *f = &friend[param1];
        f->status = param2;
        updatefriend(f);
        break;
    }

    case FRIEND_TYPING: {
        FRIEND *f = &friend[param1];
        friend_set_typing(f, param2);
        updatefriend(f);
        break;
    }

    case FRIEND_ONLINE: {
        FRIEND *f = &friend[param1];
        f->online = param2;
        if(!f->online) {
            friend_set_typing(f, 0);
        }
        updatefriend(f);
        break;
    }

    case FRIEND_CALL_STATUS: {
        /* param1: friend id
           param2: call id
           data: integer call status
         */
        FRIEND *f = &friend[param1];
        uint8_t status = (size_t)data;
        if(status == CALL_NONE && (f->calling == CALL_OK || f->calling == CALL_OK_VIDEO)) {
            toxaudio_postmessage(AUDIO_CALL_END, param2, 0, NULL);
            if(f->calling == CALL_OK_VIDEO) {
                toxvideo_postmessage(VIDEO_CALL_END, param2, 0, NULL);
            }

            video_end(param1 + 1);
        }

        f->calling = status;
        f->callid = param2;

        if(status == CALL_OK) {
            toxaudio_postmessage(AUDIO_CALL_START, param2, 0, NULL);
        }

        call_notify(f, status);

        updatefriend(f);
        break;
    }

    case FRIEND_CALL_VIDEO: {
        /* param1: friend id
           param2: call id
         */
        FRIEND *f = &friend[param1];
        f->calling = CALL_OK_VIDEO;
        f->callid = param2;
        updatefriend(f);

        toxvideo_postmessage(VIDEO_CALL_START, param2, 0, NULL);
        toxaudio_postmessage(AUDIO_CALL_START, param2, 0, NULL);

        f->call_width = 640;
        f->call_height = 480;

        video_begin(param1 + 1, f->name, f->name_length, 640, 480);

        call_notify(f, CALL_OK_VIDEO);

        break;
    }

    case FRIEND_CALL_MEDIACHANGE: {
        /* param1: friend id
           param2: call id
           data: zero = audio, nonzero = audio/video
         */
        FRIEND *f = &friend[param1];

        if(!data) {
            video_end(param1 + 1);
        } else {
            f->call_width = 640;
            f->call_height = 480;

            video_begin(param1 + 1, f->name, f->name_length, 640, 480);
        }
        break;
    }

    case FRIEND_CALL_START_VIDEO: {
        /* param1: friend id
           param2: call id
         */
        FRIEND *f = &friend[param1];
        if(f->calling == CALL_OK) {
            f->calling = CALL_OK_VIDEO;
            toxvideo_postmessage(VIDEO_CALL_START, param2, 0, NULL);
            updatefriend(f);
        }
        break;
    }

    case FRIEND_CALL_STOP_VIDEO: {
        /* param1: friend id
           param2: call id
         */
        FRIEND *f = &friend[param1];
        if(f->calling == CALL_OK_VIDEO) {
            f->calling = CALL_OK;
            toxvideo_postmessage(VIDEO_CALL_END, param2, 0, NULL);
            updatefriend(f);
        }
        break;
    }

    case FRIEND_VIDEO_FRAME: {
        /* param1: friend id
           param2: call id
           data: frame data
         */
        uint16_t *image = data;
        FRIEND *f = &friend[param1];

        _Bool b = (image[0] != f->call_width || image[1] != f->call_height);
        if(b) {
            f->call_width = image[0];
            f->call_height = image[1];
        }
        video_frame(param1 + 1, (void*)&image[2], image[0], image[1], b);
        free(image);
        break;
    }

    case PREVIEW_FRAME_NEW:
    case PREVIEW_FRAME: {
        if(video_preview) {
            video_frame(0, data, param1, param2, tox_message_id == PREVIEW_FRAME_NEW);
        }
        free(data);
        break;
    }

    case FRIEND_FILE_IN_NEW:
    case FRIEND_FILE_IN_NEW_INLINE: {
        FRIEND *f = &friend[param1];
        FILE_T *ft = &f->incoming[param2];
        _Bool inline_png = (tox_message_id == FRIEND_FILE_IN_NEW_INLINE);

        MSG_FILE *msg = malloc(sizeof(MSG_FILE));
        msg->author = 0;
        msg->msg_type = MSG_TYPE_FILE;
        msg->filenumber = param2;
        msg->status = (inline_png ? FILE_OK : FILE_PENDING);
        msg->name_length = (ft->name_length > sizeof(msg->name)) ? sizeof(msg->name) : ft->name_length;
        msg->size = ft->total;
        msg->progress = 0;
        msg->speed = 0;
        msg->inline_png = inline_png;
        msg->path = NULL;
        memcpy(msg->name, ft->name, msg->name_length);

        friend_addmessage(f, msg);
        ft->chatdata = msg;

        file_notify(f, msg);

        updatefriend(f);
        break;
    }

    case FRIEND_FILE_OUT_NEW:
    case FRIEND_FILE_OUT_NEW_INLINE: {
        FRIEND *f = &friend[param1];
        FILE_T *ft = &f->outgoing[param2];
        _Bool inline_png = (tox_message_id == FRIEND_FILE_OUT_NEW_INLINE);

        MSG_FILE *msg = malloc(sizeof(MSG_FILE));
        msg->author = 1;
        msg->msg_type = MSG_TYPE_FILE;
        msg->filenumber = param2;
        msg->status = FILE_PENDING;
        msg->name_length = (ft->name_length >= sizeof(msg->name)) ? sizeof(msg->name) - 1 : ft->name_length;
        msg->size = ft->total;
        msg->progress = 0;
        msg->speed = 0;
        msg->inline_png = inline_png;
        msg->path = NULL;
        memcpy(msg->name, ft->name, msg->name_length);
        msg->name[msg->name_length] = 0;

        friend_addmessage(f, msg);
        ft->chatdata = msg;

        updatefriend(f);
        break;
    }

    case FRIEND_FILE_IN_STATUS: {
        FRIEND *f = &friend[param1];
        FILE_T *ft = &f->incoming[param2];

        MSG_FILE *msg = ft->chatdata;
        msg->status = (size_t)data;

        file_notify(f, msg);

        updatefriend(f);
        break;
    }

    case FRIEND_FILE_OUT_STATUS: {
        FRIEND *f = &friend[param1];
        FILE_T *ft = &f->outgoing[param2];

        MSG_FILE *msg = ft->chatdata;
        msg->status = (size_t)data;

        file_notify(f, msg);

        updatefriend(f);
        break;
    }

    case FRIEND_FILE_IN_DONE: {
        FRIEND *f = &friend[param1];
        FILE_T *ft = &f->incoming[param2];

        MSG_FILE *msg = ft->chatdata;
        msg->status = FILE_DONE;
        msg->path = data;

        file_notify(f, msg);

        updatefriend(f);
        break;
    }

    case FRIEND_FILE_IN_DONE_INLINE: {
        FRIEND *f = &friend[param1];
        FILE_T *ft = &f->incoming[param2];

        MSG_FILE *msg = ft->chatdata;
        msg->status = FILE_DONE;
        msg->path = data;

        friend_recvimage(f, data, msg->size);

        file_notify(f, msg);

        updatefriend(f);
        break;
    }

    case FRIEND_FILE_OUT_DONE: {
        FRIEND *f = &friend[param1];
        FILE_T *ft = &f->outgoing[param2];

        MSG_FILE *msg = ft->chatdata;
        msg->status = FILE_DONE;
        msg->path = data;

        file_notify(f, msg);

        updatefriend(f);
        break;
    }

    case FRIEND_FILE_IN_PROGRESS: {
        FRIEND *f = &friend[param1];
        FILE_T *ft = &f->incoming[param2];
        FILE_PROGRESS *p = data;

        MSG_FILE *msg = ft->chatdata;
        msg->progress = p->bytes;
        msg->speed = p->speed;

        free(p);

        updatefriend(f);
        break;
    }

    case FRIEND_FILE_OUT_PROGRESS: {
        FRIEND *f = &friend[param1];
        FILE_T *ft = &f->outgoing[param2];
        FILE_PROGRESS *p = data;

        MSG_FILE *msg = ft->chatdata;
        msg->progress = p->bytes;
        msg->speed = p->speed;

        free(p);

        updatefriend(f);
        break;
    }

    case GROUP_ADD: {
        GROUPCHAT *g = &group[param1];
        g->name_length = snprintf((char*)g->name, sizeof(g->name), "Groupchat #%u", param1);
        g->topic_length = sizeof("Drag friends to invite them") - 1;
        memcpy(g->topic, "Drag friends to invite them", sizeof("Drag friends to invite them") - 1);
        g->msg.scroll = 1.0;
        g->type = tox_group_get_type(data, param1);
        list_addgroup(g);
        redraw();
        break;
    }

    case GROUP_MESSAGE: {
        GROUPCHAT *g = &group[param1];

        message_add(&messages_group, data, &g->msg);

        if(sitem && g == sitem->data) {
            redraw();//ui_drawmain();
        }

        break;
    }

    case GROUP_PEER_DEL: {
        GROUPCHAT *g = &group[param1];

        if (param2 > MAX_GROUP_PEERS) //TODO: dynamic arrays.
            break;

        if(g->peername[param2]) {
            free(g->peername[param2]);
            g->peername[param2] = NULL;
        }

        g->peers--;
        g->peername[param2] = g->peername[g->peers];
        g->peername[g->peers] = NULL;

        if (g->type == TOX_GROUPCHAT_TYPE_AV) {
            g->last_recv_audio[param2] = g->last_recv_audio[g->peers];
            g->last_recv_audio[g->peers] = 0;
            group_av_peer_remove(g, param2);
            g->source[param2] = g->source[g->peers];
        }

        if (g->peers == g->our_peer_number) {
            g->our_peer_number = param2;
        }

        g->topic_length = snprintf((char*)g->topic, sizeof(g->topic), "%u users in chat", g->peers);

        updategroup(g);

        break;
    }

    case GROUP_PEER_ADD:
    case GROUP_PEER_NAME: {
        GROUPCHAT *g = &group[param1];

        if (param2 > MAX_GROUP_PEERS) //TODO: dynamic arrays.
            break;

        if(g->peername[param2]) {
            free(g->peername[param2]);
        }

        if(tox_message_id == GROUP_PEER_ADD) {
            if (g->type == TOX_GROUPCHAT_TYPE_AV) {
                group_av_peer_add(g, param2);
            }

            if (tox_group_peernumber_is_ours(data, param1, param2)) {
                g->our_peer_number = param2;
            }

            uint8_t *n = malloc(10);
            n[0] = 9;
            memcpy(n + 1, "<unknown>", 9);
            data = n;
            g->peers++;

        }

        g->peername[param2] = data;

        g->topic_length = snprintf((char*)g->topic, sizeof(g->topic), "%u users in chat", g->peers);

        updategroup(g);

        break;
    }

    case GROUP_TITLE: {
        GROUPCHAT *g = &group[param1];

        if (param2 > sizeof(g->name)) {
            memcpy(g->name, data, sizeof(g->name));
            g->name_length = sizeof(g->name);
        } else {
            memcpy(g->name, data, param2);
            g->name_length = param2;
        }

        free(data);
        updategroup(g);
        break;
    }

    case GROUP_AUDIO_START: {
        GROUPCHAT *g = &group[param1];

        if (g->type == TOX_GROUPCHAT_TYPE_AV) {
            g->audio_calling = 1;
            toxaudio_postmessage(GROUP_AUDIO_CALL_START, param1, 0, NULL);
            updategroup(g);
        }
        break;
    }
    case GROUP_AUDIO_END: {
        GROUPCHAT *g = &group[param1];

        if (g->type == TOX_GROUPCHAT_TYPE_AV) {
            g->audio_calling = 0;
            toxaudio_postmessage(GROUP_AUDIO_CALL_END, param1, 0, NULL);
            updategroup(g);
        }
        break;
    }

    case GROUP_UPDATE: {
        GROUPCHAT *g = &group[param1];
        updategroup(g);

        break;
    }
    }
Beispiel #3
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");
}
Beispiel #4
0
/**
 * @brief Check, that group has audio or video stream
 * @param groupId Id of group to check
 * @return True for AV groups, false for text-only groups
 */
bool CoreAV::isGroupAvEnabled(int groupId) const
{
    return tox_group_get_type(Core::getInstance()->tox, groupId) == TOX_GROUPCHAT_TYPE_AV;
}
Beispiel #5
0
bool Core::isGroupAvEnabled(int groupId)
{
    return tox_group_get_type(tox, groupId) == TOX_GROUPCHAT_TYPE_AV;
}