<commit_before>#![feature(globs)]
extern crate tox;
extern crate libc;

use tox::core::*;
use tox::av::Event::*;

use std::sync::mpsc::{Select};
use std::collections::{HashMap};

fn main() {
    let tox = Tox::new(ToxOptions::new()).unwrap();
    let av = tox.av(2).unwrap();

    let mut audiomap = HashMap::new();

    let ids = [
        ("192.168.3.11"   , 33445 , "951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F"),
        ("172.16.17.32"   , 33445 , "A9D98212B3F972BD11DA52BEB0658C326FCCC1BFD49F347F9C2D3D8B61E1B927"),
        ("192.168.127.12"   , 33445 , "04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F"),
        ("192.168.127.12"   , 33445 , "A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074"),
        ("192.168.3.11"  , 33445 , "7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029"),
        ("172.16.31.10" , 33445 , "F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67"),
        ("172.16.17.32"   , 33445 , "B98A2CEAA6C6A2FADC2C3632D284318B60FE5375CCB41EFA081AB67F500C1B0B"),
        ("192.168.3.11"  , 33445 , "4B2C19E924972CB9B57732FB172F8A8604DE13EEDA2A6234E348983344B23057"),
        ("172.16.58.3"   , 33445 , "7BE3951B97CA4B9ECDDA768E8C52BA19E9E2690AB584787BF4C90E04DBB75111"),
        ("192.168.127.12"     , 443   , "2A4B50D1D525DA2E669592A20C327B5FAD6C7E5962DC69296F9FEC77C4436E4E"),
        ("172.16.31.10"   , 443   , "8CD087E31C67568103E8C2A28653337E90E6B8EDA0D765D57C6B5172B4F1F04C"),
    ];

    for &(ip, port, id) in ids.iter() {
        let id = id.parse().unwrap();
        tox.bootstrap_from_address(ip.to_string(), port, box id).unwrap();
    }

    let groupbot = "56A1ADE4B65B86BCD51CC73E2CD4E542179F47959FE3E0E21B4B0ACDADE51855D34D34D37CB5".parse().unwrap();
    tox.set_name("test".to_string()).ok().unwrap();
    tox.add_friend(box groupbot, "Hello".to_string()).ok().unwrap();

    let sel = Select::new();
    let mut tox_rx = sel.handle(tox.events());
    let mut av_rx = sel.handle(av.events());
    unsafe {
        tox_rx.add();
        av_rx.add();
    }

    loop {
        sel.wait();

        while let Ok(ev) = tox.events().try_recv() {
            match ev {
                FriendRequest(..)       => println!("FriendRequest(..)       "),
                FriendMessage(..)       => println!("FriendMessage(..)       "),
                FriendAction(..)        => println!("FriendAction(..)        "),
                NameChange(..)          => println!("NameChange(..)          "),
                StatusMessage(id, _)       => {
                    println!("StatusMessage(..)       ");
                    let _ = tox.send_message(id, "invite".to_string());
                },
                UserStatusVar(..)       => println!("UserStatusVar(..)       "),
                TypingChange(..)        => println!("TypingChange(..)        "),
                ReadReceipt(..)         => println!("ReadReceipt(..)         "),
                ConnectionStatusVar(..) => println!("ConnectionStatusVar(..) "),
                GroupInvite(id, ty, data)  => {
                    println!("GroupInvite(_, {}, _)         ", ty);
                    match ty {
                        GroupchatType::Text => tox.join_groupchat(id, data).unwrap(),
                        GroupchatType::Av => av.join_av_groupchat(id, data).unwrap(),
                    };
                },
                GroupMessage(_, _, msg) => println!("GroupMessage(_, _, {})", msg),
                GroupNamelistChange(gnum, pnum, change) => {
                    println!("GroupNamelistChange(..) ");
                    if change == ChatChange::PeerDel {
                        audiomap.remove(&(gnum, pnum));
                    }
                },
                FileSendRequest(..)     => println!("FileSendRequest(..)     "),
                FileControl(..)         => println!("FileControl(..)         "),
                FileData(..)            => println!("FileData(..)            "),
                AvatarInfo(..)          => println!("AvatarInfo(..)          "),
                AvatarData(..)          => println!("AvatarData(..)          "),
            }
        }

        while let Ok(ev) = av.events().try_recv() {
            match ev {
                Invite(..)             => println!("Av::Invite(..)"),
                Ringing(..)            => println!("Av::Ringing(..)"),
                Start(..)              => println!("Av::Start(..)"),
                Cancel(..)             => println!("Av::Cancel(..)"),
                Reject(..)             => println!("Av::Reject(..)"),
                End(..)                => println!("Av::End(..)"),
                RequestTimeout(..)     => println!("Av::RequestTimeout(..)"),
                PeerTimeout(..)        => println!("Av::PeerTimeout(..)"),
                PeerCsChange(..)       => println!("Av::PeerCsChange(..)"),
                SelfCsChange(..)       => println!("Av::SelfCsChange(..)"),
                GroupAudio(gnum, pnum, bit)  => {
                    //println!("Av::GroupAudio(..) SR: {} CH: {} N: {}", bit.sample_rate,
                    //         bit.channels, bit.samples);
                    if audiomap.get(&(gnum, pnum)).is_none() {
                        audiomap.insert((gnum, pnum), alsa::open().unwrap());
                    }
                    let alsa = *audiomap.get(&(gnum, pnum)).unwrap();
                    alsa::write(alsa, &bit).unwrap();
                }
            }
        }
    }
}

