diff options
| -rw-r--r-- | README.md | 28 | ||||
| -rwxr-xr-x | build.sh | 6 | ||||
| -rw-r--r-- | src/display.c | 81 | ||||
| -rw-r--r-- | src/display.h | 2 | ||||
| -rw-r--r-- | src/listener.c | 29 | ||||
| -rw-r--r-- | src/socket.c | 50 | ||||
| -rw-r--r-- | src/talker.c | 11 | ||||
| -rw-r--r-- | src/typedef.h | 13 | 
8 files changed, 123 insertions, 97 deletions
| @@ -3,16 +3,14 @@  This is a simple application that uses various linux apis to send video and audio  through udp datagram sockets -### Build +### Libraries and APIs -To build use `./build`, to clean binaries use `./build clean` -When build it create two binaries, `listener` and `talker` - -### Run +This project is written only on C, using the following techonologies: +1. V4L2 - video for linux api for getting images from the camera +2. Pulse Audio Simple API for playing and recording audio (will be changed to alsa soon) +3. GLFW with OpenGL for displaying the recieved image -The `listener` listens for connections and displays the video and plays the -audio. -The `talker` records audio and camera and sends it. +No other external libraires and things.  ### Limitations @@ -23,5 +21,15 @@ The `talker` records audio and camera and sends it.  ### TODO  1. Use alsa and not pulse audio simple api -2. Don't use glut, find a way to sync displaying and getting the video and audio data -3. MUST run at 30 fps +2. MUST run at 30 fps + +### Build + +To build use `./build`, to clean binaries use `./build clean` +When build it create two binaries, `listener` and `talker` + +### Run + +The `listener` listens for connections and displays the video and plays the +audio. +The `talker` records audio and camera and sends it. @@ -2,8 +2,8 @@  cd ${0%/*} # go to project root -FLAGS="-Wall -Wextra -g -pedantic -lpthread -D_GNU_SOURCE" -FGLUT="-lglut -lGLU -lGL" +FLAGS="-g -Wall -Wextra -pedantic -lpthread" +FGLFW="-lGL -lglfw"  FV4L2="-lv4l2"  FPASM="-lpulse -lpulse-simple"  SRC="src" @@ -31,5 +31,5 @@ gcc -o $OBJ/display.o -c $SRC/display.c  gcc -o $OBJ/camera.o  -c $SRC/camera.c  gcc -o $OBJ/audio.o   -c $SRC/audio.c -gcc -o $BIN/listener     $SRC/listener.c $OBJ/socket.o $OBJ/display.o $OBJ/audio.o $FLAGS $FPASM $FGLUT +gcc -o $BIN/listener     $SRC/listener.c $OBJ/socket.o $OBJ/display.o $OBJ/audio.o $FLAGS $FPASM $FGLFW  gcc -o $BIN/talker       $SRC/talker.c   $OBJ/socket.o $OBJ/camera.o  $OBJ/audio.o $FLAGS $FPASM $FV4L2 diff --git a/src/display.c b/src/display.c index 6d4c55a..a09cc46 100644 --- a/src/display.c +++ b/src/display.c @@ -1,15 +1,24 @@  #include <stdio.h> -#include <unistd.h>  #include <string.h> -#include <GL/glut.h> -#include "display.h" +#include <GLFW/glfw3.h>  #include "typedef.h"  #define MAX(x, y) (((x) > (y)) ? (x) : (y)) -extern unsigned char *cam_data; +static void error_callback(int error, const char* description) +{ +    err("display: %s\n", description); +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ +    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) +        glfwSetWindowShouldClose(window, GLFW_TRUE); +} + +extern unsigned char cam_data[]; -unsigned char WIDTH  = 1; +unsigned char WIDTH = 1;  unsigned char HEIGHT = 1;  GLubyte pixels[BUF_CAP] = {0}; @@ -22,30 +31,52 @@ void pixel(int x, int y, char *buf)      pixels[p+2] = buf[b+2];  } -void render() +int display(void)  { -    WIDTH = MAX(cam_data[0], 1); -    HEIGHT = MAX(cam_data[1], 1); +    GLFWwindow* window; +    glfwSetErrorCallback(error_callback); -    for(int i = 0; i < HEIGHT; i++) -        for(int j = 0; j < WIDTH; j++) -            pixel(j, i, &(cam_data[2])); +    if (!glfwInit()) { +        return 1; +    } -    glClear(GL_COLOR_BUFFER_BIT); -    glDrawPixels(WIDTH, HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels); +    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); +    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); -    glutSwapBuffers(); -    glutReshapeWindow(WIDTH, HEIGHT); -    glutPostRedisplay(); -} +    window = glfwCreateWindow(WIDTH, HEIGHT, "Client", NULL, NULL); +    if (!window) { +        glfwTerminate(); +        return 1; +    } -void display(int *argc, char **argv) -{ -	glutInit(argc, argv); -	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); -	glutInitWindowSize(69, 69); -	glutCreateWindow(argv[0]); +    glfwSetKeyCallback(window, key_callback); +    glfwMakeContextCurrent(window); +    glfwSwapInterval(1); + + +    unsigned char *copy_cam_data; +    while (!glfwWindowShouldClose(window)) +    { +        // memcpy(copy_cam_data, cam_data, BUF_CAP); +        copy_cam_data = cam_data; + +        WIDTH = MAX(copy_cam_data[0], 1); +        HEIGHT = MAX(copy_cam_data[1], 1); +        glfwSetWindowSize(window, WIDTH, HEIGHT); + +        for(int i = 0; i < HEIGHT; i++) +            for(int j = 0; j < WIDTH; j++) +                pixel(j, i, &(copy_cam_data[2])); + +        glClear(GL_COLOR_BUFFER_BIT); +        glDrawPixels(WIDTH, HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels); + +        glfwSwapBuffers(window); +        glfwPollEvents(); +    } + +    glfwDestroyWindow(window); +    glfwTerminate(); -	glutDisplayFunc(render); -	glutMainLoop(); +    return 0;  } diff --git a/src/display.h b/src/display.h index f48998a..f4b57a4 100644 --- a/src/display.h +++ b/src/display.h @@ -1,6 +1,6 @@  #ifndef DISPLAY_H  #define DISPLAY_H -void display(int *argc, char **argv); +int display(void);  #endif diff --git a/src/listener.c b/src/listener.c index 135405c..141a3f3 100644 --- a/src/listener.c +++ b/src/listener.c @@ -1,5 +1,6 @@  #include <stdio.h>  #include <stdlib.h> +#include <string.h>  #include <unistd.h>  #include <fcntl.h>  #include <pthread.h> @@ -9,32 +10,38 @@  #include "audio.h"  #include "typedef.h" -char *cam_data; +char cam_data[BUF_CAP];  void *display_thread(void *arg)  {      (void)arg; -    int c = 1; -    char *name = "./display"; -    display(&c, &name); -    pthread_exit(0); +    int r = display(); +    if(r == 0) +        info("display: closed\n"); +    else +        err("display: failed\n"); +    exit(r); +    // pthread_exit(0);  }  void on_recv(char *buf, int numbytes)  { -    cam_data = &(buf[REC_CAP]); -    usleep(100000); -    // audio_play(buf); +    memcpy(cam_data, &(buf[REC_CAP]), BUF_CAP-REC_CAP); +    audio_play(buf);  }  int main(void)  { -    // char empty[1024] = {0}; -    // cam_data = empty; +    memset(cam_data, 0, BUF_CAP);      pthread_t tid;      pthread_create(&tid, NULL, display_thread, NULL); -    return listener("4950", &on_recv); +    if(listener("4950", &on_recv) != 0) { +        err("listener: failed"); +        return 1; +    } + +    return 0;  } diff --git a/src/socket.c b/src/socket.c index 838df53..2ce4900 100644 --- a/src/socket.c +++ b/src/socket.c @@ -5,8 +5,6 @@  #include <string.h>  #include <arpa/inet.h>  #include <netdb.h> -#include <signal.h> -#include <wait.h>  #include <time.h>  #include "socket.h" @@ -23,16 +21,6 @@ void *get_in_addr(struct sockaddr *sa)  	return &(((struct sockaddr_in6*)sa)->sin6_addr);  } -void sigchld_handler(int s) -{ -    // waitpid() might overwrite errno, so we save and restore it: -    int saved_errno = errno; - -    while(waitpid(-1, NULL, WNOHANG) > 0); - -    errno = saved_errno; -} -  int listener(char *port, void (*on_recv)(char *, int))  {      int sockfd; @@ -46,7 +34,7 @@ int listener(char *port, void (*on_recv)(char *, int))      int rv;      if((rv = getaddrinfo(NULL, port, &hints, &servinfo)) != 0) { -		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); +		err("getaddrinfo: %s\n", gai_strerror(rv));  		return 1;  	} @@ -69,8 +57,8 @@ int listener(char *port, void (*on_recv)(char *, int))  	}      if(p == NULL) { -		fprintf(stderr, "listener: failed to bind socket\n"); -		return 2; +	    err("listener: failed to bind socket\n"); +		return 1;  	}      freeaddrinfo(servinfo); @@ -81,17 +69,8 @@ int listener(char *port, void (*on_recv)(char *, int))      {          if(now < time(NULL)) {              now = time(NULL); -            printf("FPS: %d\n", i); +            info("FPS: %d\n", i);              i = 0; - -            // struct sigaction sa; -            // sa.sa_handler = sigchld_handler; // reap all dead processes -            // sigemptyset(&sa.sa_mask); -            // sa.sa_flags = SA_RESTART; -            // if (sigaction(SIGCHLD, &sa, NULL) == -1) { -            //     perror("sigaction"); -            //     return 1; -            // }          }          char buf[BUF_CAP] = {0}; @@ -107,20 +86,13 @@ int listener(char *port, void (*on_recv)(char *, int))      #ifdef LOG_INFO_STDOUT          char s[INET6_ADDRSTRLEN]; -        printf("listener: got packet from %s, %d bytes long\n", +        info("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 -        // #include <stdlib.h> - -        // pid_t p = fork(); -        // if(p < -1) { return 69; } -        // else if(p == 0) { -            on_recv(buf, numbytes); -            // exit(0); -        // } +        on_recv(buf, numbytes);          i++;      } @@ -139,7 +111,7 @@ int talker(char *port, char *address, void (*on_send)(char *, int *))      int rv;      if((rv = getaddrinfo(address, port, &hints, &servinfo)) != 0) { -		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); +        err("getaddrinfo: %s\n", gai_strerror(rv));  		return 1;  	} @@ -156,8 +128,8 @@ int talker(char *port, char *address, void (*on_send)(char *, int *))  	}      if(p == NULL) { -        fprintf(stderr, "talker: failed to create socket\n"); -		return 2; +        err("talker: failed to create socket\n"); +		return 1;  	}      int i = 0; @@ -166,7 +138,7 @@ int talker(char *port, char *address, void (*on_send)(char *, int *))      {          if(now < time(NULL)) {              now = time(NULL); -            printf("FPS %d\n", i); +            info("FPS %d\n", i);              i = 0;          } @@ -181,7 +153,7 @@ int talker(char *port, char *address, void (*on_send)(char *, int *))              return 1;          }      #ifdef LOG_INFO_STDOUT -        printf("talker: sent %d bytes to %s\n", numbytes, address); +        info("talker: sent %d bytes to %s\n", numbytes, address);      #endif          i++; diff --git a/src/talker.c b/src/talker.c index 0ba2994..c481570 100644 --- a/src/talker.c +++ b/src/talker.c @@ -31,21 +31,18 @@ void on_send(char *buf, int *bytes)  int main(void)  { -    int ret = 1; -      camera_params params = {0}; -    params.device = "/dev/video0"; +    params.device = CAM;      params.x_res = 160;      params.y_res = 120;      camera_init(&cam_handle, params);      if(talker("4950", "localhost", &on_send) != 0) { -        goto finish; +        err("talker: failed\n"); +        return 1;      } -    ret = 0; -finish:      camera_deinit(&cam_handle); -    return ret; +    return 0;  } diff --git a/src/typedef.h b/src/typedef.h index a875116..c585f7a 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -1,7 +1,18 @@  #ifndef TYPEDEF_H  #define TYPEDEF_H -#define BUF_CAP 65536 +#include <stdio.h> +#define __str__(x) #x +#define stringize(x) __str__(x) + +#define __RED__ "\033[0;31m" +#define __GREEN__ "\033[0;32m" +#define __RESET__ "\033[0m" + +#define info(...) fprintf(stdout, __GREEN__"[INFO]"__RESET__" "__FILE__":"stringize(__LINE__)": "__VA_ARGS__) +#define err(...) fprintf(stderr, __RED__"[ERR]"__RESET__"  "__FILE__":"stringize(__LINE__)": "__VA_ARGS__) + +#define BUF_CAP 65536 // max datagram size  #define REC_CAP 5880 // 30th of a second of audio  #endif | 
