Skip to content
Open
9 changes: 5 additions & 4 deletions src/app_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ static inline void app_config_open(FILE **file, const char *flags) {

ssize_t exe_len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1);
if (exe_len != -1) {
char *dir = dirname(exe_path);
exe_path[exe_len] = '\0';
char *dir = dirname(exe_path);
snprintf(conf_path, sizeof(conf_path), "%s/divinus.yaml", dir);
if (!access(conf_path, F_OK)) {
if (*flags == 'w') {
Expand Down Expand Up @@ -44,8 +44,8 @@ void app_config_restore(void) {

ssize_t exe_len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1);
if (exe_len != -1) {
char bak_path[PATH_MAX], *dir = dirname(exe_path);
exe_path[exe_len] = '\0';
char bak_path[PATH_MAX], *dir = dirname(exe_path);
snprintf(conf_path, sizeof(conf_path), "%s/divinus.yaml", dir);
sprintf(bak_path, "%s.bak", conf_path);
if (!access(bak_path, F_OK)) {
Expand Down Expand Up @@ -318,8 +318,9 @@ enum ConfigError app_config_parse(void) {
if (err != CONFIG_OK)
goto RET_ERR;
app_config.web_port = (unsigned short)port;
/* Keep the last entry free for the empty terminator. */
parse_list(&ini, "system", "web_whitelist",
sizeof(app_config.web_whitelist) / sizeof(*app_config.web_whitelist),
sizeof(app_config.web_whitelist) / sizeof(*app_config.web_whitelist) - 1,
&count, app_config.web_whitelist);
*app_config.web_whitelist[count] = '\0';
parse_bool(&ini, "system", "web_enable_auth", &app_config.web_enable_auth);
Expand Down Expand Up @@ -496,7 +497,7 @@ enum ConfigError app_config_parse(void) {
err = parse_int(&ini, "stream", "udp_srcport", 0, USHRT_MAX, &val);
if (err == CONFIG_OK) app_config.stream_udp_srcport = (unsigned short)val;
parse_list(&ini, "stream", "dest",
sizeof(app_config.stream_dests) / sizeof(*app_config.stream_dests),
sizeof(app_config.stream_dests) / sizeof(*app_config.stream_dests) - 1,
&count, app_config.stream_dests);
*app_config.stream_dests[count] = '\0';
}
Expand Down
35 changes: 22 additions & 13 deletions src/media.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,12 @@ static char rtsp_g711_active(void) { return EQUALS(rtsp_codec, "pcma") || EQUALS
static void rtsp_pcma_feed(short *pcm, unsigned int samples)
{
static unsigned char alaw[160];
static unsigned int fill, phase, step;
static unsigned int fill, phase;
static int acc, count;
char ulaw = EQUALS(rtsp_codec, "pcmu");
if (!step) {
unsigned int srate = app_config.audio_srate > 0 ? app_config.audio_srate : 8000;
step = (srate << 16) / 8000;
if (!step) step = 1 << 16;
}
unsigned int srate = app_config.audio_srate > 0 ? app_config.audio_srate : 8000;
/* Input samples per 8 kHz output sample in Q16, i.e. (srate << 16) / 8000 */
unsigned int step = srate * 1024 / 125;
for (unsigned int i = 0; i < samples; i++) {
acc += pcm[i];
count++;
Expand Down Expand Up @@ -590,6 +588,9 @@ int media_audio_enable(void) {
pcmSamp = shine_samples_per_pass(mp3Enc);
}

/* The capture and encoding threads run only while audioOn is set. */
audioOn = 1;

{
pthread_attr_t thread_attr;
pthread_attr_init(&thread_attr);
Expand All @@ -599,8 +600,10 @@ int media_audio_enable(void) {
if (pthread_attr_setstacksize(&thread_attr, new_stacksize))
HAL_DANGER("media", "Can't set stack size %zu\n", new_stacksize);
if (pthread_create(
&audPid, &thread_attr, (void *(*)(void *))aud_thread, NULL))
&audPid, &thread_attr, (void *(*)(void *))aud_thread, NULL)) {
audioOn = 0;
HAL_ERROR("media", "Starting the audio capture thread failed!\n");
}
if (pthread_attr_setstacksize(&thread_attr, stacksize))
HAL_DANGER("media", "Can't set stack size %zu\n", stacksize);
pthread_attr_destroy(&thread_attr);
Expand All @@ -615,15 +618,15 @@ int media_audio_enable(void) {
if (pthread_attr_setstacksize(&thread_attr, new_stacksize))
HAL_DANGER("media", "Can't set stack size %zu\n", new_stacksize);
if (pthread_create(
&aencPid, &thread_attr, (void *(*)(void *))aenc_thread, NULL))
&aencPid, &thread_attr, (void *(*)(void *))aenc_thread, NULL)) {
audioOn = 0;
HAL_ERROR("media", "Starting the audio encoding thread failed!\n");
}
if (pthread_attr_setstacksize(&thread_attr, stacksize))
HAL_DANGER("media", "Can't set stack size %zu\n", stacksize);
pthread_attr_destroy(&thread_attr);
}

audioOn = 1;

return ret;
}

Expand Down Expand Up @@ -737,6 +740,14 @@ int media_mp4_disable(void) {
return EXIT_SUCCESS;
}

void media_mp4_config(void) {
pthread_mutex_lock(&mp4Mtx);
mp4_set_config(app_config.mp4_width, app_config.mp4_height, app_config.mp4_fps,
app_config.audio_enable ? HAL_AUDCODEC_MP3 : HAL_AUDCODEC_UNSPEC,
app_config.audio_bitrate, 1, app_config.audio_srate);
pthread_mutex_unlock(&mp4Mtx);
}

int media_mp4_enable(void) {
int ret;

Expand Down Expand Up @@ -797,9 +808,7 @@ int media_mp4_enable(void) {
index, ret, errstr(ret));
}

mp4_set_config(app_config.mp4_width, app_config.mp4_height, app_config.mp4_fps,
app_config.audio_enable ? HAL_AUDCODEC_MP3 : HAL_AUDCODEC_UNSPEC,
app_config.audio_bitrate, 1, app_config.audio_srate);
media_mp4_config();
}

if (ret = bind_channel(index, app_config.mp4_fps, 0))
Expand Down
1 change: 1 addition & 0 deletions src/media.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ void media_audio_disable(void);
int media_audio_enable(void);
int media_mjpeg_disable(void);
int media_mjpeg_enable(void);
void media_mp4_config(void);
int media_mp4_disable(void);
int media_mp4_enable(void);

Expand Down
5 changes: 3 additions & 2 deletions src/region.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ int region_parse_bitmap(FILE **file, bitmapfile *bmpFile, bitmapinfo *bmpInfo) {

int region_prepare_image(char *path, hal_bitmap *bitmap) {
FILE *file;
unsigned char *bitmapdata, *bitmapout;
unsigned char *bitmapdata = NULL, *bitmapout = NULL;
unsigned short *dest;

if (!path)
Expand Down Expand Up @@ -225,7 +225,7 @@ int region_prepare_image(char *path, hal_bitmap *bitmap) {
}

err = spng_decode_image(ctx, bitmapdata, bitmapsize, SPNG_FMT_RGBA8, 0);
if (!bitmapdata) {
if (err) {
HAL_DANGER("server", "Decoding the PNG image failed!\nError: %s\n", spng_strerror(err));
goto png_error;
}
Expand All @@ -239,6 +239,7 @@ int region_prepare_image(char *path, hal_bitmap *bitmap) {
free(bitmapdata);

fclose(file);
spng_ctx_free(ctx);

bitmap->data = bitmapout;
bitmap->dim.width = ihdr.width;
Expand Down
73 changes: 37 additions & 36 deletions src/rtsp/rtp.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,37 @@ struct __transfer_set_t {

static unsigned int __frame_ts_video, __frame_ts_audio;

static inline void __wait_out(int fd)
/* A client that accepts no data for 20 polls of 100 ms is dropped. */
#define TCP_STALL_POLLS 20

static int __tcp_send_all(int fd, const char *buf, size_t len)
{
struct pollfd p = { .fd = fd, .events = POLLOUT };
poll(&p, 1, 100);
int stalls = 0;

while (len) {
int r = send(fd, buf, len, 0);
if (r > 0) {
buf += r;
len -= r;
stalls = 0;
} else if (r < 0 && (errno == EAGAIN || errno == EWOULDBLOCK) &&
stalls++ < TCP_STALL_POLLS) {
struct pollfd p = { .fd = fd, .events = POLLOUT };
poll(&p, 1, 100);
} else {
/* Let the RTSP thread see EOF and tear the session down. */
shutdown(fd, SHUT_RDWR);
return FAILURE;
}
}
return SUCCESS;
}

static int __tcp_flush(struct connection_item_t *con)
{
unsigned int sent = 0;
while (sent < con->tx_len) {
int r = send(con->client_fd, con->tx_buf + sent, con->tx_len - sent, 0);
if (r > 0) sent += r;
else if (r < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { __wait_out(con->client_fd); }
else { con->tx_len = 0; return FAILURE; }
}
int ret = __tcp_send_all(con->client_fd, (char *)con->tx_buf, con->tx_len);
con->tx_len = 0;
return SUCCESS;
return ret;
}

static int __tcp_flush_each(struct list_t *e, void *v)
Expand All @@ -68,9 +82,10 @@ static int __tcp_flush_each(struct list_t *e, void *v)
* Testing track 0 here never flushed a client that set up audio alone. */
if (!con->tx_buf || !con->tx_len) return SUCCESS;
pthread_mutex_lock(&con->write_mutex);
int ret = __tcp_flush(con);
__tcp_flush(con);
pthread_mutex_unlock(&con->write_mutex);
return ret;
/* A failed client is shut down; keep flushing the others. */
return SUCCESS;
}

/******************************************************************************
Expand Down Expand Up @@ -253,34 +268,20 @@ static inline int __rtp_send_eachconnection(struct list_t *e, void *v)
return SUCCESS;
}
ERR("send (staged):%s\n", strerror(errno));
return FAILURE;
}
int sent_h = 0;
while (sent_h < 4) {
int r = send(con->client_fd, head + sent_h, 4 - sent_h, 0);
if (r > 0) sent_h += r;
else if (r < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { __wait_out(con->client_fd); }
else { sent_h = -1; break; }
}
if (sent_h == 4) {
int sent_b = 0;
while (sent_b < rtp->rtpsize) {
int r = send(con->client_fd, (char*)&(rtp->packet) + sent_b, rtp->rtpsize - sent_b, 0);
if (r > 0) sent_b += r;
else if (r < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { __wait_out(con->client_fd); }
else { sent_b = -1; break; }
}
send_bytes = sent_b;
} else {
send_bytes = -1;
/* The client is shut down; keep sending to the others. */
return SUCCESS;
}
int ok = __tcp_send_all(con->client_fd, (char *)head, 4) == SUCCESS &&
__tcp_send_all(con->client_fd, (char *)&(rtp->packet), rtp->rtpsize) == SUCCESS;
pthread_mutex_unlock(&con->write_mutex);

if (send_bytes == rtp->rtpsize) {
if (ok) {
con->trans[track_id].rtcp_packet_cnt += 1;
con->trans[track_id].rtcp_octet += rtp->rtpsize;
return SUCCESS;
}
} else
ERR("send:%s\n", strerror(errno));
/* A failed client is shut down; keep sending to the others. */
return SUCCESS;
} else {
char attempts = 0;
do {
Expand Down
14 changes: 10 additions & 4 deletions src/rtsp/rtsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ static void __method_options(struct connection_item_t *p, rtsp_handle h)
{
__rtsp_write(p, "RTSP/1.0 200 OK\r\n"
"CSeq: %d\r\n"
"Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE\r\n"
"Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY\r\n"
"\r\n", p->cseq);
}

Expand Down Expand Up @@ -299,19 +299,25 @@ static void __method_setup(struct connection_item_t *p, rtsp_handle h)
static void __method_pause(struct connection_item_t *p, rtsp_handle h)
{
__rtsp_write(p,
"RTSP/1.0 "__RESPONCE_STR_METHODNOTALLOWED "\r\n");
"RTSP/1.0 " __RESPONCE_STR_METHODNOTALLOWED "\r\n"
"CSeq: %d\r\n"
"\r\n", p->cseq);
}

static void __method_record(struct connection_item_t *p, rtsp_handle h)
{
__rtsp_write(p,
"RTSP/1.0 " __RESPONCE_STR_METHODNOTALLOWED "\r\n");
"RTSP/1.0 " __RESPONCE_STR_METHODNOTALLOWED "\r\n"
"CSeq: %d\r\n"
"\r\n", p->cseq);
}

static void __method_error(struct connection_item_t *p, rtsp_handle h)
{
__rtsp_write(p,
"RTSP/1.0 " __RESPONCE_STR_SERVERERROR "\r\n");
"RTSP/1.0 " __RESPONCE_STR_SERVERERROR "\r\n"
"CSeq: %d\r\n"
"\r\n", p->cseq);
}

static void __method_play(struct connection_item_t *p, rtsp_handle h)
Expand Down
43 changes: 33 additions & 10 deletions src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,10 @@ void respond_request(http_request_t *req) {

media_audio_disable();
if (app_config.audio_enable) media_audio_enable();
if (app_config.mp4_enable) {
media_mp4_config();
request_idr();
}
}

respLen = sprintf(response,
Expand Down Expand Up @@ -1358,27 +1362,46 @@ void respond_request(http_request_t *req) {
if (EQUALS(req->method, "POST")) {
char *type = request_header("Content-Type");
if (type && STARTS_WITH(type, "multipart/form-data")) {
char *bound = strstr(type, "boundary=") + strlen("boundary=");

char *payloadb = strstr(req->payload, bound);
payloadb = memstr(payloadb, "\r\n\r\n", req->total - (payloadb - req->input), 4);
if (payloadb) payloadb += 4;

char *payloade = memstr(payloadb, bound,
req->total - (payloadb - req->input), strlen(bound));
if (payloade) payloade -= 4;
char *bound = strstr(type, "boundary=");
char *payloadb = NULL, *payloade = NULL;

if (bound) {
bound += strlen("boundary=");
/* RFC 2046 boundaries are 1 to 70 characters long */
if (*bound && strlen(bound) <= 70)
payloadb = strstr(req->payload, bound);
}
if (payloadb)
payloadb = memstr(payloadb, "\r\n\r\n",
req->total - (payloadb - req->input), 4);
if (payloadb) {
payloadb += 4;
payloade = memstr(payloadb, bound,
req->total - (payloadb - req->input), strlen(bound));
}
if (!payloade || payloade - 4 < payloadb) {
send_http_error(req->clntFd, 400);
return;
}
payloade -= 4;

char path[32];

if (!memcmp(payloadb, "\x89\x50\x4E\x47\xD\xA\x1A\xA", 8))
if (payloade - payloadb >= 8 &&
!memcmp(payloadb, "\x89\x50\x4E\x47\xD\xA\x1A\xA", 8))
sprintf(path, "/tmp/osd%d.png", id);
else
sprintf(path, "/tmp/osd%d.bmp", id);

FILE *img = fopen(path, "wb");
if (!img) {
send_http_error(req->clntFd, 500);
return;
}
fwrite(payloadb, sizeof(char), payloade - payloadb, img);
fclose(img);

strcpy(osds[id].img, path);
strcpy(osds[id].text, "");
osds[id].updt = 1;
} else {
Expand Down
Loading