mod alsa {
    use libc::{c_int, c_uint, c_void, c_ulong, c_long, c_char, puts, EPIPE};
    use tox::av::{AudioBit};

    pub const RATE: u32 = 48000;
    pub const CHANNELS: u8 = 2;

    #[repr(C)]
    pub struct snd_pcm_t;

    pub const SND_PCM_STREAM_PLAYBACK: c_uint = 0;
    pub const SND_PCM_FORMAT_S16_LE: c_uint = 2;
    pub const SND_PCM_ACCESS_RW_INTERLEAVED: c_int = 3;

    #[link(name = "asound")]
    extern {
        fn snd_pcm_open(pcm: *mut *mut snd_pcm_t, name: *const u8, stream: c_uint,
                        mode: c_int) -> c_int;
        fn snd_pcm_set_params(pcm: *mut snd_pcm_t, format: c_uint, access: c_int,
                              channels: c_uint, rate: c_uint, soft_resample: c_int,
                              latency: c_uint) -> c_int;
        fn snd_pcm_writei(pcm: *mut snd_pcm_t, buffer: *const c_void,
                          size: c_ulong) -> c_long;
        fn snd_strerror(e: c_int) -> *const c_char;
        fn snd_pcm_prepare(pcm: *mut snd_pcm_t) -> c_int;
    }

    pub fn open() -> Option<*mut snd_pcm_t> {
        unsafe {
            let mut ptr = 0 as *mut snd_pcm_t;
            let e = snd_pcm_open(&mut ptr, b"default\0".as_ptr(), SND_PCM_STREAM_PLAYBACK,
                                 0);
            if e != 0 {
                puts(snd_strerror(e));
                return None;
            }
            let e = snd_pcm_set_params(ptr, SND_PCM_FORMAT_S16_LE,
                                  SND_PCM_ACCESS_RW_INTERLEAVED, CHANNELS as c_uint,
                                  RATE as c_uint, 1, 500000);
            if e != 0 {
                puts(snd_strerror(e));
                return None;
            }
            Some(ptr)
        }
    }

    pub fn write(p: *mut snd_pcm_t, bit: &AudioBit) -> Option<()> {
        unsafe {
            if bit.sample_rate != RATE || bit.channels != CHANNELS {
                return None;
            }
            let e = snd_pcm_writei(p, bit.pcm.as_ptr() as *const c_void,
                                   bit.samples as c_ulong);
            if e < 0 {
                if e as c_int == -EPIPE {
                    snd_pcm_prepare(p);
                    Some(())
                } else {
                    None
                }
            } else {
                Some(())
            }
        }
    }
}<commit_msg>update test program<commit_after>extern crate tox;
extern crate libc;

use tox::core::*;
use tox::av::Event::*;

use std::sync::mpsc::{Select};
use std::collections::{HashMap};

