diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/audio.c | 80 | ||||
| -rw-r--r-- | src/audio.h | 8 | ||||
| -rw-r--r-- | src/camera.c | 25 | ||||
| -rw-r--r-- | src/camera.h | 12 | ||||
| -rw-r--r-- | src/common_v4l2.h | 141 | ||||
| -rw-r--r-- | src/display.c | 53 | ||||
| -rw-r--r-- | src/display.h | 6 | ||||
| -rw-r--r-- | src/listener.c | 37 | ||||
| -rw-r--r-- | src/socket.c | 153 | ||||
| -rw-r--r-- | src/socket.h | 8 | ||||
| -rw-r--r-- | src/talker.c | 33 | ||||
| -rw-r--r-- | src/typedef.h | 7 | 
12 files changed, 563 insertions, 0 deletions
| diff --git a/src/audio.c b/src/audio.c new file mode 100644 index 0000000..0c40f9f --- /dev/null +++ b/src/audio.c @@ -0,0 +1,80 @@ +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <pulse/simple.h> +#include <pulse/error.h> + +#include "audio.h" +#include "typedef.h" + +static const pa_sample_spec ss = { +    .format = PA_SAMPLE_S16LE, +    .rate = 44100, +    .channels = 1 +}; + +static pa_simple *play = NULL; + +int audip_play(char *buf) +{ +    int ret = 1; +    int error; + +    if(!play) { +        if (!(play = pa_simple_new(NULL, __FILE__, PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &error))) { +            fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); +            goto finish; +        } +    } + +    if(pa_simple_write(play, buf, REC_CAP, &error) < 0) { +                    fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error)); +            goto finish; +    } + +    if(pa_simple_drain(play, &error) < 0) { +        fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(error)); +        goto finish; +    } + +    ret = 0; + +finish: + +    if (play) +        pa_simple_free(play); + +    return ret; +} + +int audio_record(int fd) +{ +    pa_simple *rec = NULL; +    int ret = 1; +    int error; + +    if (!(rec = pa_simple_new(NULL, __FILE__, PA_STREAM_RECORD, NULL, "record", &ss, NULL, NULL, &error))) { +        fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); +        goto finish; +    } + +    for(;;) +    { +        char buf[REC_CAP]; + +        if (pa_simple_read(rec, buf, sizeof(buf), &error) < 0) { +            fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error)); +            goto finish; +        } + +        write(fd, buf, sizeof(buf)); +    } + +finish: +    if(rec) +        pa_simple_free(rec); + +    return ret; +} diff --git a/src/audio.h b/src/audio.h new file mode 100644 index 0000000..f7f4ae4 --- /dev/null +++ b/src/audio.h @@ -0,0 +1,8 @@ +#ifndef AUDIO_H +#define AUDIO_H + +int audip_play(char *buf); + +int audio_record(int fd); + +#endif diff --git a/src/camera.c b/src/camera.c new file mode 100644 index 0000000..fcd0606 --- /dev/null +++ b/src/camera.c @@ -0,0 +1,25 @@ +#include "camera.h" +#include "common_v4l2.h" + +CommonV4l2 common_v4l2; + +void camera_init(char *dev_name, unsigned int x_res, unsigned int y_res) +{ +    CommonV4l2_init(&common_v4l2, dev_name, x_res, y_res); +} + +char *camera_get_image() +{ +    CommonV4l2_update_image(&common_v4l2); +    return CommonV4l2_get_image(&common_v4l2); +} + +void camera_deinit() +{ +    CommonV4l2_deinit(&common_v4l2); +} + +int camera_get_image_size() +{ +    return (int)CommonV4l2_get_image_size(&common_v4l2); +} diff --git a/src/camera.h b/src/camera.h new file mode 100644 index 0000000..6a3db62 --- /dev/null +++ b/src/camera.h @@ -0,0 +1,12 @@ +#ifndef CAMERA_H +#define CAMERA_H + +void camera_init(char *dev_name, unsigned int x_res, unsigned int y_res); + +char *camera_get_image(); + +void camera_deinit(); + +int camera_get_image_size(); + +#endif diff --git a/src/common_v4l2.h b/src/common_v4l2.h new file mode 100644 index 0000000..c3762b5 --- /dev/null +++ b/src/common_v4l2.h @@ -0,0 +1,141 @@ +#ifndef COMMON_V4L2_H +#define COMMON_V4L2_H + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <sys/types.h> + +#include <libv4l2.h> +#include <linux/videodev2.h> + +#define COMMON_V4L2_CLEAR(x) memset(&(x), 0, sizeof(x)) + +typedef struct { +    void *start; +    size_t length; +} CommonV4l2_Buffer; + +typedef struct { +    int fd; +    CommonV4l2_Buffer *buffers; +    struct v4l2_buffer buf; +    unsigned int n_buffers; +} CommonV4l2; + +void CommonV4l2_xioctl(int fh, unsigned long int request, void *arg) +{ +    int r; +    do { +        r = v4l2_ioctl(fh, request, arg); +    } while (r == -1 && ((errno == EINTR) || (errno == EAGAIN))); +    if (r == -1) { +        fprintf(stderr, "error %d, %s\n", errno, strerror(errno)); +        exit(EXIT_FAILURE); +    } +} + +void CommonV4l2_init(CommonV4l2 *this, char *dev_name, unsigned int x_res, unsigned int y_res) { +    enum v4l2_buf_type type; +    struct v4l2_format fmt; +    struct v4l2_requestbuffers req; +    unsigned int i; + +    this->fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0); +    if (this->fd < 0) { +        perror("Cannot open device"); +        exit(EXIT_FAILURE); +    } +    COMMON_V4L2_CLEAR(fmt); +    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +    fmt.fmt.pix.width       = x_res; +    fmt.fmt.pix.height      = y_res; +    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; +    fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED; +    CommonV4l2_xioctl(this->fd, VIDIOC_S_FMT, &fmt); +    if ((fmt.fmt.pix.width != x_res) || (fmt.fmt.pix.height != y_res)) +        printf("Warning: driver is sending image at %dx%d\n", +            fmt.fmt.pix.width, fmt.fmt.pix.height); +    COMMON_V4L2_CLEAR(req); +    req.count = 2; +    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +    req.memory = V4L2_MEMORY_MMAP; +    CommonV4l2_xioctl(this->fd, VIDIOC_REQBUFS, &req); +    this->buffers = calloc(req.count, sizeof(*this->buffers)); +    for (this->n_buffers = 0; this->n_buffers < req.count; ++this->n_buffers) { +        COMMON_V4L2_CLEAR(this->buf); +        this->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +        this->buf.memory = V4L2_MEMORY_MMAP; +        this->buf.index = this->n_buffers; +        CommonV4l2_xioctl(this->fd, VIDIOC_QUERYBUF, &this->buf); +        this->buffers[this->n_buffers].length = this->buf.length; +        this->buffers[this->n_buffers].start = v4l2_mmap(NULL, this->buf.length, +            PROT_READ | PROT_WRITE, MAP_SHARED, this->fd, this->buf.m.offset); +        if (MAP_FAILED == this->buffers[this->n_buffers].start) { +            perror("mmap"); +            exit(EXIT_FAILURE); +        } +    } +    for (i = 0; i < this->n_buffers; ++i) { +        COMMON_V4L2_CLEAR(this->buf); +        this->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +        this->buf.memory = V4L2_MEMORY_MMAP; +        this->buf.index = i; +        CommonV4l2_xioctl(this->fd, VIDIOC_QBUF, &this->buf); +    } +    type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +    CommonV4l2_xioctl(this->fd, VIDIOC_STREAMON, &type); +} + +void CommonV4l2_update_image(CommonV4l2 *this) { +    fd_set fds; +    int r; +    struct timeval tv; + +    do { +        FD_ZERO(&fds); +        FD_SET(this->fd, &fds); + +        /* Timeout. */ +        tv.tv_sec = 2; +        tv.tv_usec = 0; + +        r = select(this->fd + 1, &fds, NULL, NULL, &tv); +    } while ((r == -1 && (errno == EINTR))); +    if (r == -1) { +        perror("select"); +        exit(EXIT_FAILURE); +    } +    COMMON_V4L2_CLEAR(this->buf); +    this->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +    this->buf.memory = V4L2_MEMORY_MMAP; +    CommonV4l2_xioctl(this->fd, VIDIOC_DQBUF, &this->buf); +    CommonV4l2_xioctl(this->fd, VIDIOC_QBUF, &this->buf); +} + +char * CommonV4l2_get_image(CommonV4l2 *this) { +    return ((char *)this->buffers[this->buf.index].start); +} + +size_t CommonV4l2_get_image_size(CommonV4l2 *this) { +    return this->buffers[this->buf.index].length; +} + +void CommonV4l2_deinit(CommonV4l2 *this) { +    unsigned int i; +    enum v4l2_buf_type type; + +    type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +    CommonV4l2_xioctl(this->fd, VIDIOC_STREAMOFF, &type); +    for (i = 0; i < this->n_buffers; ++i) +        v4l2_munmap(this->buffers[i].start, this->buffers[i].length); +    v4l2_close(this->fd); +    free(this->buffers); +} + +#endif diff --git a/src/display.c b/src/display.c new file mode 100644 index 0000000..33131ef --- /dev/null +++ b/src/display.c @@ -0,0 +1,53 @@ +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <GL/glut.h> +#include "display.h" +#include "typedef.h" + +unsigned char WIDTH  = 1; +unsigned char HEIGHT = 1; + +GLubyte pixels[BUF_CAP] = {0}; +static int fd; + +void pixel(int x, int y, char *buf) +{ +    int p = (y*WIDTH + x)*3; +    int b = ((HEIGHT-1-y)*WIDTH+x)*3; +    pixels[p+0] = buf[b+0]; +    pixels[p+1] = buf[b+1]; +    pixels[p+2] = buf[b+2]; +} + +void render() +{ +    read(fd, &WIDTH,  sizeof(WIDTH)); +    read(fd, &HEIGHT, sizeof(HEIGHT)); + +    char buf[BUF_CAP] = {0}; +    if(read(fd, buf, sizeof(buf)) != -1) +        for(int i = 0; i < HEIGHT; i++) +            for(int j = 0; j < WIDTH; j++) +                pixel(j, i, buf); + +    glClear(GL_COLOR_BUFFER_BIT); +    glDrawPixels(WIDTH, HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels); + +    glutSwapBuffers(); +    glutReshapeWindow(WIDTH, HEIGHT); +    glutPostRedisplay(); +} + +void display(int *argc, char **argv, int readfd) +{ +	glutInit(argc, argv); +	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); +	glutInitWindowSize(69, 69); +	glutCreateWindow(argv[0]); + +    fd = readfd; + +	glutDisplayFunc(render); +	glutMainLoop(); +} diff --git a/src/display.h b/src/display.h new file mode 100644 index 0000000..7e4f187 --- /dev/null +++ b/src/display.h @@ -0,0 +1,6 @@ +#ifndef DISPLAY_H +#define DISPLAY_H + +void display(int *argc, char **argv, int readfd); + +#endif diff --git a/src/listener.c b/src/listener.c new file mode 100644 index 0000000..0a5df2d --- /dev/null +++ b/src/listener.c @@ -0,0 +1,37 @@ +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> + +#include "socket.h" +#include "display.h" +#include "typedef.h" + +static int fd; + +void on_recv(char *buf, int numbytes) +{ +    // read and play audio +    write(fd, buf, numbytes); +} + +int main(int argc, char **argv) +{ +    int pipefd[2]; +    if(pipe2(pipefd, O_NONBLOCK) == -1) { +        fputs("pipe: failed", stderr); +        return 1; +    } + +    pid_t p = fork(); +    if(p < 0) { +        fputs("fork: failed", stderr); +        return 1; +    } else if(p > 0) { +        close(pipefd[0]); +        fd = pipefd[1]; +        return listener("4950", &on_recv); +    } else { +        close(pipefd[1]); +        display(&argc, argv, pipefd[0]); +    } +} diff --git a/src/socket.c b/src/socket.c new file mode 100644 index 0000000..e388e45 --- /dev/null +++ b/src/socket.c @@ -0,0 +1,153 @@ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <arpa/inet.h> +#include <netdb.h> +#include "socket.h" +#include "typedef.h" + +void *get_in_addr(struct sockaddr *sa) +{ +	if (sa->sa_family == AF_INET) { +		return &(((struct sockaddr_in*)sa)->sin_addr); +	} + +	return &(((struct sockaddr_in6*)sa)->sin6_addr); +} + +int listener(char *port, void (*on_recv)(char *, int)) +{ +    int sockfd; +    int ret; + +    struct addrinfo hints, *servinfo; +    memset(&hints, 0, sizeof hints); +	hints.ai_family = AF_INET6; // set to AF_INET to use IPv4 +	hints.ai_socktype = SOCK_DGRAM; +	hints.ai_flags = AI_PASSIVE; // use my IP + +    int rv; +    if((rv = getaddrinfo(NULL, port, &hints, &servinfo)) != 0) { +		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); +		return 1; +	} + +    struct addrinfo *p; +    for(p = servinfo; p != NULL; p = p->ai_next) +    { +        if((sockfd = socket(p->ai_family, p->ai_socktype, +                             p->ai_protocol)) == -1) { +			perror("listener: socket"); +			continue; +		} + +		if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { +			close(sockfd); +			perror("listener: bind"); +			continue; +		} + +		break; +	} + +    if(p == NULL) { +		fprintf(stderr, "listener: failed to bind socket\n"); +		return 2; +	} + +    freeaddrinfo(servinfo); + +    #include <time.h> +    int i = 0; +    time_t now = 0; +    while(1) +    { +        if(now < time(NULL)) { +            now = time(NULL); +            printf("FPS: %d\n", i); +            i = 0; +        } + +        char buf[BUF_CAP] = {0}; +        struct sockaddr_storage their_addr; +        socklen_t addr_len = sizeof(their_addr); + +        int numbytes; +        if ((numbytes = recvfrom(sockfd, buf, BUF_CAP-1 , 0, +                                 (struct sockaddr *)&their_addr, &addr_len)) == -1) { +            perror("recvfrom"); +            return 1; +        } + +    #ifdef LOG_INFO_STDOUT +        char s[INET6_ADDRSTRLEN]; +        printf("listener: got packet from %s, %d bytes long\n", +               inet_ntop(their_addr.ss_family, +                         get_in_addr((struct sockaddr *)&their_addr), +                         s, sizeof(s)), numbytes); +    #endif + +        on_recv(buf, numbytes); + +        i++; +    } + +    return 0; +} + +int talker(char *port, char *address, void (*on_send)(char *, int *)) +{ +    int sockfd; + +    struct addrinfo hints, *servinfo; +    memset(&hints, 0, sizeof hints); +	hints.ai_family = AF_INET6; // set to AF_INET to use IPv4 +	hints.ai_socktype = SOCK_DGRAM; + +    int rv; +    if((rv = getaddrinfo(address, port, &hints, &servinfo)) != 0) { +		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); +		return 1; +	} + +    struct addrinfo *p; +    for(p = servinfo; p != NULL; p = p->ai_next) +    { +        if((sockfd = socket(p->ai_family, p->ai_socktype, +                             p->ai_protocol)) == -1) { +			perror("talker: socket"); +			continue; +		} + +		break; +	} + +    if(p == NULL) { +        fprintf(stderr, "talker: failed to create socket\n"); +		return 2; +	} + +    while(1) +    { +        char buf[BUF_CAP] = {0}; +        int bytes; +        on_send(buf, &bytes); + +        int numbytes; +        if((numbytes = sendto(sockfd, buf, bytes, 0, +                              p->ai_addr, p->ai_addrlen)) == -1) { +            perror("talker: sendto"); +            return 1; +        } +    #ifdef LOG_INFO_STDOUT +        printf("talker: sent %d bytes to %s\n", numbytes, address); +    #endif +    } + +    freeaddrinfo(servinfo); +    close(sockfd); + +    return 0; +} diff --git a/src/socket.h b/src/socket.h new file mode 100644 index 0000000..ecb27ab --- /dev/null +++ b/src/socket.h @@ -0,0 +1,8 @@ +#ifndef SOCKET_H +#define SOCKET_H + +int listener(char *port, void (*on_recv)(char *, int)); + +int talker(char *port, char *address, void (*on_send)(char *, int *)); + +#endif diff --git a/src/talker.c b/src/talker.c new file mode 100644 index 0000000..8b09274 --- /dev/null +++ b/src/talker.c @@ -0,0 +1,33 @@ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> + +#include "socket.h" +#include "camera.h" +#include "typedef.h" + +#define CAM "/dev/video0" +#define X_RES 160 +#define Y_RES 120 + +void on_send(char *buf, int *bytes) +{ +    // write here audio + +    int cisz = camera_get_image_size(); +    buf[0] = (unsigned char)X_RES; +    buf[1] = (unsigned char)Y_RES; + +    *bytes = cisz + 2; + +    memcpy(&(buf[2]), camera_get_image(), cisz); + +    printf("%d\n", *bytes); +} + +int main(void) +{ +    camera_init(CAM, X_RES, Y_RES); +    return talker("4950", "localhost", &on_send); +} diff --git a/src/typedef.h b/src/typedef.h new file mode 100644 index 0000000..a8871fd --- /dev/null +++ b/src/typedef.h @@ -0,0 +1,7 @@ +#ifndef TYPEDEF_H +#define TYPEDEF_H + +#define BUF_CAP 65536 +#define REC_CAP 2940 // second of audio + +#endif | 
