mirror of
https://github.com/badaix/snapcast.git
synced 2025-05-12 16:46:42 +02:00
logging
This commit is contained in:
parent
84cdd5b8ff
commit
e57971c6cb
7 changed files with 671 additions and 52 deletions
100
bug.txt
Normal file
100
bug.txt
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 2552778 > 92, chunks: 35, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 2461512 > 92, chunks: 34, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 2369340 > 92, chunks: 33, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 2276977 > 92, chunks: 32, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 2184579 > 92, chunks: 31, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 2092190 > 92, chunks: 30, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 1999795 > 92, chunks: 29, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 1907409 > 92, chunks: 28, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 1816011 > 92, chunks: 27, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 1723643 > 92, chunks: 26, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 1631253 > 92, chunks: 25, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 1538985 > 92, chunks: 24, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 1446600 > 92, chunks: 23, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 1354213 > 92, chunks: 22, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 1266210 > 92, chunks: 22, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 1173955 > 92, chunks: 21, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 1081592 > 92, chunks: 20, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 989316 > 92, chunks: 19, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 896943 > 92, chunks: 18, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 804551 > 92, chunks: 17, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 712152 > 92, chunks: 16, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 619757 > 92, chunks: 15, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 527375 > 92, chunks: 14, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 434978 > 92, chunks: 13, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 342585 > 92, chunks: 12, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 250190 > 92, chunks: 11, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] sleep > chunk_->getDuration(): 157787 > 92, chunks: 10, out: 100000, needed: 25034013
|
||||||
|
2015-02-11 06-53-30 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 06-53-30 [out] Sleep 65289, age: -27457, bufferDuration: 25034
|
||||||
|
2015-02-11 06-53-30 [out] Chunk: -274 -274 -274 -274 1 100000
|
||||||
|
2015-02-11 06-53-40 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 06-53-40 [out] Sleep 65189, age: 9939282, bufferDuration: 25034
|
||||||
|
2015-02-11 06-53-40 [out] Chunk: 99392 99392 99392 99392 1 100000
|
||||||
|
2015-02-11 06-53-50 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 06-53-50 [out] Sleep 65089, age: 19914052, bufferDuration: 25034
|
||||||
|
2015-02-11 06-53-50 [out] Chunk: 199140 199140 199140 199140 1 100000
|
||||||
|
2015-02-11 06-54-00 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 06-54-00 [out] Sleep 64989, age: 29888939, bufferDuration: 25034
|
||||||
|
2015-02-11 06-54-00 [out] Chunk: 298889 298889 298889 298889 1 100000
|
||||||
|
2015-02-11 06-54-10 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 06-54-10 [out] Sleep 64889, age: 19245105, bufferDuration: 25034
|
||||||
|
2015-02-11 06-54-10 [out] Chunk: 192451 192451 192451 192451 1 100000
|
||||||
|
2015-02-11 06-54-20 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 06-54-20 [out] Sleep 64789, age: 29219324, bufferDuration: 25034
|
||||||
|
2015-02-11 06-54-20 [out] Chunk: 292193 292193 292193 292193 1 100000
|
||||||
|
2015-02-11 06-54-30 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 06-54-30 [out] Sleep 64689, age: 39194206, bufferDuration: 25034
|
||||||
|
2015-02-11 06-54-30 [out] Chunk: 391942 391942 391942 391942 1 100000
|
||||||
|
...
|
||||||
|
2015-02-11 07-16-00 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 07-16-00 [out] Sleep 51789, age: 29166609, bufferDuration: 25034
|
||||||
|
2015-02-11 07-16-00 [out] Chunk: 291666 291666 291666 291666 1 100000
|
||||||
|
2015-02-11 07-16-10 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 07-16-10 [out] Sleep 51689, age: 39141449, bufferDuration: 25034
|
||||||
|
2015-02-11 07-16-10 [out] Chunk: 391414 391414 391414 391414 1 100000
|
||||||
|
2015-02-11 07-16-20 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 07-16-20 [out] Sleep 51589, age: 19208741, bufferDuration: 25034
|
||||||
|
2015-02-11 07-16-20 [out] Chunk: 192087 192087 192087 192087 1 100000
|
||||||
|
2015-02-11 07-16-30 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 07-16-30 [out] Sleep 51489, age: 29183951, bufferDuration: 25034
|
||||||
|
2015-02-11 07-16-30 [out] Chunk: 291839 291839 291839 291839 1 100000
|
||||||
|
2015-02-11 07-16-40 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 07-16-40 [out] Sleep 51389, age: 39158778, bufferDuration: 25034
|
||||||
|
2015-02-11 07-16-40 [out] Chunk: 391587 391587 391587 391587 1 100000
|
||||||
|
2015-02-11 07-16-50 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 07-16-50 [out] Sleep 51289, age: 49133134, bufferDuration: 25034
|
||||||
|
2015-02-11 07-16-50 [out] Chunk: 491331 491331 491331 491331 1 100000
|
||||||
|
2015-02-11 07-17-00 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 07-17-00 [out] Sleep 51189, age: 19170398, bufferDuration: 25034
|
||||||
|
2015-02-11 07-17-00 [out] Chunk: 191703 191703 191703 191703 1 100000
|
||||||
|
2015-02-11 07-17-10 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 07-17-10 [out] Sleep 51089, age: 29145503, bufferDuration: 25034
|
||||||
|
2015-02-11 07-17-10 [out] Chunk: 291455 291455 291455 291455 1 100000
|
||||||
|
2015-02-11 07-17-20 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 07-17-20 [out] Sleep 50989, age: 39119549, bufferDuration: 25034
|
||||||
|
2015-02-11 07-17-20 [out] Chunk: 391195 391195 391195 391195 1 100000
|
||||||
|
2015-02-11 07-17-30 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 07-17-30 [out] Sleep 50889, age: 49094582, bufferDuration: 25034
|
||||||
|
2015-02-11 07-17-30 [out] Chunk: 490945 490945 490945 490945 1 100000
|
||||||
|
2015-02-11 07-17-40 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 07-17-40 [out] Sleep 50789, age: 19224557, bufferDuration: 25034
|
||||||
|
2015-02-11 07-17-40 [out] Chunk: 192245 192245 192245 192245 1 100000
|
||||||
|
2015-02-11 07-17-50 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 07-17-50 [out] Sleep 50689, age: 29199351, bufferDuration: 25034
|
||||||
|
2015-02-11 07-17-50 [out] Chunk: 291993 291993 291993 291993 1 100000
|
||||||
|
2015-02-11 07-18-00 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 07-18-00 [out] Sleep 50589, age: 39174527, bufferDuration: 25034
|
||||||
|
2015-02-11 07-18-00 [out] Chunk: 391745 391745 391745 391745 1 100000
|
||||||
|
2015-02-11 07-18-10 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 07-18-10 [out] Sleep 50489, age: 19242269, bufferDuration: 25034
|
||||||
|
2015-02-11 07-18-10 [out] Chunk: 192422 192422 192422 192422 1 100000
|
||||||
|
2015-02-11 07-18-20 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 07-18-20 [out] Sleep 50389, age: 29216343, bufferDuration: 25034
|
||||||
|
2015-02-11 07-18-20 [out] Chunk: 292163 292163 292163 292163 1 100000
|
||||||
|
^[[5~2015-02-11 07-18-30 [out] correction: 4, factor: 1.00362
|
||||||
|
2015-02-11 07-18-30 [out] Sleep 50289, age: 39191836, bufferDuration: 25034
|
||||||
|
2015-02-11 07-18-30 [out] Chunk: 391918 391918 391918 391918 1 100000
|
||||||
|
|
||||||
|
|
||||||
|
|
201
client/browseAvahi.cpp
Normal file
201
client/browseAvahi.cpp
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
/***
|
||||||
|
This file is part of avahi.
|
||||||
|
|
||||||
|
avahi is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as
|
||||||
|
published by the Free Software Foundation; either version 2.1 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
avahi is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
|
||||||
|
Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with avahi; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
USA.
|
||||||
|
***/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <avahi-client/client.h>
|
||||||
|
#include <avahi-client/lookup.h>
|
||||||
|
|
||||||
|
#include <avahi-common/simple-watch.h>
|
||||||
|
#include <avahi-common/malloc.h>
|
||||||
|
#include <avahi-common/error.h>
|
||||||
|
|
||||||
|
static AvahiSimplePoll *simple_poll = NULL;
|
||||||
|
|
||||||
|
static void resolve_callback(
|
||||||
|
AvahiServiceResolver *r,
|
||||||
|
AVAHI_GCC_UNUSED AvahiIfIndex interface,
|
||||||
|
AVAHI_GCC_UNUSED AvahiProtocol protocol,
|
||||||
|
AvahiResolverEvent event,
|
||||||
|
const char *name,
|
||||||
|
const char *type,
|
||||||
|
const char *domain,
|
||||||
|
const char *host_name,
|
||||||
|
const AvahiAddress *address,
|
||||||
|
uint16_t port,
|
||||||
|
AvahiStringList *txt,
|
||||||
|
AvahiLookupResultFlags flags,
|
||||||
|
AVAHI_GCC_UNUSED void* userdata) {
|
||||||
|
|
||||||
|
assert(r);
|
||||||
|
|
||||||
|
/* Called whenever a service has been resolved successfully or timed out */
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case AVAHI_RESOLVER_FAILURE:
|
||||||
|
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AVAHI_RESOLVER_FOUND: {
|
||||||
|
char a[AVAHI_ADDRESS_STR_MAX], *t;
|
||||||
|
|
||||||
|
fprintf(stderr, "Service '%s' of type '%s' in domain '%s':\n", name, type, domain);
|
||||||
|
|
||||||
|
avahi_address_snprint(a, sizeof(a), address);
|
||||||
|
t = avahi_string_list_to_string(txt);
|
||||||
|
fprintf(stderr,
|
||||||
|
"\t%s:%u (%s)\n"
|
||||||
|
"\tTXT=%s\n"
|
||||||
|
"\tProto=%i\n"
|
||||||
|
"\tcookie is %u\n"
|
||||||
|
"\tis_local: %i\n"
|
||||||
|
"\tour_own: %i\n"
|
||||||
|
"\twide_area: %i\n"
|
||||||
|
"\tmulticast: %i\n"
|
||||||
|
"\tcached: %i\n",
|
||||||
|
host_name, port, a,
|
||||||
|
t,
|
||||||
|
(int)protocol,
|
||||||
|
avahi_string_list_get_service_cookie(txt),
|
||||||
|
!!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
|
||||||
|
!!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
|
||||||
|
!!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
|
||||||
|
!!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
|
||||||
|
!!(flags & AVAHI_LOOKUP_RESULT_CACHED));
|
||||||
|
|
||||||
|
avahi_free(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
avahi_service_resolver_free(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void browse_callback(
|
||||||
|
AvahiServiceBrowser *b,
|
||||||
|
AvahiIfIndex interface,
|
||||||
|
AvahiProtocol protocol,
|
||||||
|
AvahiBrowserEvent event,
|
||||||
|
const char *name,
|
||||||
|
const char *type,
|
||||||
|
const char *domain,
|
||||||
|
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
|
||||||
|
void* userdata) {
|
||||||
|
|
||||||
|
AvahiClient *c = (AvahiClient*)userdata;
|
||||||
|
assert(b);
|
||||||
|
|
||||||
|
/* Called whenever a new services becomes available on the LAN or is removed from the LAN */
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case AVAHI_BROWSER_FAILURE:
|
||||||
|
|
||||||
|
fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
|
||||||
|
avahi_simple_poll_quit(simple_poll);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case AVAHI_BROWSER_NEW:
|
||||||
|
fprintf(stderr, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
|
||||||
|
|
||||||
|
/* We ignore the returned resolver object. In the callback
|
||||||
|
function we free it. If the server is terminated before
|
||||||
|
the callback function is called the server will free
|
||||||
|
the resolver for us. */
|
||||||
|
|
||||||
|
if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, (AvahiLookupFlags)0, resolve_callback, c)))
|
||||||
|
fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c)));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AVAHI_BROWSER_REMOVE:
|
||||||
|
fprintf(stderr, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AVAHI_BROWSER_ALL_FOR_NOW:
|
||||||
|
case AVAHI_BROWSER_CACHE_EXHAUSTED:
|
||||||
|
fprintf(stderr, "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) {
|
||||||
|
assert(c);
|
||||||
|
|
||||||
|
/* Called whenever the client or server state changes */
|
||||||
|
|
||||||
|
if (state == AVAHI_CLIENT_FAILURE) {
|
||||||
|
fprintf(stderr, "Server connection failure: %s\n", avahi_strerror(avahi_client_errno(c)));
|
||||||
|
avahi_simple_poll_quit(simple_poll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
|
||||||
|
AvahiClient *client = NULL;
|
||||||
|
AvahiServiceBrowser *sb = NULL;
|
||||||
|
int error;
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
/* Allocate main loop object */
|
||||||
|
if (!(simple_poll = avahi_simple_poll_new())) {
|
||||||
|
fprintf(stderr, "Failed to create simple poll object.\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate a new client */
|
||||||
|
client = avahi_client_new(avahi_simple_poll_get(simple_poll), (AvahiClientFlags)0, client_callback, NULL, &error);
|
||||||
|
|
||||||
|
/* Check wether creating the client object succeeded */
|
||||||
|
if (!client) {
|
||||||
|
fprintf(stderr, "Failed to create client: %s\n", avahi_strerror(error));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the service browser */
|
||||||
|
if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_snapcast._tcp", NULL, (AvahiLookupFlags)0, browse_callback, client))) {
|
||||||
|
fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client)));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Run the main loop */
|
||||||
|
avahi_simple_poll_loop(simple_poll);
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
|
||||||
|
/* Cleanup things */
|
||||||
|
if (sb)
|
||||||
|
avahi_service_browser_free(sb);
|
||||||
|
|
||||||
|
if (client)
|
||||||
|
avahi_client_free(client);
|
||||||
|
|
||||||
|
if (simple_poll)
|
||||||
|
avahi_simple_poll_free(simple_poll);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
#include "timeProvider.h"
|
#include "timeProvider.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace chronos;
|
//using namespace chronos;
|
||||||
|
namespace cs = chronos;
|
||||||
|
|
||||||
|
|
||||||
Stream::Stream(const msg::SampleFormat& sampleFormat) : format_(sampleFormat), sleep_(0), median_(0), shortMedian_(0), lastUpdate_(0), playedFrames_(0)
|
Stream::Stream(const msg::SampleFormat& sampleFormat) : format_(sampleFormat), sleep_(0), median_(0), shortMedian_(0), lastUpdate_(0), playedFrames_(0)
|
||||||
|
@ -14,7 +15,7 @@ Stream::Stream(const msg::SampleFormat& sampleFormat) : format_(sampleFormat), s
|
||||||
shortBuffer_.setSize(100);
|
shortBuffer_.setSize(100);
|
||||||
miniBuffer_.setSize(20);
|
miniBuffer_.setSize(20);
|
||||||
// cardBuffer_.setSize(50);
|
// cardBuffer_.setSize(50);
|
||||||
bufferMs_ = msec(500);
|
bufferMs_ = cs::msec(500);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
48000 x
|
48000 x
|
||||||
|
@ -39,7 +40,7 @@ void Stream::setRealSampleRate(double sampleRate)
|
||||||
|
|
||||||
void Stream::setBufferLen(size_t bufferLenMs)
|
void Stream::setBufferLen(size_t bufferLenMs)
|
||||||
{
|
{
|
||||||
bufferMs_ = msec(bufferLenMs);
|
bufferMs_ = cs::msec(bufferLenMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,7 +54,7 @@ void Stream::clearChunks()
|
||||||
|
|
||||||
void Stream::addChunk(msg::PcmChunk* chunk)
|
void Stream::addChunk(msg::PcmChunk* chunk)
|
||||||
{
|
{
|
||||||
while (chunks_.size() * chunk->duration<chronos::msec>().count() > 10000)
|
while (chunks_.size() * chunk->duration<cs::msec>().count() > 10000)
|
||||||
chunks_.pop();
|
chunks_.pop();
|
||||||
chunks_.push(shared_ptr<msg::PcmChunk>(chunk));
|
chunks_.push(shared_ptr<msg::PcmChunk>(chunk));
|
||||||
// logD << "new chunk: " << chunk_->getDuration() << ", Chunks: " << chunks_.size() << "\n";
|
// logD << "new chunk: " << chunk_->getDuration() << ", Chunks: " << chunks_.size() << "\n";
|
||||||
|
@ -61,11 +62,11 @@ void Stream::addChunk(msg::PcmChunk* chunk)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
time_point_hrc Stream::getSilentPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer)
|
cs::time_point_hrc Stream::getSilentPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer)
|
||||||
{
|
{
|
||||||
if (!chunk_)
|
if (!chunk_)
|
||||||
chunk_ = chunks_.pop();
|
chunk_ = chunks_.pop();
|
||||||
time_point_hrc tp = chunk_->start();
|
cs::time_point_hrc tp = chunk_->start();
|
||||||
memset(outputBuffer, 0, framesPerBuffer * format_.frameSize);
|
memset(outputBuffer, 0, framesPerBuffer * format_.frameSize);
|
||||||
return tp;
|
return tp;
|
||||||
}
|
}
|
||||||
|
@ -98,10 +99,10 @@ time_point_hrc Stream::seek(long ms)
|
||||||
return chunk_->start();
|
return chunk_->start();
|
||||||
|
|
||||||
// time_point_ms tp = chunk_->timePoint();
|
// time_point_ms tp = chunk_->timePoint();
|
||||||
while (ms > chunk_->duration<chronos::msec>().count())
|
while (ms > chunk_->duration<cs::msec>().count())
|
||||||
{
|
{
|
||||||
chunk_ = chunks_.pop();
|
chunk_ = chunks_.pop();
|
||||||
ms -= min(ms, (long)chunk_->durationLeft<chronos::msec>().count());
|
ms -= min(ms, (long)chunk_->durationLeft<cs::msec>().count());
|
||||||
}
|
}
|
||||||
chunk_->seek(ms * format_.msRate());
|
chunk_->seek(ms * format_.msRate());
|
||||||
return chunk_->start();
|
return chunk_->start();
|
||||||
|
@ -109,12 +110,12 @@ time_point_hrc Stream::seek(long ms)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
time_point_hrc Stream::getNextPlayerChunk(void* outputBuffer, const chronos::usec& timeout, unsigned long framesPerBuffer)
|
cs::time_point_hrc Stream::getNextPlayerChunk(void* outputBuffer, const cs::usec& timeout, unsigned long framesPerBuffer)
|
||||||
{
|
{
|
||||||
if (!chunk_ && !chunks_.try_pop(chunk_, timeout))
|
if (!chunk_ && !chunks_.try_pop(chunk_, timeout))
|
||||||
throw 0;
|
throw 0;
|
||||||
|
|
||||||
time_point_hrc tp = chunk_->start();
|
cs::time_point_hrc tp = chunk_->start();
|
||||||
char* buffer = (char*)outputBuffer;
|
char* buffer = (char*)outputBuffer;
|
||||||
unsigned long read = 0;
|
unsigned long read = 0;
|
||||||
while (read < framesPerBuffer)
|
while (read < framesPerBuffer)
|
||||||
|
@ -127,14 +128,14 @@ time_point_hrc Stream::getNextPlayerChunk(void* outputBuffer, const chronos::use
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
time_point_hrc Stream::getNextPlayerChunk(void* outputBuffer, const chronos::usec& timeout, unsigned long framesPerBuffer, long framesCorrection)
|
cs::time_point_hrc Stream::getNextPlayerChunk(void* outputBuffer, const cs::usec& timeout, unsigned long framesPerBuffer, long framesCorrection)
|
||||||
{
|
{
|
||||||
if (framesCorrection == 0)
|
if (framesCorrection == 0)
|
||||||
return getNextPlayerChunk(outputBuffer, timeout, framesPerBuffer);
|
return getNextPlayerChunk(outputBuffer, timeout, framesPerBuffer);
|
||||||
|
|
||||||
long toRead = framesPerBuffer + framesCorrection;
|
long toRead = framesPerBuffer + framesCorrection;
|
||||||
char* buffer = (char*)malloc(toRead * format_.frameSize);
|
char* buffer = (char*)malloc(toRead * format_.frameSize);
|
||||||
time_point_hrc tp = getNextPlayerChunk(buffer, timeout, toRead);
|
cs::time_point_hrc tp = getNextPlayerChunk(buffer, timeout, toRead);
|
||||||
|
|
||||||
float factor = (float)toRead / framesPerBuffer;//(float)(framesPerBuffer*channels_);
|
float factor = (float)toRead / framesPerBuffer;//(float)(framesPerBuffer*channels_);
|
||||||
if (abs(framesCorrection) > 1)
|
if (abs(framesCorrection) > 1)
|
||||||
|
@ -170,28 +171,33 @@ void Stream::resetBuffers()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool Stream::getPlayerChunk(void* outputBuffer, const chronos::usec& outputBufferDacTime, unsigned long framesPerBuffer)
|
bool Stream::getPlayerChunk(void* outputBuffer, const cs::usec& outputBufferDacTime, unsigned long framesPerBuffer)
|
||||||
{
|
{
|
||||||
if (outputBufferDacTime > bufferMs_)
|
if (outputBufferDacTime > bufferMs_)
|
||||||
{
|
{
|
||||||
logO << "outputBufferDacTime > bufferMs: " << outputBufferDacTime.count() << " > " << std::chrono::duration_cast<usec>(bufferMs_).count() << "\n";
|
logO << "outputBufferDacTime > bufferMs: " << cs::duration<cs::msec>(outputBufferDacTime) << " > " << cs::duration<cs::msec>(bufferMs_) << "\n";
|
||||||
sleep_ = chronos::usec(0);
|
sleep_ = cs::usec(0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!chunk_ && !chunks_.try_pop(chunk_, outputBufferDacTime))
|
if (!chunk_ && !chunks_.try_pop(chunk_, outputBufferDacTime))
|
||||||
{
|
{
|
||||||
logO << "!chunk_ && !chunks_.try_pop(chunk_, outputBufferDacTime)\n";
|
logO << "no chunks available\n";
|
||||||
sleep_ = chronos::usec(0);
|
sleep_ = cs::usec(0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
playedFrames_ += framesPerBuffer;
|
playedFrames_ += framesPerBuffer;
|
||||||
|
|
||||||
chronos::usec age = std::chrono::duration_cast<usec>(TimeProvider::serverNow() - chunk_->start() - bufferMs_ + outputBufferDacTime);
|
/// we have a chunk
|
||||||
if ((sleep_.count() == 0) && (chronos::abs(age) > chronos::msec(200)))
|
/// age = chunk age (server now - rec time: some positive value) - buffer (e.g. 1000ms) + time to DAC
|
||||||
|
/// age = 0 => play now
|
||||||
|
/// age < 0 => play in -age
|
||||||
|
/// age > 0 => too old
|
||||||
|
cs::usec age = std::chrono::duration_cast<cs::usec>(TimeProvider::serverNow() - chunk_->start() - bufferMs_ + outputBufferDacTime);
|
||||||
|
if ((sleep_.count() == 0) && (cs::abs(age) > cs::msec(200)))
|
||||||
{
|
{
|
||||||
logO << "age > 200: " << age.count() << "\n";
|
logO << "age > 200: " << cs::duration<cs::msec>(age) << "\n";
|
||||||
sleep_ = age;
|
sleep_ = age;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,54 +205,56 @@ bool Stream::getPlayerChunk(void* outputBuffer, const chronos::usec& outputBuffe
|
||||||
{
|
{
|
||||||
|
|
||||||
//logD << "framesPerBuffer: " << framesPerBuffer << "\tms: " << framesPerBuffer*2 / PLAYER_CHUNK_MS_SIZE << "\t" << PLAYER_CHUNK_SIZE << "\n";
|
//logD << "framesPerBuffer: " << framesPerBuffer << "\tms: " << framesPerBuffer*2 / PLAYER_CHUNK_MS_SIZE << "\t" << PLAYER_CHUNK_SIZE << "\n";
|
||||||
chronos::nsec bufferDuration = chronos::nsec(chronos::usec::rep(framesPerBuffer / format_.nsRate()));
|
cs::nsec bufferDuration = cs::nsec(cs::nsec::rep(framesPerBuffer / format_.nsRate()));
|
||||||
// logD << "buffer duration: " << bufferDuration.count() << "\n";
|
// logD << "buffer duration: " << bufferDuration.count() << "\n";
|
||||||
|
|
||||||
chronos::usec correction = chronos::usec(0);
|
cs::usec correction = cs::usec(0);
|
||||||
if (sleep_.count() != 0)
|
if (sleep_.count() != 0)
|
||||||
{
|
{
|
||||||
resetBuffers();
|
resetBuffers();
|
||||||
if (sleep_ < -bufferDuration/2)
|
if (sleep_ < -bufferDuration/2)
|
||||||
{
|
{
|
||||||
|
logO << "sleep < -bufferDuration/2: " << cs::duration<cs::msec>(sleep_) << " < " << -cs::duration<cs::msec>(bufferDuration)/2 << ", ";
|
||||||
// We're early: not enough chunks_. play silence. Reference chunk_ is the oldest (front) one
|
// We're early: not enough chunks_. play silence. Reference chunk_ is the oldest (front) one
|
||||||
sleep_ = chrono::duration_cast<usec>(TimeProvider::serverNow() - getSilentPlayerChunk(outputBuffer, framesPerBuffer) - bufferMs_ + outputBufferDacTime);
|
sleep_ = chrono::duration_cast<cs::usec>(TimeProvider::serverNow() - getSilentPlayerChunk(outputBuffer, framesPerBuffer) - bufferMs_ + outputBufferDacTime);
|
||||||
//logD << "-sleep: " << sleep_.count() << " " << -bufferDuration.count() / 2000 << "\n";
|
logO << "sleep: " << cs::duration<cs::msec>(sleep_) << "\n";
|
||||||
if (sleep_ < -bufferDuration/2)
|
if (sleep_ < -bufferDuration/2)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (sleep_ > bufferDuration/2)
|
else if (sleep_ > bufferDuration/2)
|
||||||
{
|
{
|
||||||
|
logO << "sleep > bufferDuration/2: " << cs::duration<cs::msec>(sleep_) << " > " << cs::duration<cs::msec>(bufferDuration)/2 << "\n";
|
||||||
// We're late: discard oldest chunks
|
// We're late: discard oldest chunks
|
||||||
while (sleep_ > chunk_->duration<chronos::usec>())
|
while (sleep_ > chunk_->duration<cs::usec>())
|
||||||
{
|
{
|
||||||
logO << "sleep > chunk_->getDuration(): " << sleep_.count() << " > " << chunk_->duration<chronos::msec>().count() << ", chunks: " << chunks_.size() << ", out: " << outputBufferDacTime.count() << ", needed: " << bufferDuration.count() << "\n";
|
logO << "sleep > chunkDuration: " << cs::duration<cs::msec>(sleep_) << " > " << chunk_->duration<cs::msec>().count() << ", chunks: " << chunks_.size() << ", out: " << cs::duration<cs::msec>(outputBufferDacTime) << ", needed: " << cs::duration<cs::msec>(bufferDuration) << "\n";
|
||||||
sleep_ = std::chrono::duration_cast<usec>(TimeProvider::serverNow() - chunk_->start() - bufferMs_ + outputBufferDacTime);
|
sleep_ = std::chrono::duration_cast<cs::usec>(TimeProvider::serverNow() - chunk_->start() - bufferMs_ + outputBufferDacTime);
|
||||||
if (!chunks_.try_pop(chunk_, outputBufferDacTime))
|
if (!chunks_.try_pop(chunk_, outputBufferDacTime))
|
||||||
{
|
{
|
||||||
logO << "no chunks available\n";
|
logO << "no chunks available\n";
|
||||||
chunk_ = NULL;
|
chunk_ = NULL;
|
||||||
sleep_ = chronos::usec(0);
|
sleep_ = cs::usec(0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// out of sync, can be corrected by playing faster/slower
|
// out of sync, can be corrected by playing faster/slower
|
||||||
if (sleep_ < -chronos::usec(100))
|
if (sleep_ < -cs::usec(100))
|
||||||
{
|
{
|
||||||
sleep_ += chronos::usec(100);
|
sleep_ += cs::usec(100);
|
||||||
correction = -chronos::usec(100);
|
correction = -cs::usec(100);
|
||||||
}
|
}
|
||||||
else if (sleep_ > chronos::usec(100))
|
else if (sleep_ > cs::usec(100))
|
||||||
{
|
{
|
||||||
sleep_ -= chronos::usec(100);
|
sleep_ -= cs::usec(100);
|
||||||
correction = chronos::usec(100);
|
correction = cs::usec(100);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logO << "Sleep " << sleep_.count() << "\n";
|
logO << "Sleep " << cs::duration<cs::msec>(sleep_) << "\n";
|
||||||
correction = sleep_;
|
correction = sleep_;
|
||||||
sleep_ = chronos::usec(0);
|
sleep_ = cs::usec(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,55 +265,55 @@ bool Stream::getPlayerChunk(void* outputBuffer, const chronos::usec& outputBuffe
|
||||||
playedFrames_ -= abs(correctAfterXFrames_);
|
playedFrames_ -= abs(correctAfterXFrames_);
|
||||||
}
|
}
|
||||||
|
|
||||||
age = std::chrono::duration_cast<usec>(TimeProvider::serverNow() - getNextPlayerChunk(outputBuffer, outputBufferDacTime, framesPerBuffer, framesCorrection) - bufferMs_ + outputBufferDacTime);
|
age = std::chrono::duration_cast<cs::usec>(TimeProvider::serverNow() - getNextPlayerChunk(outputBuffer, outputBufferDacTime, framesPerBuffer, framesCorrection) - bufferMs_ + outputBufferDacTime);
|
||||||
|
|
||||||
setRealSampleRate(format_.rate);
|
setRealSampleRate(format_.rate);
|
||||||
if (sleep_.count() == 0)
|
if (sleep_.count() == 0)
|
||||||
{
|
{
|
||||||
if (buffer_.full())
|
if (buffer_.full())
|
||||||
{
|
{
|
||||||
if (chronos::usec(abs(median_)) > chronos::msec(1))
|
if (cs::usec(abs(median_)) > cs::msec(1))
|
||||||
{
|
{
|
||||||
logO << "pBuffer->full() && (abs(median_) > 1): " << median_ << "\n";
|
logO << "pBuffer->full() && (abs(median_) > 1): " << median_ << "\n";
|
||||||
sleep_ = chronos::usec(shortMedian_);
|
sleep_ = cs::usec(shortMedian_);
|
||||||
}
|
}
|
||||||
/* else if (chronos::usec(median_) > chronos::usec(300))
|
/* else if (cs::usec(median_) > cs::usec(300))
|
||||||
{
|
{
|
||||||
setRealSampleRate(format_.rate - format_.rate / 1000);
|
setRealSampleRate(format_.rate - format_.rate / 1000);
|
||||||
}
|
}
|
||||||
else if (chronos::usec(median_) < -chronos::usec(300))
|
else if (cs::usec(median_) < -cs::usec(300))
|
||||||
{
|
{
|
||||||
setRealSampleRate(format_.rate + format_.rate / 1000);
|
setRealSampleRate(format_.rate + format_.rate / 1000);
|
||||||
}
|
}
|
||||||
*/ }
|
*/ }
|
||||||
else if (shortBuffer_.full())
|
else if (shortBuffer_.full())
|
||||||
{
|
{
|
||||||
if (chronos::usec(abs(shortMedian_)) > chronos::msec(5))
|
if (cs::usec(abs(shortMedian_)) > cs::msec(5))
|
||||||
{
|
{
|
||||||
logO << "pShortBuffer->full() && (abs(shortMedian_) > 5): " << shortMedian_ << "\n";
|
logO << "pShortBuffer->full() && (abs(shortMedian_) > 5): " << shortMedian_ << "\n";
|
||||||
sleep_ = chronos::usec(shortMedian_);
|
sleep_ = cs::usec(shortMedian_);
|
||||||
}
|
}
|
||||||
/* else
|
/* else
|
||||||
{
|
{
|
||||||
setRealSampleRate(format_.rate + -shortMedian_ / 100);
|
setRealSampleRate(format_.rate + -shortMedian_ / 100);
|
||||||
}
|
}
|
||||||
*/ }
|
*/ }
|
||||||
else if (miniBuffer_.full() && (chronos::usec(abs(miniBuffer_.median())) > chronos::msec(50)))
|
else if (miniBuffer_.full() && (cs::usec(abs(miniBuffer_.median())) > cs::msec(50)))
|
||||||
{
|
{
|
||||||
logO << "pMiniBuffer->full() && (abs(pMiniBuffer->mean()) > 50): " << miniBuffer_.median() << "\n";
|
logO << "pMiniBuffer->full() && (abs(pMiniBuffer->mean()) > 50): " << miniBuffer_.median() << "\n";
|
||||||
sleep_ = chronos::usec((chronos::msec::rep)miniBuffer_.mean());
|
sleep_ = cs::usec((cs::msec::rep)miniBuffer_.mean());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sleep_.count() != 0)
|
if (sleep_.count() != 0)
|
||||||
{
|
{
|
||||||
logO << "Sleep " << sleep_.count() << ", age: " << age.count() << ", bufferDuration: " << std::chrono::duration_cast<usec>(bufferDuration).count() << "\n";
|
logO << "Sleep " << cs::duration<cs::msec>(sleep_) << ", age: " << cs::duration<cs::msec>(age) << ", bufferDuration: " << cs::duration<cs::msec>(bufferDuration) << "\n";
|
||||||
}
|
}
|
||||||
else if (shortBuffer_.full())
|
else if (shortBuffer_.full())
|
||||||
{
|
{
|
||||||
if (chronos::usec(shortMedian_) > chronos::usec(100))
|
if (cs::usec(shortMedian_) > cs::usec(100))
|
||||||
setRealSampleRate(format_.rate * 0.9999);
|
setRealSampleRate(format_.rate * 0.9999);
|
||||||
else if (chronos::usec(shortMedian_) < -chronos::usec(100))
|
else if (cs::usec(shortMedian_) < -cs::usec(100))
|
||||||
setRealSampleRate(format_.rate * 1.0001);
|
setRealSampleRate(format_.rate * 1.0001);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,13 +326,13 @@ bool Stream::getPlayerChunk(void* outputBuffer, const chronos::usec& outputBuffe
|
||||||
lastUpdate_ = now;
|
lastUpdate_ = now;
|
||||||
median_ = buffer_.median();
|
median_ = buffer_.median();
|
||||||
shortMedian_ = shortBuffer_.median();
|
shortMedian_ = shortBuffer_.median();
|
||||||
logO << "Chunk: " << age.count()/100 << "\t" << miniBuffer_.median()/100 << "\t" << shortMedian_/100 << "\t" << median_/100 << "\t" << buffer_.size() << "\t" << outputBufferDacTime.count() << "\n";
|
logO << "Chunk: " << age.count()/100 << "\t" << miniBuffer_.median()/100 << "\t" << shortMedian_/100 << "\t" << median_/100 << "\t" << buffer_.size() << "\t" << cs::duration<cs::msec>(outputBufferDacTime) << "\n";
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch(int e)
|
catch(int e)
|
||||||
{
|
{
|
||||||
sleep_ = chronos::usec(0);
|
sleep_ = cs::usec(0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,12 @@ namespace chronos
|
||||||
Rep x = d.count();
|
Rep x = d.count();
|
||||||
return std::chrono::duration<Rep, Period>(x >= 0 ? x : -x);
|
return std::chrono::duration<Rep, Period>(x >= 0 ? x : -x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class ToDuration, class Rep, class Period>
|
||||||
|
int64_t duration(std::chrono::duration<Rep, Period> d)
|
||||||
|
{
|
||||||
|
return std::chrono::duration_cast<ToDuration>(d).count();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
271
server/publishAvahi.cpp
Normal file
271
server/publishAvahi.cpp
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
/***
|
||||||
|
This file is part of avahi.
|
||||||
|
|
||||||
|
avahi is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as
|
||||||
|
published by the Free Software Foundation; either version 2.1 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
avahi is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
|
||||||
|
Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with avahi; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
USA.
|
||||||
|
***/
|
||||||
|
|
||||||
|
#include "publishAvahi.h"
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <avahi-client/client.h>
|
||||||
|
#include <avahi-client/publish.h>
|
||||||
|
|
||||||
|
#include <avahi-common/alternative.h>
|
||||||
|
#include <avahi-common/simple-watch.h>
|
||||||
|
#include <avahi-common/malloc.h>
|
||||||
|
#include <avahi-common/error.h>
|
||||||
|
#include <avahi-common/timeval.h>
|
||||||
|
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
PublishAvahi::PublishAvahi() : group(NULL), simple_poll(NULL), name(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PublishAvahi::~PublishAvahi()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PublishAvahi::entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void *userdata) {
|
||||||
|
assert(g == group || group == NULL);
|
||||||
|
group = g;
|
||||||
|
|
||||||
|
/* Called whenever the entry group state changes */
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case AVAHI_ENTRY_GROUP_ESTABLISHED :
|
||||||
|
/* The entry group has been established successfully */
|
||||||
|
fprintf(stderr, "Service '%s' successfully established.\n", name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AVAHI_ENTRY_GROUP_COLLISION : {
|
||||||
|
char *n;
|
||||||
|
|
||||||
|
/* A service name collision with a remote service
|
||||||
|
* happened. Let's pick a new name */
|
||||||
|
n = avahi_alternative_service_name(name);
|
||||||
|
avahi_free(name);
|
||||||
|
name = n;
|
||||||
|
|
||||||
|
fprintf(stderr, "Service name collision, renaming service to '%s'\n", name);
|
||||||
|
|
||||||
|
/* And recreate the services */
|
||||||
|
create_services(avahi_entry_group_get_client(g));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AVAHI_ENTRY_GROUP_FAILURE :
|
||||||
|
|
||||||
|
fprintf(stderr, "Entry group failure: %s\n", avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))));
|
||||||
|
|
||||||
|
/* Some kind of failure happened while we were registering our services */
|
||||||
|
avahi_simple_poll_quit(simple_poll);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AVAHI_ENTRY_GROUP_UNCOMMITED:
|
||||||
|
case AVAHI_ENTRY_GROUP_REGISTERING:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PublishAvahi::create_services(AvahiClient *c) {
|
||||||
|
char *n, r[128];
|
||||||
|
int ret;
|
||||||
|
assert(c);
|
||||||
|
|
||||||
|
/* If this is the first time we're called, let's create a new
|
||||||
|
* entry group if necessary */
|
||||||
|
|
||||||
|
if (!group)
|
||||||
|
{
|
||||||
|
if (!(group = avahi_entry_group_new(c, (void(*)(AvahiEntryGroup*, AvahiEntryGroupState, void*))std::bind(&PublishAvahi::entry_group_callback, this), NULL))) {
|
||||||
|
fprintf(stderr, "avahi_entry_group_new() failed: %s\n", avahi_strerror(avahi_client_errno(c)));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* If the group is empty (either because it was just created, or
|
||||||
|
* because it was reset previously, add our entries. */
|
||||||
|
|
||||||
|
if (avahi_entry_group_is_empty(group)) {
|
||||||
|
fprintf(stderr, "Adding service '%s'\n", name);
|
||||||
|
|
||||||
|
/* Create some random TXT data */
|
||||||
|
snprintf(r, sizeof(r), "random=%i", rand());
|
||||||
|
|
||||||
|
/* We will now add two services and one subtype to the entry
|
||||||
|
* group. The two services have the same name, but differ in
|
||||||
|
* the service type (IPP vs. BSD LPR). Only services with the
|
||||||
|
* same name should be put in the same entry group. */
|
||||||
|
|
||||||
|
/* Add the service for IPP */
|
||||||
|
/* if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AVAHI_PUBLISH_UNIQUE, name, "_ipp._tcp", NULL, NULL, 651, "test=blah", r, NULL)) < 0) {
|
||||||
|
|
||||||
|
if (ret == AVAHI_ERR_COLLISION)
|
||||||
|
goto collision;
|
||||||
|
|
||||||
|
fprintf(stderr, "Failed to add _ipp._tcp service: %s\n", avahi_strerror(ret));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/* Add the same service for BSD LPR */
|
||||||
|
if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name, "_snapcast._tcp", NULL, NULL, 515, NULL)) < 0) {
|
||||||
|
|
||||||
|
if (ret == AVAHI_ERR_COLLISION)
|
||||||
|
goto collision;
|
||||||
|
|
||||||
|
fprintf(stderr, "Failed to add _snapcast._tcp service: %s\n", avahi_strerror(ret));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add an additional (hypothetic) subtype */
|
||||||
|
/* if ((ret = avahi_entry_group_add_service_subtype(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name, "_printer._tcp", NULL, "_magic._sub._printer._tcp") < 0)) {
|
||||||
|
fprintf(stderr, "Failed to add subtype _magic._sub._printer._tcp: %s\n", avahi_strerror(ret));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/* Tell the server to register the service */
|
||||||
|
if ((ret = avahi_entry_group_commit(group)) < 0) {
|
||||||
|
fprintf(stderr, "Failed to commit entry group: %s\n", avahi_strerror(ret));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
collision:
|
||||||
|
|
||||||
|
/* A service name collision with a local service happened. Let's
|
||||||
|
* pick a new name */
|
||||||
|
n = avahi_alternative_service_name(name);
|
||||||
|
avahi_free(name);
|
||||||
|
name = n;
|
||||||
|
|
||||||
|
fprintf(stderr, "Service name collision, renaming service to '%s'\n", name);
|
||||||
|
|
||||||
|
avahi_entry_group_reset(group);
|
||||||
|
|
||||||
|
create_services(c);
|
||||||
|
return;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
avahi_simple_poll_quit(simple_poll);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PublishAvahi::client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) {
|
||||||
|
assert(c);
|
||||||
|
|
||||||
|
/* Called whenever the client or server state changes */
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case AVAHI_CLIENT_S_RUNNING:
|
||||||
|
|
||||||
|
/* The server has startup successfully and registered its host
|
||||||
|
* name on the network, so it's time to create our services */
|
||||||
|
create_services(c);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AVAHI_CLIENT_FAILURE:
|
||||||
|
|
||||||
|
fprintf(stderr, "Client failure: %s\n", avahi_strerror(avahi_client_errno(c)));
|
||||||
|
avahi_simple_poll_quit(simple_poll);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AVAHI_CLIENT_S_COLLISION:
|
||||||
|
|
||||||
|
/* Let's drop our registered services. When the server is back
|
||||||
|
* in AVAHI_SERVER_RUNNING state we will register them
|
||||||
|
* again with the new host name. */
|
||||||
|
|
||||||
|
case AVAHI_CLIENT_S_REGISTERING:
|
||||||
|
|
||||||
|
/* The server records are now being established. This
|
||||||
|
* might be caused by a host name change. We need to wait
|
||||||
|
* for our own records to register until the host name is
|
||||||
|
* properly esatblished. */
|
||||||
|
|
||||||
|
if (group)
|
||||||
|
avahi_entry_group_reset(group);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AVAHI_CLIENT_CONNECTING:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
|
||||||
|
PublishAvahi publishAvahi;
|
||||||
|
|
||||||
|
AvahiClient *client = NULL;
|
||||||
|
int error;
|
||||||
|
int ret = 1;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
/* Allocate main loop object */
|
||||||
|
if (!(simple_poll = avahi_simple_poll_new())) {
|
||||||
|
fprintf(stderr, "Failed to create simple poll object.\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = avahi_strdup("MegaPrinter");
|
||||||
|
|
||||||
|
/* Allocate a new client */
|
||||||
|
client = avahi_client_new(avahi_simple_poll_get(simple_poll), AVAHI_CLIENT_IGNORE_USER_CONFIG, client_callback, NULL, &error);
|
||||||
|
|
||||||
|
/* Check wether creating the client object succeeded */
|
||||||
|
if (!client) {
|
||||||
|
fprintf(stderr, "Failed to create client: %s\n", avahi_strerror(error));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* After 10s do some weird modification to the service */
|
||||||
|
/* avahi_simple_poll_get(simple_poll)->timeout_new(
|
||||||
|
avahi_simple_poll_get(simple_poll),
|
||||||
|
avahi_elapse_time(&tv, 1000*10, 0),
|
||||||
|
modify_callback,
|
||||||
|
client);
|
||||||
|
*/
|
||||||
|
/* Run the main loop */
|
||||||
|
while (avahi_simple_poll_iterate(simple_poll, 100) == 0)
|
||||||
|
printf("1");
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
|
||||||
|
/* Cleanup things */
|
||||||
|
|
||||||
|
if (client)
|
||||||
|
avahi_client_free(client);
|
||||||
|
|
||||||
|
if (simple_poll)
|
||||||
|
avahi_simple_poll_free(simple_poll);
|
||||||
|
|
||||||
|
avahi_free(name);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
33
server/publishAvahi.h
Normal file
33
server/publishAvahi.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef PUBLISH_AVAHI_H
|
||||||
|
#define PUBLISH_AVAHI_H
|
||||||
|
|
||||||
|
#include <avahi-client/client.h>
|
||||||
|
#include <avahi-client/publish.h>
|
||||||
|
|
||||||
|
#include <avahi-common/alternative.h>
|
||||||
|
#include <avahi-common/simple-watch.h>
|
||||||
|
#include <avahi-common/malloc.h>
|
||||||
|
#include <avahi-common/error.h>
|
||||||
|
#include <avahi-common/timeval.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class PublishAvahi
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PublishAvahi();
|
||||||
|
~PublishAvahi();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void *userdata);
|
||||||
|
void create_services(AvahiClient *c);
|
||||||
|
void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata);
|
||||||
|
|
||||||
|
AvahiEntryGroup *group;
|
||||||
|
AvahiSimplePoll *simple_poll;
|
||||||
|
char* name;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -118,10 +118,10 @@ int main(int argc, char* argv[])
|
||||||
int fd = open(fifoName.c_str(), O_RDONLY | O_NONBLOCK);
|
int fd = open(fifoName.c_str(), O_RDONLY | O_NONBLOCK);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
shared_ptr<msg::PcmChunk> chunk;//(new WireChunk());
|
shared_ptr<msg::PcmChunk> chunk;
|
||||||
while (!g_terminated)//cin.good())
|
while (!g_terminated)//cin.good())
|
||||||
{
|
{
|
||||||
chunk.reset(new msg::PcmChunk(sampleFormat, duration));//2*WIRE_CHUNK_SIZE));
|
chunk.reset(new msg::PcmChunk(sampleFormat, duration));
|
||||||
int toRead = chunk->payloadSize;
|
int toRead = chunk->payloadSize;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
do
|
do
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue