- renamed some constants to match esd.h

- ask server latency and use it (not always better...)
- set and get host/port parameter, setting doesn't reconnect correctly. not saved yet.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19199 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
François Revol
2006-11-04 14:51:53 +00:00
parent e9ba57e495
commit 7191645844
5 changed files with 155 additions and 49 deletions
@@ -49,15 +49,11 @@
ESDEndpoint::ESDEndpoint()
: BDataIO()
, fHost(NULL)
, fPort(ESD_PORT)
, fPort(ESD_DEFAULT_PORT)
, fSocket(-1)
, fDefaultCommand(ESD_CMD_STREAM_PLAY)
, fDefaultCommandSent(false)
, fDefaultFormat(ESD_BITS8 | ESD_MONO)
, fDefaultRate(ESD_DEFAULT_RATE)
, fLatency(0LL)
{
CALLED();
Reset();
}
ESDEndpoint::~ESDEndpoint()
@@ -68,6 +64,15 @@ ESDEndpoint::~ESDEndpoint()
fSocket = -1;
}
void ESDEndpoint::Reset()
{
fDefaultCommand = ESD_PROTO_STREAM_PLAY;
fDefaultCommandSent = false;
fDefaultFormat = ESD_BITS8 | ESD_MONO;
fDefaultRate = ESD_DEFAULT_RATE;
fLatency = 0LL;
}
status_t ESDEndpoint::SendAuthKey()
{
CALLED();
@@ -104,6 +109,7 @@ status_t ESDEndpoint::SendAuthKey()
status_t ESDEndpoint::Connect(const char *host, uint16 port)
{
status_t err;
int flag;
CALLED();
fHost = host;
fPort = port;
@@ -116,46 +122,104 @@ status_t ESDEndpoint::Connect(const char *host, uint16 port)
return ENOENT;
memcpy((struct in_addr *)&sin.sin_addr, he->h_addr, sizeof(struct in_addr));
/* close old connection */
if (fSocket > -1)
closesocket(fSocket);
Reset();
fSocket = socket(AF_INET, SOCK_STREAM, 0);
if (fSocket < 0)
return errno;
sin.sin_family = AF_INET;
sin.sin_port = htons( port );
/*
flag = 128*1024;
setsockopt(fSocket, SOL_SOCKET, SO_SNDBUF, &flag, sizeof(flag));
setsockopt(fSocket, SOL_SOCKET, SO_RCVBUF, &flag, sizeof(flag));
*/
err = connect(fSocket, (struct sockaddr *) &sin, sizeof(sin));
PRINT(("connect: %s\n", strerror(err)));
if (err < 0)
return errno;
/* uint32 cmd = ESD_CMD_CONNECT;
uint32 cmd;
uint32 result;
/* uint32 cmd = ESD_PROTO_CONNECT;
err = write(fSocket, &cmd, sizeof(cmd));
if (err < 0)
return errno;
if (err < sizeof(cmd))
return EIO;
*/
/* send authentification key */
err = SendAuthKey();
if (err < 0)
return errno;
/* send endian tag, wait for 'ok' and measure the round-trip time
* to account for the network latency
*/
bigtime_t ping = system_time();
uint32 endian = ESD_ENDIAN_TAG;
err = write(fSocket, &endian, sizeof(endian));
cmd = ESD_ENDIAN_TAG;
err = write(fSocket, &cmd, sizeof(cmd));
if (err < 0)
return errno;
if (err < sizeof(endian))
if (err < sizeof(cmd))
return EIO;
uint32 ok;
read(fSocket, &ok, sizeof(uint32));
read(fSocket, &result, sizeof(result));
if (result != 1)
fprintf(stderr, "ESDEndpoint::Connect: didn't get ok from ESD_PROTO_INIT (%ld)!\n", result);
ping = system_time() - ping;
ping = (system_time() - ping) / 2; /* approximate one-way trip time */
fLatency = ping;
int flag = 1;
/* ask the server for its own latency
* sadly it seems to only give a fixed value,
* not counting the audio card's buffering into account.
* we take another measurement of the round-trip,
* and use the mean of the 2.
*/
ping = system_time();
cmd = ESD_PROTO_LATENCY;
err = write(fSocket, &cmd, sizeof(cmd));
if (err < 0)
return errno;
if (err < sizeof(cmd))
return EIO;
read(fSocket, &result, sizeof(result));
fprintf(stderr, "ESDEndpoint::Connect: ESD_PROTO_LATENCY: %ld\n", result);
ping = (system_time() - ping) / 2; /* approximate one-way trip time */
bigtime_t serverLatency = result * 1000000LL / (ESD_DEFAULT_RATE * 2/*16b*/ * 2/*stereo*/ );
bigtime_t netLatency = (fLatency + ping) / 2; /* mean of both */
fprintf(stderr, "ESDEndpoint::Connect: Latency: server: %Ld, net1: %Ld, net2: %Ld\n", serverLatency, fLatency, ping);
fLatency = netLatency + serverLatency;
flag = 1;
int len;
/* disable Nagle */
setsockopt(fSocket, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
//setsockopt(fSocket, SOL_SOCKET, SO_NONBLOCK, &flag, sizeof(flag));
/*
len = sizeof(flag);
getsockopt(fSocket, SOL_SOCKET, SO_SNDBUF, &flag, &len);
fprintf(stderr, "ESDEndpoint::Connect: SNDBUF: %ld\n", flag);
flag = MIN(TCP_MAXWIN, MAX(flag, (4 * netLatency * (ESD_DEFAULT_RATE*2*2) / 1000000LL)));
fprintf(stderr, "ESDEndpoint::Connect: SNDBUF: %ld\n", flag);
setsockopt(fSocket, SOL_SOCKET, SO_SNDBUF, &flag, sizeof(flag));
*/
// read(fSocket, &ok, sizeof(uint32));
// connect
// auth
@@ -227,7 +291,7 @@ status_t ESDEndpoint::GetServerInfo()
uint32 fmt;
} si;
status_t err;
err = SendCommand(ESD_CMD_SERVER_INFO, (const uint8 *)&si, 0, (uint8 *)&si, sizeof(si));
err = SendCommand(ESD_PROTO_SERVER_INFO, (const uint8 *)&si, 0, (uint8 *)&si, sizeof(si));
if (err < 0)
return err;
PRINT(("err %d, version: %lu, rate: %lu, fmt: %lu\n", err, si.ver, si.rate, si.fmt));
@@ -44,12 +44,13 @@ public:
~ESDEndpoint();
/* */
void Reset();
status_t SendAuthKey();
status_t Connect(const char *host, uint16 port=ESD_PORT);
status_t Connect(const char *host, uint16 port=ESD_DEFAULT_PORT);
status_t Disconnect();
/* set the default command and format for BDataIO interface */
status_t SetCommand(esd_command_t cmd=ESD_CMD_STREAM_PLAY);
status_t SetCommand(esd_command_t cmd=ESD_PROTO_STREAM_PLAY);
status_t SetFormat(int bits, int channels, float rate=ESD_DEFAULT_RATE);
status_t GetServerInfo();
@@ -57,6 +58,8 @@ status_t GetServerInfo();
/* */
bigtime_t GetLatency() const { return fLatency; };
const char *Host() const { return fHost.String(); };
uint16 Port() const { return fPort; };
bool CanSend();
@@ -1087,14 +1087,31 @@ status_t
ESDSinkNode::GetParameterValue(int32 id, bigtime_t* last_change, void* value, size_t* ioSize)
{
CALLED();
PRINT(("id : %i\n", id));
if (!fDevice)
return B_ERROR;
//PRINT(("id : %i\n", id));
if (id == fWebHostId) {
BString s = fDevice->Host();
*ioSize = MIN(*ioSize, s.Length());
memcpy(value, s.String(), *ioSize);
return B_OK;
}
if (id == fWebPortId) {
BString s;
s << fDevice->Port();
*ioSize = MIN(*ioSize, s.Length());
memcpy(value, s.String(), *ioSize);
return B_OK;
}
#if 0
BParameter *parameter = NULL;
for(int32 i=0; i<fWeb->CountParameters(); i++) {
parameter = fWeb->ParameterAt(i);
if(parameter->ID() == id)
break;
}
#endif
#if 0
if(!parameter) {
// Hmmm, we were asked for a parameter that we don't actually
@@ -1181,6 +1198,20 @@ ESDSinkNode::SetParameterValue(int32 id, bigtime_t performance_time, const void*
if(parameter->ID() == id)
break;
}
if (id == fWebHostId) {
fprintf(stderr, "set HOST: %s\n", (const char *)value);
BString host = (const char *)value;
uint16 port = fDevice->Port();
fDevice->Connect(host.String(), port);
return;
}
if (id == fWebPortId) {
fprintf(stderr, "set PORT: %s\n", (const char *)value);
BString host = fDevice->Host();
uint16 port = atoi((const char *)value);
fDevice->Connect(host.String(), port);
return;
}
#if 0
if(parameter) {
multi_mix_value_info MMVI;
@@ -1259,8 +1290,13 @@ ESDSinkNode::MakeParameterWeb()
int id = 0;
BParameterGroup *group = web->MakeGroup("Server");
BParameter *p;
p = group->MakeTextParameter(id++, B_MEDIA_RAW_AUDIO, "Hostname", B_GENERIC, 128);
p = group->MakeTextParameter(id++, B_MEDIA_RAW_AUDIO, "Port", B_GENERIC, 16);
fWebHostId = fWebPortId = -1;
#ifdef B_BEOS_VERSION_DANO /* not yet in Haiku */
fWebHostId = id++;
p = group->MakeTextParameter(fWebHostId, B_MEDIA_RAW_AUDIO, "Hostname", B_GENERIC, 128);
fWebPortId = id++;
p = group->MakeTextParameter(fWebPortId, B_MEDIA_RAW_AUDIO, "Port", B_GENERIC, 16);
#endif
return web;
}
#if 0
@@ -357,6 +357,8 @@ private:
bool fTimeSourceStarted;
BParameterWeb *fWeb;
int32 fWebHostId;
int32 fWebPortId;
BMessage fConfig;
};
@@ -49,8 +49,8 @@ typedef char esd_key_t[ESD_MAX_KEY];
typedef char esd_name_t[ESD_MAX_NAME];
/* defaults */
//#define ESD_PORT 5001
#define ESD_PORT 16001
//#define ESD_DEFAULT_PORT 5001
#define ESD_DEFAULT_PORT 16001
#define ESD_DEFAULT_RATE 44100
//#define ESD_DEFAULT_RATE 22050
@@ -59,39 +59,40 @@ typedef char esd_name_t[ESD_MAX_NAME];
enum {
/* init */
ESD_CMD_CONNECT = 0,
ESD_PROTO_CONNECT = 0,
/* security */
ESD_CMD_LOCK,
ESD_CMD_UNLOCK,
ESD_PROTO_LOCK,
ESD_PROTO_UNLOCK,
ESD_CMD_STREAM_PLAY,
ESD_CMD_STREAM_REC,
ESD_CMD_STREAM_MON,
ESD_PROTO_STREAM_PLAY,
ESD_PROTO_STREAM_REC,
ESD_PROTO_STREAM_MON,
ESD_CMD_SAMPLE_CACHE,
ESD_CMD_SAMPLE_FREE,
ESD_CMD_SAMPLE_PLAY,
ESD_CMD_SAMPLE_LOOP,
ESD_CMD_SAMPLE_STOP,
ESD_CMD_SAMPLE_KILL,
ESD_PROTO_SAMPLE_CACHE,
ESD_PROTO_SAMPLE_FREE,
ESD_PROTO_SAMPLE_PLAY,
ESD_PROTO_SAMPLE_LOOP,
ESD_PROTO_SAMPLE_STOP,
ESD_PROTO_SAMPLE_KILL,
ESD_CMD_STANDBY,
ESD_CMD_RESUME,
ESD_PROTO_STANDBY,
ESD_PROTO_RESUME,
ESD_CMD_SAMPLE_GETID,
ESD_CMD_STREAM_FILTER,
ESD_PROTO_SAMPLE_GETID,
ESD_PROTO_STREAM_FILTER,
ESD_CMD_SERVER_INFO,
ESD_CMD_SERVER_ALL_INFO,
_ESD_CMD_SUBSCRIBE,
_ESD_CMD_UNSUBSCRIBE,
ESD_PROTO_SERVER_INFO,
ESD_PROTO_SERVER_ALL_INFO,
ESD_PROTO_SUBSCRIBE,
ESD_PROTO_UNSUBSCRIBE,
ESD_CMD_STREAM_PAN,
ESD_CMD_SAMPLE_PAN,
ESD_PROTO_STREAM_PAN,
ESD_PROTO_SAMPLE_PAN,
ESD_CMD_STANDBY_MODE,
ESD_CMD_LATENCY
ESD_PROTO_STANDBY_MODE,
ESD_PROTO_LATENCY,
ESD_PROTO_MAX
};
#define ESD_MASK_BITS 0x000F