fn main() {
    let tox = Tox::new(ToxOptions::new()).unwrap();
    let av = tox.av(2).unwrap();

    let mut audiomap = HashMap::new();

    let ids = [
        ("192.168.3.11"   , 33445 , "951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F"),
        ("172.16.17.32"   , 33445 , "A9D98212B3F972BD11DA52BEB0658C326FCCC1BFD49F347F9C2D3D8B61E1B927"),
        ("192.168.127.12"   , 33445 , "04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F"),
        ("192.168.127.12"   , 33445 , "A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074"),
        ("192.168.3.11"  , 33445 , "7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029"),
        ("172.16.31.10" , 33445 , "F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67"),
        ("172.16.17.32"   , 33445 , "B98A2CEAA6C6A2FADC2C3632D284318B60FE5375CCB41EFA081AB67F500C1B0B"),
        ("192.168.3.11"  , 33445 , "4B2C19E924972CB9B57732FB172F8A8604DE13EEDA2A6234E348983344B23057"),
        ("172.16.58.3"   , 33445 , "7BE3951B97CA4B9ECDDA768E8C52BA19E9E2690AB584787BF4C90E04DBB75111"),
        ("192.168.127.12"     , 443   , "2A4B50D1D525DA2E669592A20C327B5FAD6C7E5962DC69296F9FEC77C4436E4E"),
        ("172.16.31.10"   , 443   , "8CD087E31C67568103E8C2A28653337E90E6B8EDA0D765D57C6B5172B4F1F04C"),
    ];

    for &(ip, port, id) in ids.iter() {
        let id = id.parse().unwrap();
        tox.bootstrap_from_address(ip.to_string(), port, box id).unwrap();
    }

    let groupbot = "56A1ADE4B65B86BCD51CC73E2CD4E542179F47959FE3E0E21B4B0ACDADE51855D34D34D37CB5".parse().unwrap();
    tox.set_name("test".to_string()).ok().unwrap();
    tox.add_friend(box groupbot, "Hello".to_string()).ok().unwrap();

    let sel = Select::new();
    let mut tox_rx = sel.handle(tox.events());
    let mut av_rx = sel.handle(av.events());
    unsafe {
        tox_rx.add();
        av_rx.add();
    }

    loop {
        sel.wait();

        while let Ok(ev) = tox.events().try_recv() {
            match ev {
                FriendRequest(..)       => println!("FriendRequest(..)       "),
                FriendMessage(..)       => println!("FriendMessage(..)       "),
                FriendAction(..)        => println!("FriendAction(..)        "),
                NameChange(..)          => println!("NameChange(..)          "),
                StatusMessage(id, _)       => {
                    println!("StatusMessage(..)       ");
                    let _ = tox.send_message(id, "invite".to_string());
                },
                UserStatusVar(..)       => println!("UserStatusVar(..)       "),
                TypingChange(..)        => println!("TypingChange(..)        "),
                ReadReceipt(..)         => println!("ReadReceipt(..)         "),
                ConnectionStatusVar(..) => println!("ConnectionStatusVar(..) "),
                GroupInvite(id, ty, data)  => {
                    println!("GroupInvite(_, {:?}, _)         ", ty);
                    match ty {
                        GroupchatType::Text => tox.join_groupchat(id, data).unwrap(),
                        GroupchatType::Av => av.join_av_groupchat(id, data).unwrap(),
                    };
                },
                GroupMessage(_, _, msg) => println!("GroupMessage(_, _, {:?})", msg),
                GroupNamelistChange(gnum, pnum, change) => {
                    println!("GroupNamelistChange(..) ");
                    if change == ChatChange::PeerDel {
                        audiomap.remove(&(gnum, pnum));
                    }
                },
                FileSendRequest(..)     => println!("FileSendRequest(..)     "),
                FileControl(..)         => println!("FileControl(..)         "),
                FileData(..)            => println!("FileData(..)            "),
                AvatarInfo(..)          => println!("AvatarInfo(..)          "),
                AvatarData(..)          => println!("AvatarData(..)          "),
            }
        }

        while let Ok(ev) = av.events().try_recv() {
            match ev {
                Invite(..)             => println!("Av::Invite(..)"),
                Ringing(..)            => println!("Av::Ringing(..)"),
                Start(..)              => println!("Av::Start(..)"),
                Cancel(..)             => println!("Av::Cancel(..)"),
                Reject(..)             => println!("Av::Reject(..)"),
                End(..)                => println!("Av::End(..)"),
                RequestTimeout(..)     => println!("Av::RequestTimeout(..)"),
                PeerTimeout(..)        => println!("Av::PeerTimeout(..)"),
                PeerCsChange(..)       => println!("Av::PeerCsChange(..)"),
                SelfCsChange(..)       => println!("Av::SelfCsChange(..)"),
                GroupAudio(gnum, pnum, bit)  => {
                    //println!("Av::GroupAudio(..) SR: {} CH: {} N: {}", bit.sample_rate,
                    //         bit.channels, bit.samples);
                    if audiomap.get(&(gnum, pnum)).is_none() {
                        audiomap.insert((gnum, pnum), alsa::open().unwrap());
                    }
                    let alsa = *audiomap.get(&(gnum, pnum)).unwrap();
                    alsa::write(alsa, &bit).unwrap();
                }
            }
        }
    }
}

