]> code.delx.au - pulseaudio/commitdiff
latency
authorLennart Poettering <lennart@poettering.net>
Wed, 30 Jun 2004 00:00:52 +0000 (00:00 +0000)
committerLennart Poettering <lennart@poettering.net>
Wed, 30 Jun 2004 00:00:52 +0000 (00:00 +0000)
esound volume changing

git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@43 fefdeb5f-60dc-0310-8127-8f9354f1896f

src/esound-spec.h
src/main.c
src/protocol-esound.c
src/socket-client.c
src/socket-server.c
src/util.c
src/util.h

index 1c2dc02224d345c6720659f7de7d3aeedec3dbe0..f7a4d3db5c86a366ff98df21d95533c48bfa9069 100644 (file)
@@ -181,6 +181,7 @@ typedef int esd_client_state_t;
 
 /* switch endian order for cross platform playing */
 #define swap_endian_32(x) ((x >> 24) | ((x >> 8) & 0xFF00) | (((x & 0xFF00) << 8)) | (x << 24))
+#define maybe_swap_endian_32(c,x) ((c) ? swap_endian_32(x) : x)
 
 /* the endian key is transferred in binary, if it's read into int, */
 /* and matches ESD_ENDIAN_KEY (ENDN), then the endianness of the */
index 3512c5bab91e1220b48e2733797426804eda6426..e50321f8d78218285a4e27676005f43bd911041f 100644 (file)
@@ -38,7 +38,7 @@ int main(int argc, char *argv[]) {
     c = core_new(pa_mainloop_get_api(mainloop));
     assert(c);
 
-    module_load(c, "module-oss", "/dev/dsp1");
+    module_load(c, "module-oss-mmap", "/dev/dsp1");
 /*    module_load(c, "module-pipe-sink", NULL);
     module_load(c, "module-simple-protocol-tcp", NULL);
     module_load(c, "module-simple-protocol-unix", NULL);
index 5db7a13f4927758e67679ce08046bec1a4200646..56c852856d981af7357c09a3a0b0be9be66ec9cf 100644 (file)
@@ -16,6 +16,7 @@
 /* This is heavily based on esound's code */
 
 struct connection {
+    uint32_t index;
     struct protocol_esound *protocol;
     struct iochannel *io;
     struct client *client;
@@ -36,6 +37,7 @@ struct protocol_esound {
     struct socket_server *server;
     struct idxset *connections;
     uint32_t sink_index;
+    unsigned n_player;
 };
 
 typedef struct proto_handler {
@@ -47,7 +49,7 @@ typedef struct proto_handler {
 #define MEMBLOCKQ_LENGTH (10*1204)
 #define MEMBLOCKQ_PREBUF (2*1024)
 
-#define BUFSIZE PIPE_BUF
+#define BUFSIZE (1024)
 
 static void sink_input_drop_cb(struct sink_input *i, size_t length);
 static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk);
@@ -59,6 +61,8 @@ static int esd_proto_stream_play(struct connection *c, const void *data, size_t
 static int esd_proto_stream_record(struct connection *c, const void *data, size_t length);
 static int esd_proto_get_latency(struct connection *c, const void *data, size_t length);
 static int esd_proto_server_info(struct connection *c, const void *data, size_t length);
+static int esd_proto_all_info(struct connection *c, const void *data, size_t length);
+static int esd_proto_stream_pan(struct connection *c, const void *data, size_t length);
 
 static int do_write(struct connection *c);
 
@@ -86,11 +90,11 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = {
     { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" },
 
     { sizeof(int),                    esd_proto_server_info, "server info" },
-    { sizeof(int),                    NULL, "all info" },
+    { sizeof(int),                    esd_proto_all_info, "all info" },
     { -1,                             NULL, "TODO: subscribe" },
     { -1,                             NULL, "TODO: unsubscribe" },
 
-    { 3 * sizeof(int),                NULL, "stream pan"},
+    { 3 * sizeof(int),                esd_proto_stream_pan, "stream pan"},
     { 3 * sizeof(int),                NULL, "sample pan" },
      
     { sizeof(int),                    NULL, "standby mode" },
@@ -102,6 +106,9 @@ static void connection_free(struct connection *c) {
     assert(c);
     idxset_remove_by_data(c->protocol->connections, c, NULL);
 
+    if (c->state == ESD_STREAMING_DATA)
+        c->protocol->n_player--;
+    
     client_free(c->client);
     
     if (c->sink_input)
@@ -170,9 +177,6 @@ static int esd_proto_connect(struct connection *c, const void *data, size_t leng
     ok = connection_write(c, sizeof(int));
     assert(ok);
     *ok = 1;
-
-    do_write(c);
-
     return 0;
 }
 
@@ -183,13 +187,8 @@ static int esd_proto_stream_play(struct connection *c, const void *data, size_t
     struct pa_sample_spec ss;
     assert(length == (sizeof(int)*2+ESD_NAME_MAX));
     
-    format = *(int*)data;
-    rate = *((int*)data + 1);
-
-    if (c->swap_byte_order)
-        format = swap_endian_32(format);
-    if (c->swap_byte_order)
-        rate = swap_endian_32(rate);
+    format = maybe_swap_endian_32(c->swap_byte_order, *(int*)data);
+    rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1));
 
     ss.rate = rate;
     ss.channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1;
@@ -222,6 +221,8 @@ static int esd_proto_stream_play(struct connection *c, const void *data, size_t
     
     c->state = ESD_STREAMING_DATA;
 
+    c->protocol->n_player++;
+    
     return 0;
 }
 
@@ -234,21 +235,19 @@ static int esd_proto_stream_record(struct connection *c, const void *data, size_
 static int esd_proto_get_latency(struct connection *c, const void *data, size_t length) {
     struct sink *sink;
     int latency, *lag;
-    assert(c && data && length == 0);
+    assert(c && !data && length == 0);
 
     if (!(sink = get_output_sink(c->protocol)))
         latency = 0;
     else {
         float usec = sink_get_latency(sink);
-        usec += pa_samples_usec(MEMBLOCKQ_LENGTH, &sink->sample_spec);
-        latency = (int) (usec*441/10000);
+        usec += pa_samples_usec(MEMBLOCKQ_LENGTH-BUFSIZE, &sink->sample_spec);
+        latency = (int) ((usec*44100)/1000000);
     }
     
     lag = connection_write(c, sizeof(int));
     assert(lag);
     *lag = c->swap_byte_order ? swap_endian_32(latency) : latency;
-
-    do_write(c);
     return 0;
 }
 
@@ -267,9 +266,94 @@ static int esd_proto_server_info(struct connection *c, const void *data, size_t
     response = connection_write(c, sizeof(int)*3);
     assert(response);
     *(response++) = 0;
-    *(response++) = c->swap_byte_order ? swap_endian_32(rate) : rate;
-    *(response++) = c->swap_byte_order ? swap_endian_32(format) : format;
-    do_write(c);
+    *(response++) = maybe_swap_endian_32(c->swap_byte_order, rate);
+    *(response++) = maybe_swap_endian_32(c->swap_byte_order, format);
+    return 0;
+}
+
+static int esd_proto_all_info(struct connection *c, const void *data, size_t length) {
+    void *response;
+    size_t t, k, s;
+    struct connection *conn;
+    size_t index = IDXSET_INVALID;
+    assert(c && data && length == sizeof(int));
+    
+    if (esd_proto_server_info(c, data, length) < 0)
+        return -1;
+
+    k = sizeof(int)*5+ESD_NAME_MAX;
+    s = sizeof(int)*6+ESD_NAME_MAX;
+    response = connection_write(c, (t = s+k*(c->protocol->n_player+1)));
+    assert(k);
+
+    for (conn = idxset_first(c->protocol->connections, &index); conn; conn = idxset_next(c->protocol->connections, &index)) {
+        int format = ESD_BITS16 | ESD_STEREO, rate = 44100, volume = 0xFF;
+
+        if (conn->state != ESD_STREAMING_DATA)
+            continue;
+
+        assert(t >= s+k+k);
+        
+        if (conn->sink_input) {
+            rate = conn->sink_input->sample_spec.rate;
+            volume = (conn->sink_input->volume*0xFF)/0x100;
+            format = (conn->sink_input->sample_spec.format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16;
+            format |= (conn->sink_input->sample_spec.channels >= 2) ? ESD_STEREO : ESD_MONO;
+        }
+        
+        /* id */
+        *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (int) conn->index);
+        response += sizeof(int);
+
+        /* name */
+        assert(conn->client);
+        strncpy(response, conn->client->name, ESD_NAME_MAX);
+        response += ESD_NAME_MAX;
+
+        /* rate */
+        *((int*) response) = maybe_swap_endian_32(c->swap_byte_order,  rate);
+        response += sizeof(int);
+
+        /* left */
+        *((int*) response) = maybe_swap_endian_32(c->swap_byte_order,  volume);
+        response += sizeof(int);
+
+        /*right*/
+        *((int*) response) = maybe_swap_endian_32(c->swap_byte_order,  volume);
+        response += sizeof(int);
+
+        /*format*/
+        *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, format);
+        response += sizeof(int);
+
+        t-= k;
+    }
+
+    assert(t == s+k);
+    memset(response, 0, t);
+    return 0;
+}
+
+static int esd_proto_stream_pan(struct connection *c, const void *data, size_t length) {
+    int *ok;
+    uint32_t index, volume;
+    struct connection *conn;
+    assert(c && data && length == sizeof(int)*3);
+    
+    index = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *(int*)data);
+    volume = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1));
+    volume = (volume*0x100)/0xFF;
+
+    ok = connection_write(c, sizeof(int));
+    assert(ok);
+
+    if ((conn = idxset_get_by_index(c->protocol->connections, index))) {
+        assert(conn->sink_input);
+        conn->sink_input->volume = volume;
+        *ok = 1;
+    } else
+        *ok = 0;
+    
     return 0;
 }
 
@@ -380,6 +464,7 @@ static int do_read(struct connection *c) {
         memblock_unref(chunk.memblock);
         assert(c->sink_input);
         sink_notify(c->sink_input->sink);
+
     } else
         assert(0);
 
@@ -487,7 +572,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us
     c->sink_input = NULL;
     c->input_memblockq = NULL;
 
-    idxset_put(c->protocol->connections, c, NULL);
+    idxset_put(c->protocol->connections, c, &c->index);
 }
 
 /*** entry points ***/
@@ -505,6 +590,8 @@ struct protocol_esound* protocol_esound_new(struct core*core, struct socket_serv
     assert(p->connections);
     p->sink_index = IDXSET_INVALID;
 
+    p->n_player = 0;
+
     socket_server_set_callback(p->server, on_connection, p);
 
     return p;
index b10f8ab1a6d3228b276c7d5dc445f3f27323dc14..95c76813e0569299a630a9dfa0f588e14ea79c19 100644 (file)
@@ -120,6 +120,8 @@ struct socket_client* socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t
         goto fail;
     }
 
+    make_tcp_socket_low_delay(c->fd);
+
     sa.sin_family = AF_INET;
     sa.sin_port = htons(port);
     sa.sin_addr.s_addr = htonl(address);
@@ -147,6 +149,8 @@ struct socket_client* socket_client_new_unix(struct pa_mainloop_api *m, const ch
         goto fail;
     }
 
+    make_socket_low_delay(c->fd);
+
     sa.sun_family = AF_LOCAL;
     strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1);
     sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
index 87fe147680181ecd87481dccdbc6bc1de570ec86..bd590f3cb9f8f189bbd94b06e22e1b30202ad3cd 100644 (file)
@@ -11,6 +11,7 @@
 #include <arpa/inet.h>
 
 #include "socket-server.h"
+#include "util.h"
 
 struct socket_server {
     int fd;
@@ -39,6 +40,9 @@ static void callback(struct pa_mainloop_api *mainloop, void *id, int fd, enum pa
         return;
     }
 
+    /* There should be a check for socket type here */
+    make_tcp_socket_low_delay(fd);
+    
     io = iochannel_new(s->mainloop, nfd, nfd);
     assert(io);
     s->on_connection(s, io, s->userdata);
@@ -78,6 +82,8 @@ struct socket_server* socket_server_new_unix(struct pa_mainloop_api *m, const ch
     strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1);
     sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
 
+    make_socket_low_delay(fd);
+    
     if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) {
         fprintf(stderr, "bind(): %s\n", strerror(errno));
         goto fail;
@@ -117,6 +123,8 @@ struct socket_server* socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t
 
     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
         fprintf(stderr, "setsockopt(): %s\n", strerror(errno));
+
+    make_tcp_socket_low_delay(fd);
     
     sa.sin_family = AF_INET;
     sa.sin_port = htons(port);
index 953504218bdb1465faf6c45bd160202f3301808c..8f4443360471a1c26fb9222569a226ac081388d8 100644 (file)
@@ -7,6 +7,8 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/types.h>
+#include <netinet/tcp.h>
+#include <netinet/ip.h>
 
 #include "util.h"
 
@@ -83,3 +85,42 @@ fail:
     rmdir(dir);
     return -1;
 }
+
+int make_socket_low_delay(int fd) {
+    int ret = 0, buf_size, priority;
+
+    assert(fd >= 0);
+
+    buf_size = 1024;
+    if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size)) < 0)
+        ret = -1;
+
+    buf_size = 1024;
+    if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(buf_size)) < 0)
+        ret = -1;
+
+    priority = 7;
+    if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0)
+        ret = -1;
+
+    return ret;
+}
+
+int make_tcp_socket_low_delay(int fd) {
+    int ret, tos, on;
+    
+    assert(fd >= 0);
+
+    ret = make_socket_low_delay(fd);
+    
+    on = 1;
+    if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
+        ret = -1;
+
+    tos = IPTOS_LOWDELAY;
+    if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0)
+        ret = -1;
+
+    return ret;
+
+}
index 2a5071989eb173a983052ee552585d82fa0361ff..8e9a3796fccf8b70c840d7f23d63bc4334d0cdf1 100644 (file)
@@ -7,4 +7,7 @@ void peer_to_string(char *c, size_t l, int fd);
 
 int make_secure_dir(const char* dir);
 
+int make_socket_low_delay(int fd);
+int make_tcp_socket_low_delay(int fd);
+
 #endif