diff options
| -rw-r--r-- | README.md | 27 | ||||
| -rwxr-xr-x | build.sh | 11 | ||||
| -rw-r--r-- | src/audio.c | 11 | ||||
| -rw-r--r-- | src/camera.c | 18 | ||||
| -rw-r--r-- | src/camera.h | 16 | ||||
| -rw-r--r-- | src/display.c | 24 | ||||
| -rw-r--r-- | src/display.h | 2 | ||||
| -rw-r--r-- | src/listener.c | 56 | ||||
| -rw-r--r-- | src/socket.c | 25 | ||||
| -rw-r--r-- | src/talker.c | 22 | 
10 files changed, 128 insertions, 84 deletions
| diff --git a/README.md b/README.md new file mode 100644 index 0000000..f58bcd4 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +### Video call + +This is a simple application that uses various linux apis to send video and audio +through udp datagram sockets + +### 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. + +### Limitations + +1. 160x120 video resolution because of the limited size of sockets +2. Crappy audio, most likely because of pulse audio +3. Works only one linux, I don't plan porting it to windows. + +### 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 @@ -9,11 +9,6 @@ FPASM="-lpulse -lpulse-simple"  SRC="src"  OBJ="obj"  BIN="bin" -RUN=0 - -function __run__ { -    RUN=1 -}  function __clean__ {      rm -rf $BIN @@ -38,9 +33,3 @@ 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/talker       $SRC/talker.c   $OBJ/socket.o $OBJ/camera.o  $OBJ/audio.o $FLAGS $FPASM $FV4L2 - -# if ! { [[ $RUN -eq 0 ]]; } 2> /dev/null -# then -# fi - -# bin/listener diff --git a/src/audio.c b/src/audio.c index f7a51a5..710c10c 100644 --- a/src/audio.c +++ b/src/audio.c @@ -32,6 +32,12 @@ int audio_play(char *buf)          }      } +    if(pa_simple_flush(play, &error) < 0) +    { +        fprintf(stderr, __FILE__": pa_simple_flush() 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; @@ -64,6 +70,11 @@ int audio_record(char *buf)          }      } +    if(pa_simple_flush(rec, &error) < 0) { +        fprintf(stderr, __FILE__": pa_simple_flush() failed: %s\n", pa_strerror(error)); +        goto finish; +    } +      if (pa_simple_read(rec, buf, REC_CAP, &error) < 0) {          fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error));          goto finish; diff --git a/src/camera.c b/src/camera.c index 6842a12..8d74217 100644 --- a/src/camera.c +++ b/src/camera.c @@ -1,20 +1,20 @@  #include "camera.h"  #include "common_v4l2.h" -CommonV4l2 common_v4l2; - -void camera_init(char *dev_name, unsigned int x_res, unsigned int y_res) +void camera_init(camera_handle *handle, camera_params params)  { -    CommonV4l2_init(&common_v4l2, dev_name, x_res, y_res); +    handle->handle = malloc(sizeof(CommonV4l2)); +    CommonV4l2_init(handle->handle, params.device, params.x_res, params.y_res);  } -char *camera_get_image() +char *camera_get_image(camera_handle *handle)  { -    CommonV4l2_update_image(&common_v4l2); -    return CommonV4l2_get_image(&common_v4l2); +    CommonV4l2_update_image(handle->handle); +    return CommonV4l2_get_image(handle->handle);  } -void camera_deinit() +void camera_deinit(camera_handle *handle)  { -    CommonV4l2_deinit(&common_v4l2); +    CommonV4l2_deinit(handle->handle); +    free(handle->handle);  } diff --git a/src/camera.h b/src/camera.h index aaf690c..bfc5394 100644 --- a/src/camera.h +++ b/src/camera.h @@ -1,10 +1,20 @@  #ifndef CAMERA_H  #define CAMERA_H -void camera_init(char *dev_name, unsigned int x_res, unsigned int y_res); +typedef struct camera_handle { +    void *handle; +} camera_handle; -char *camera_get_image(); +typedef struct camera_params { +    char *device; +    int x_res; +    int y_res; +} camera_params; -void camera_deinit(); +void camera_init(camera_handle *handle, camera_params params); + +char *camera_get_image(camera_handle *handle); + +void camera_deinit(camera_handle *handle);  #endif diff --git a/src/display.c b/src/display.c index 2fb1d78..6d4c55a 100644 --- a/src/display.c +++ b/src/display.c @@ -5,11 +5,13 @@  #include "display.h"  #include "typedef.h" +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) + +extern unsigned char *cam_data; +  unsigned char WIDTH  = 1;  unsigned char HEIGHT = 1; -  GLubyte pixels[BUF_CAP] = {0}; -static int fd;  void pixel(int x, int y, char *buf)  { @@ -22,14 +24,12 @@ void pixel(int x, int y, char *buf)  void render()  { -    read(fd, &WIDTH,  sizeof(WIDTH)); -    read(fd, &HEIGHT, sizeof(HEIGHT)); +    WIDTH = MAX(cam_data[0], 1); +    HEIGHT = MAX(cam_data[1], 1); -    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); +    for(int i = 0; i < HEIGHT; i++) +        for(int j = 0; j < WIDTH; j++) +            pixel(j, i, &(cam_data[2]));      glClear(GL_COLOR_BUFFER_BIT);      glDrawPixels(WIDTH, HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels); @@ -39,17 +39,13 @@ void render()      glutPostRedisplay();  } -void display(int *argc, char **argv, int readfd) +void display(int *argc, char **argv)  {  	glutInit(argc, argv);  	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);  	glutInitWindowSize(69, 69);  	glutCreateWindow(argv[0]); -    fd = readfd; -  	glutDisplayFunc(render);  	glutMainLoop(); - -    puts("DISPLAY EXIT");  } diff --git a/src/display.h b/src/display.h index 7e4f187..f48998a 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 readfd); +void display(int *argc, char **argv);  #endif diff --git a/src/listener.c b/src/listener.c index 7e9a839..135405c 100644 --- a/src/listener.c +++ b/src/listener.c @@ -2,51 +2,39 @@  #include <stdlib.h>  #include <unistd.h>  #include <fcntl.h> +#include <pthread.h>  #include "socket.h"  #include "display.h"  #include "audio.h"  #include "typedef.h" -static int fd; +char *cam_data; -void on_recv(char *buf, int numbytes) +void *display_thread(void *arg)  { -    // read and play audio -    pid_t p = fork(); -    if(p < 0) { -        fputs("fork: failed", stderr); -        exit(1); -    } else if(p > 0) { -        write(fd, &(buf[REC_CAP]), numbytes-REC_CAP); -    } else { -        audio_play(buf); -        exit(0); -    } +    (void)arg; -    // audio_play(buf); -    // write(fd, &(buf[REC_CAP]), numbytes-REC_CAP); +    int c = 1; +    char *name = "./display"; +    display(&c, &name); +    pthread_exit(0); +} +void on_recv(char *buf, int numbytes) +{ +    cam_data = &(buf[REC_CAP]); +    usleep(100000); +    // audio_play(buf);  } -int main(int argc, char **argv) +int main(void)  { -    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]); -    } +    // char empty[1024] = {0}; +    // cam_data = empty; + +    pthread_t tid; +    pthread_create(&tid, NULL, display_thread, NULL); + +    return listener("4950", &on_recv);  } diff --git a/src/socket.c b/src/socket.c index f435812..838df53 100644 --- a/src/socket.c +++ b/src/socket.c @@ -84,14 +84,14 @@ int listener(char *port, void (*on_recv)(char *, int))              printf("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; -            } +            // 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}; @@ -113,7 +113,14 @@ int listener(char *port, void (*on_recv)(char *, int))                           s, sizeof(s)), numbytes);      #endif -        on_recv(buf, numbytes); +        // #include <stdlib.h> + +        // pid_t p = fork(); +        // if(p < -1) { return 69; } +        // else if(p == 0) { +            on_recv(buf, numbytes); +            // exit(0); +        // }          i++;      } diff --git a/src/talker.c b/src/talker.c index 027d0e6..0ba2994 100644 --- a/src/talker.c +++ b/src/talker.c @@ -13,6 +13,7 @@  #define X_RES 160  #define Y_RES 120 +camera_handle cam_handle;  void on_send(char *buf, int *bytes)  { @@ -24,12 +25,27 @@ void on_send(char *buf, int *bytes)      *bytes = REC_CAP + 2 + image_sz; -    memcpy(&(buf[REC_CAP+2]), camera_get_image(), image_sz); +    memcpy(&(buf[REC_CAP+2]), camera_get_image(&cam_handle), image_sz);  }  int main(void)  { -    camera_init(CAM, X_RES, Y_RES); -    return talker("4950", "localhost", &on_send); +    int ret = 1; + +    camera_params params = {0}; +    params.device = "/dev/video0"; +    params.x_res = 160; +    params.y_res = 120; + +    camera_init(&cam_handle, params); + +    if(talker("4950", "localhost", &on_send) != 0) { +        goto finish; +    } + +    ret = 0; +finish: +    camera_deinit(&cam_handle); +    return ret;  } | 