mod alsa {
    use libc::{c_int, c_uint, c_void, c_ulong, c_long, c_char, puts, EPIPE};
    use tox::av::{AudioBit};

    pub const RATE: u32 = 48000;
    pub const CHANNELS: u8 = 1;

    #[repr(C)]
    pub struct snd_pcm_t;

    pub const SND_PCM_STREAM_PLAYBACK: c_uint = 0;
    pub const SND_PCM_FORMAT_S16_LE: c_uint = 2;
    pub const SND_PCM_ACCESS_RW_INTERLEAVED: c_int = 3;

    #[link(name = "asound")]
    extern {
        fn snd_pcm_open(pcm: *mut *mut snd_pcm_t, name: *const u8, stream: c_uint,
                        mode: c_int) -> c_int;
        fn snd_pcm_set_params(pcm: *mut snd_pcm_t, format: c_uint, access: c_int,
                              channels: c_uint, rate: c_uint, soft_resample: c_int,
                              latency: c_uint) -> c_int;
        fn snd_pcm_writei(pcm: *mut snd_pcm_t, buffer: *const c_void,
                          size: c_ulong) -> c_long;
        fn snd_strerror(e: c_int) -> *const c_char;
        fn snd_pcm_prepare(pcm: *mut snd_pcm_t) -> c_int;
    }

    pub fn open() -> Option<*mut snd_pcm_t> {
        unsafe {
            let mut ptr = 0 as *mut snd_pcm_t;
            let e = snd_pcm_open(&mut ptr, b"default\0".as_ptr(), SND_PCM_STREAM_PLAYBACK,
                                 0);
            if e != 0 {
                puts(snd_strerror(e));
                return None;
            }
            let e = snd_pcm_set_params(ptr, SND_PCM_FORMAT_S16_LE,
                                  SND_PCM_ACCESS_RW_INTERLEAVED, CHANNELS as c_uint,
                                  RATE as c_uint, 1, 500000);
            if e != 0 {
                puts(snd_strerror(e));
                return None;
            }
            Some(ptr)
        }
    }

    pub fn write(p: *mut snd_pcm_t, bit: &AudioBit) -> Option<()> {
        unsafe {
            if bit.sample_rate != RATE || bit.channels != CHANNELS {
                println!("sample rate {} channels {}", bit.sample_rate, bit.channels);
                return None;
            }
            let e = snd_pcm_writei(p, bit.pcm.as_ptr() as *const c_void,
                                   bit.samples as c_ulong);
            if e < 0 {
                if e as c_int == -EPIPE {
                    snd_pcm_prepare(p);
                    Some(())
                } else {
                    puts(snd_strerror(e as c_int));
                    None
                }
            } else {
                Some(())
            }
        }
    }
}
{'fraction_non_alphanumeric': 0.15069444444444444, 'fraction_numerical': 0.08421717171717172, 'mean_word_length': 1.5934839554682383, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 81, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 22, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6225951', 'n_tokens_mistral': 6232, 'n_tokens_neox': 5389, 'n_words': 789}