- 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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user