#include <MediaDefs.h>
#include <MediaNode.h>
#include <MediaAddOn.h>
#include <BufferConsumer.h>
#include <FileInterface.h>
#include <Controllable.h>
#include <MediaEventLooper.h>
#include <File.h>
#include <Errors.h>
#include <Entry.h>
#include <BufferGroup.h>
#include <TimeSource.h>
#include <Buffer.h>
#include <ParameterWeb.h>
#include <MediaRoster.h>
#include <limits.h>
#include <MediaDefs.h>
#include <Message.h>
#include "ESDSinkNode.h"
#include "ESDEndpoint.h"
#ifdef DEBUG
#define PRINTING
#endif
#include "debug.h"
#include <Debug.h>
#include <stdio.h>
#include <string.h>
ESDSinkNode::~ESDSinkNode(void)
{
CALLED();
fAddOn->GetConfigurationFor(this, NULL);
BMediaEventLooper::Quit();
fWeb = NULL;
delete fDevice;
}
ESDSinkNode::ESDSinkNode(BMediaAddOn *addon, char* name, BMessage * config)
: BMediaNode(name),
BBufferConsumer(B_MEDIA_RAW_AUDIO),
#if ENABLE_INPUT
BBufferProducer(B_MEDIA_RAW_AUDIO),
#endif
#ifdef ENABLE_TS
BTimeSource(),
#endif
BMediaEventLooper(),
fThread(-1),
fDevice(NULL),
fTimeSourceStarted(false),
fWeb(NULL),
fConfig(*config)
{
CALLED();
fInitCheckStatus = B_NO_INIT;
fAddOn = addon;
fId = 0;
AddNodeKind( B_PHYSICAL_OUTPUT );
#if ENABLE_INPUT
AddNodeKind( B_PHYSICAL_INPUT );
#endif
memset(&fPreferredFormat, 0, sizeof(fPreferredFormat));
fPreferredFormat.type = B_MEDIA_RAW_AUDIO;
#if ESD_FMT == 8
fPreferredFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_UCHAR;
#else
fPreferredFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT;
#endif
fPreferredFormat.u.raw_audio.valid_bits = 0;
fPreferredFormat.u.raw_audio.channel_count = 2;
fPreferredFormat.u.raw_audio.frame_rate = ESD_DEFAULT_RATE;
fPreferredFormat.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN;
fPreferredFormat.u.raw_audio.buffer_size = ESD_MAX_BUF / 4
;
if(config) {
config->FindString("hostname", &fHostname);
}
if (fHostname.Length() < 1)
fHostname = "172.20.109.151";
fPort = ESD_DEFAULT_PORT;
fEnabled = false;
fDevice = new ESDEndpoint();
if (!fDevice)
return;
fInitCheckStatus = B_OK;
}
status_t ESDSinkNode::InitCheck(void) const
{
CALLED();
return fInitCheckStatus;
}
BMediaAddOn * ESDSinkNode::AddOn(
int32 * internal_id) const
{
CALLED();
if (fAddOn != 0) {
if (internal_id != 0) {
*internal_id = fId;
}
}
return fAddOn;
}
void ESDSinkNode::Preroll(void)
{
CALLED();
BMediaNode::Preroll();
}
status_t ESDSinkNode::HandleMessage(
int32 message,
const void * data,
size_t size)
{
CALLED();
return B_ERROR;
}
void ESDSinkNode::NodeRegistered(void)
{
CALLED();
if (fInitCheckStatus != B_OK) {
ReportError(B_NODE_IN_DISTRESS);
return;
}
fInput.format = fPreferredFormat;
fInput.destination.port = ControlPort();
fInput.destination.id = 0;
fInput.node = Node();
sprintf(fInput.name, "output %ld", fInput.destination.id);
fOutput.format = fPreferredFormat;
fOutput.destination = media_destination::null;
fOutput.source.port = ControlPort();
fOutput.source.id = 0;
fOutput.node = Node();
sprintf(fOutput.name, "input %ld", fOutput.source.id);
fWeb = MakeParameterWeb();
SetParameterWeb(fWeb);
#ifdef PRINTING
bigtime_t start = system_time();
#endif
int32 index = 0;
int32 parameterID = 0;
const void *data;
ssize_t size;
while(fConfig.FindInt32("parameterID", index, ¶meterID) == B_OK) {
if(fConfig.FindData("parameterData", B_RAW_TYPE, index, &data, &size) == B_OK)
SetParameterValue(parameterID, TimeSource()->Now(), data, size);
index++;
}
#ifdef PRINTING
PRINT(("apply configuration in : %lld\n", system_time() - start));
#endif
SetPriority(B_REAL_TIME_PRIORITY);
Run();
}
status_t ESDSinkNode::RequestCompleted(const media_request_info &info)
{
CALLED();
return B_OK;
}
void ESDSinkNode::SetTimeSource(BTimeSource *timeSource)
{
CALLED();
}
status_t ESDSinkNode::AcceptFormat(
const media_destination & dest,
media_format * format)
{
status_t err;
CALLED();
if(fInput.destination != dest) {
fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION");
return B_MEDIA_BAD_DESTINATION;
}
if ( format->type != B_MEDIA_RAW_AUDIO ) {
fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n");
return B_MEDIA_BAD_FORMAT;
}
format->u.raw_audio.format = fPreferredFormat.u.raw_audio.format;
format->u.raw_audio.valid_bits = fPreferredFormat.u.raw_audio.valid_bits;
format->u.raw_audio.frame_rate = fPreferredFormat.u.raw_audio.frame_rate;
format->u.raw_audio.channel_count = fPreferredFormat.u.raw_audio.channel_count;
format->u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN;
format->u.raw_audio.buffer_size = ESD_MAX_BUF / 4
;
err = fDevice->Connect(fHostname.String(), fPort);
return B_OK;
}
status_t ESDSinkNode::GetNextInput(
int32 * cookie,
media_input * out_input)
{
CALLED();
if ((*cookie < 1) && (*cookie >= 0)) {
*out_input = fInput;
*cookie += 1;
PRINT(("input.format : %lu\n", fInput.format.u.raw_audio.format));
return B_OK;
} else
return B_BAD_INDEX;
}
void ESDSinkNode::DisposeInputCookie(
int32 cookie)
{
CALLED();
}
void ESDSinkNode::BufferReceived(
BBuffer * buffer)
{
CALLED();
switch (buffer->Header()->type) {
case B_MEDIA_RAW_AUDIO:
#if 0
if (buffer->Flags() & BBuffer::B_SMALL_BUFFER) {
fprintf(stderr,"NOT IMPLEMENTED: B_SMALL_BUFFER in ESDSinkNode::BufferReceived\n");
buffer->Recycle();
} else {
media_timed_event event(buffer->Header()->start_time, BTimedEventQueue::B_HANDLE_BUFFER,
buffer, BTimedEventQueue::B_RECYCLE_BUFFER);
status_t status = EventQueue()->AddEvent(event);
if (status != B_OK) {
fprintf(stderr,"EventQueue()->AddEvent(event) in ESDSinkNode::BufferReceived failed\n");
buffer->Recycle();
}
}
#endif
if (fDevice->CanSend()) {
fDevice->Write(buffer->Data(), buffer->SizeUsed());
}
buffer->Recycle();
break;
default:
fprintf(stderr,"unexpected buffer type in ESDSinkNode::BufferReceived\n");
buffer->Recycle();
break;
}
}
void ESDSinkNode::ProducerDataStatus(
const media_destination & for_whom,
int32 status,
bigtime_t at_performance_time)
{
CALLED();
if(fInput.destination != for_whom) {
fprintf(stderr,"invalid destination received in ESDSinkNode::ProducerDataStatus\n");
return;
}
media_timed_event event(at_performance_time, BTimedEventQueue::B_DATA_STATUS,
&fInput, BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL);
EventQueue()->AddEvent(event);
}
status_t ESDSinkNode::GetLatencyFor(
const media_destination & for_whom,
bigtime_t * out_latency,
media_node_id * out_timesource)
{
CALLED();
if ((out_latency == 0) || (out_timesource == 0)) {
fprintf(stderr,"<- B_BAD_VALUE\n");
return B_BAD_VALUE;
}
if(fInput.destination != for_whom) {
fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
return B_MEDIA_BAD_DESTINATION;
}
bigtime_t intl = EventLatency();
bigtime_t netl = 0LL;
if (fDevice)
netl = fDevice->Latency();
if (netl > 500000)
netl = 500000;
*out_latency = intl + netl;
fprintf(stderr, "int latency %lld, net latency %lld, total latency %lld\n", intl, netl, *out_latency);
*out_timesource = TimeSource()->ID();
return B_OK;
}
status_t ESDSinkNode::Connected(
const media_source & producer,
const media_destination & where,
const media_format & with_format,
media_input * out_input)
{
status_t err;
CALLED();
if(fInput.destination != where) {
fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
return B_MEDIA_BAD_DESTINATION;
}
if (fDevice) {
err = fDevice->WaitForConnect();
if (err < B_OK)
return err;
fDevice->SetCommand();
fDevice->SetFormat(ESD_FMT, 2);
err = fDevice->SendDefaultCommand();
if (err < B_OK)
return err;
}
fInternalLatency = with_format.u.raw_audio.buffer_size * 10000 / 2
/ ( (with_format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK)
* with_format.u.raw_audio.channel_count)
/ ((int32)(with_format.u.raw_audio.frame_rate / 100));
PRINT((" internal latency = %lld\n",fInternalLatency));
SetEventLatency(fInternalLatency);
fInput.source = producer;
fInput.format = with_format;
*out_input = fInput;
return B_OK;
}
void ESDSinkNode::Disconnected(
const media_source & producer,
const media_destination & where)
{
CALLED();
if(fInput.destination != where) {
fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
return;
}
if (fInput.source != producer) {
fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
return;
}
fInput.source = media_source::null;
fInput.format = fPreferredFormat;
if (fDevice)
fDevice->Disconnect();
}
status_t ESDSinkNode::FormatChanged(
const media_source & producer,
const media_destination & consumer,
int32 change_tag,
const media_format & format)
{
CALLED();
if(fInput.destination != consumer) {
fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
return B_MEDIA_BAD_DESTINATION;
}
if (fInput.source != producer) {
return B_MEDIA_BAD_SOURCE;
}
return B_ERROR;
}
status_t ESDSinkNode::SeekTagRequested(
const media_destination & destination,
bigtime_t in_target_time,
uint32 in_flags,
media_seek_tag * out_seek_tag,
bigtime_t * out_tagged_time,
uint32 * out_flags)
{
CALLED();
return BBufferConsumer::SeekTagRequested(destination,in_target_time,in_flags,
out_seek_tag,out_tagged_time,out_flags);
}
#if 0
status_t
ESDSinkNode::FormatSuggestionRequested(media_type type, int32 , media_format* format)
{
CALLED();
if (!format)
{
fprintf(stderr, "\tERROR - NULL format pointer passed in!\n");
return B_BAD_VALUE;
}
*format = fPreferredFormat;
if (type == B_MEDIA_UNKNOWN_TYPE) type = B_MEDIA_RAW_AUDIO;
if (type != B_MEDIA_RAW_AUDIO) return B_MEDIA_BAD_FORMAT;
else return B_OK;
}
status_t
ESDSinkNode::FormatProposal(const media_source& output, media_format* format)
{
CALLED();
node_output *channel = FindOutput(output);
if (channel == NULL)
{
fprintf(stderr, "ESDSinkNode::FormatProposal returning B_MEDIA_BAD_SOURCE\n");
return B_MEDIA_BAD_SOURCE;
}
media_type requestedType = format->type;
*format = channel->fPreferredFormat;
if ((requestedType != B_MEDIA_UNKNOWN_TYPE) && (requestedType != B_MEDIA_RAW_AUDIO))
{
fprintf(stderr, "ESDSinkNode::FormatProposal returning B_MEDIA_BAD_FORMAT\n");
return B_MEDIA_BAD_FORMAT;
}
else return B_OK;
}
status_t
ESDSinkNode::FormatChangeRequested(const media_source& source, const media_destination& destination, media_format* io_format, int32* _deprecated_)
{
CALLED();
return B_ERROR;
}
status_t
ESDSinkNode::GetNextOutput(int32* cookie, media_output* out_output)
{
CALLED();
if ((*cookie < fOutputs.CountItems()) && (*cookie >= 0)) {
node_output *channel = (node_output *)fOutputs.ItemAt(*cookie);
*out_output = channel->fOutput;
*cookie += 1;
return B_OK;
} else
return B_BAD_INDEX;
}
status_t
ESDSinkNode::DisposeOutputCookie(int32 cookie)
{
CALLED();
return B_OK;
}
status_t
ESDSinkNode::SetBufferGroup(const media_source& for_source, BBufferGroup* newGroup)
{
CALLED();
node_output *channel = FindOutput(for_source);
if (channel == NULL)
{
fprintf(stderr, "ESDSinkNode::SetBufferGroup returning B_MEDIA_BAD_SOURCE\n");
return B_MEDIA_BAD_SOURCE;
}
if (newGroup == channel->fBufferGroup) return B_OK;
delete channel->fBufferGroup;
if (newGroup != NULL)
{
channel->fBufferGroup = newGroup;
}
else
{
size_t size = channel->fOutput.format.u.raw_audio.buffer_size;
int32 count = int32(fLatency / BufferDuration() + 1 + 1);
channel->fBufferGroup = new BBufferGroup(size, count);
}
return B_OK;
}
status_t
ESDSinkNode::PrepareToConnect(const media_source& what, const media_destination& where, media_format* format, media_source* out_source, char* out_name)
{
CALLED();
node_output *channel = FindOutput(what);
if (channel == NULL)
{
fprintf(stderr, "ESDSinkNode::PrepareToConnect returning B_MEDIA_BAD_SOURCE\n");
return B_MEDIA_BAD_SOURCE;
}
if (channel->fOutput.destination != media_destination::null)
return B_MEDIA_ALREADY_CONNECTED;
if (format->type != B_MEDIA_RAW_AUDIO)
{
fprintf(stderr, "\tnon-raw-audio format?!\n");
return B_MEDIA_BAD_FORMAT;
}
if (format->u.raw_audio.buffer_size == media_raw_audio_format::wildcard.buffer_size)
{
format->u.raw_audio.buffer_size = 2048;
fprintf(stderr, "\tno buffer size provided, suggesting %lu\n", format->u.raw_audio.buffer_size);
}
else
{
fprintf(stderr, "\tconsumer suggested buffer_size %lu\n", format->u.raw_audio.buffer_size);
}
channel->fOutput.destination = where;
channel->fOutput.format = *format;
*out_source = channel->fOutput.source;
strncpy(out_name, channel->fOutput.name, B_MEDIA_NAME_LENGTH);
return B_OK;
}
void
ESDSinkNode::Connect(status_t error, const media_source& source, const media_destination& destination, const media_format& format, char* io_name)
{
CALLED();
node_output *channel = FindOutput(source);
if (channel == NULL)
{
fprintf(stderr, "ESDSinkNode::Connect returning (cause : B_MEDIA_BAD_SOURCE)\n");
return;
}
if (error)
{
channel->fOutput.destination = media_destination::null;
channel->fOutput.format = channel->fPreferredFormat;
return;
}
channel->fOutput.destination = destination;
channel->fOutput.format = format;
strncpy(io_name, channel->fOutput.name, B_MEDIA_NAME_LENGTH);
bigtime_t duration = channel->fOutput.format.u.raw_audio.buffer_size * 10000
/ ( (channel->fOutput.format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK)
* channel->fOutput.format.u.raw_audio.channel_count)
/ ((int32)(channel->fOutput.format.u.raw_audio.frame_rate / 100));
SetBufferDuration(duration);
media_node_id id;
FindLatencyFor(channel->fOutput.destination, &fLatency, &id);
PRINT(("\tdownstream latency = %lld\n", fLatency));
fInternalLatency = BufferDuration();
PRINT(("\tbuffer-filling took %lld usec on this machine\n", fInternalLatency));
if (!channel->fBufferGroup)
AllocateBuffers(*channel);
StartThread();
}
void
ESDSinkNode::Disconnect(const media_source& what, const media_destination& where)
{
CALLED();
node_output *channel = FindOutput(what);
if (channel == NULL)
{
fprintf(stderr, "ESDSinkNode::Disconnect() returning (cause : B_MEDIA_BAD_SOURCE)\n");
return;
}
if ((where == channel->fOutput.destination) && (what == channel->fOutput.source))
{
channel->fOutput.destination = media_destination::null;
channel->fOutput.format = channel->fPreferredFormat;
delete channel->fBufferGroup;
channel->fBufferGroup = NULL;
}
else
{
fprintf(stderr, "\tDisconnect() called with wrong source/destination (%ld/%ld), ours is (%ld/%ld)\n",
what.id, where.id, channel->fOutput.source.id, channel->fOutput.destination.id);
}
}
void
ESDSinkNode::LateNoticeReceived(const media_source& what, bigtime_t how_much, bigtime_t performance_time)
{
CALLED();
node_output *channel = FindOutput(what);
if (channel == NULL)
{
return;
}
if (RunMode() == B_RECORDING)
{
}
else if (RunMode() == B_INCREASE_LATENCY)
{
fInternalLatency += how_much;
SetEventLatency(fLatency + fInternalLatency);
fprintf(stderr, "\tincreasing latency to %lld\n", fLatency + fInternalLatency);
}
else
{
fprintf(stderr, "\tskipping a buffer to try to catch up\n");
}
}
void
ESDSinkNode::EnableOutput(const media_source& what, bool enabled, int32* _deprecated_)
{
CALLED();
node_output *channel = FindOutput(what);
if (channel != NULL)
{
channel->fOutputEnabled = enabled;
}
}
void
ESDSinkNode::AdditionalBufferRequested(const media_source& source, media_buffer_id prev_buffer, bigtime_t prev_time, const media_seek_tag* prev_tag)
{
CALLED();
return;
}
#endif
void ESDSinkNode::HandleEvent(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent)
{
CALLED();
switch (event->type) {
case BTimedEventQueue::B_START:
HandleStart(event,lateness,realTimeEvent);
break;
case BTimedEventQueue::B_SEEK:
HandleSeek(event,lateness,realTimeEvent);
break;
case BTimedEventQueue::B_WARP:
HandleWarp(event,lateness,realTimeEvent);
break;
case BTimedEventQueue::B_STOP:
HandleStop(event,lateness,realTimeEvent);
break;
case BTimedEventQueue::B_HANDLE_BUFFER:
if (RunState() == BMediaEventLooper::B_STARTED) {
HandleBuffer(event,lateness,realTimeEvent);
}
break;
case BTimedEventQueue::B_DATA_STATUS:
HandleDataStatus(event,lateness,realTimeEvent);
break;
case BTimedEventQueue::B_PARAMETER:
HandleParameter(event,lateness,realTimeEvent);
break;
default:
fprintf(stderr," unknown event type: %li\n",event->type);
break;
}
}
status_t ESDSinkNode::HandleBuffer(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent)
{
CALLED();
BBuffer * buffer = const_cast<BBuffer*>((BBuffer*)event->pointer);
if (buffer == 0) {
fprintf(stderr,"<- B_BAD_VALUE\n");
return B_BAD_VALUE;
}
if(fInput.destination.id != buffer->Header()->destination) {
fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
return B_MEDIA_BAD_DESTINATION;
}
media_header* hdr = buffer->Header();
bigtime_t now = TimeSource()->Now();
bigtime_t perf_time = hdr->start_time;
bigtime_t how_early = perf_time - EventLatency() - now;
if ((RunMode() != B_OFFLINE) &&
(RunMode() != B_RECORDING) &&
(how_early < 0LL))
{
NotifyLateProducer(fInput.source, -how_early, perf_time);
fprintf(stderr," <- LATE BUFFER : %lli\n", how_early);
buffer->Recycle();
} else {
if (fDevice->CanSend())
fDevice->Write(buffer->Data(), buffer->SizeUsed());
}
return B_OK;
}
status_t ESDSinkNode::HandleDataStatus(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent)
{
CALLED();
PRINT(("ESDSinkNode::HandleDataStatus status:%li, lateness:%lli\n", event->data, lateness));
switch(event->data) {
case B_DATA_NOT_AVAILABLE:
break;
case B_DATA_AVAILABLE:
break;
case B_PRODUCER_STOPPED:
break;
default:
break;
}
return B_OK;
}
status_t ESDSinkNode::HandleStart(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent)
{
CALLED();
if (RunState() != B_STARTED) {
}
return B_OK;
}
status_t ESDSinkNode::HandleSeek(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent)
{
CALLED();
PRINT(("ESDSinkNode::HandleSeek(t=%lld,d=%li,bd=%lld)\n",event->event_time,event->data,event->bigdata));
return B_OK;
}
status_t ESDSinkNode::HandleWarp(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent)
{
CALLED();
return B_OK;
}
status_t ESDSinkNode::HandleStop(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent)
{
CALLED();
EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER);
return B_OK;
}
status_t ESDSinkNode::HandleParameter(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent)
{
CALLED();
return B_OK;
}
#ifdef ENABLE_TS
void
ESDSinkNode::SetRunMode(run_mode mode)
{
CALLED();
PRINT(("ESDSinkNode::SetRunMode mode:%i\n", mode));
}
status_t
ESDSinkNode::TimeSourceOp(const time_source_op_info &op, void *_reserved)
{
CALLED();
switch(op.op) {
case B_TIMESOURCE_START:
PRINT(("TimeSourceOp op B_TIMESOURCE_START\n"));
if (RunState() != BMediaEventLooper::B_STARTED) {
fTimeSourceStarted = true;
media_timed_event startEvent(0, BTimedEventQueue::B_START);
EventQueue()->AddEvent(startEvent);
}
break;
case B_TIMESOURCE_STOP:
PRINT(("TimeSourceOp op B_TIMESOURCE_STOP\n"));
if (RunState() == BMediaEventLooper::B_STARTED) {
media_timed_event stopEvent(0, BTimedEventQueue::B_STOP);
EventQueue()->AddEvent(stopEvent);
fTimeSourceStarted = false;
PublishTime(0, 0, 1.0f);
}
break;
case B_TIMESOURCE_STOP_IMMEDIATELY:
PRINT(("TimeSourceOp op B_TIMESOURCE_STOP_IMMEDIATELY\n"));
if (RunState() == BMediaEventLooper::B_STARTED) {
media_timed_event stopEvent(0, BTimedEventQueue::B_STOP);
EventQueue()->AddEvent(stopEvent);
fTimeSourceStarted = false;
PublishTime(0, 0, 1.0f);
}
break;
case B_TIMESOURCE_SEEK:
PRINT(("TimeSourceOp op B_TIMESOURCE_SEEK\n"));
BroadcastTimeWarp(op.real_time, op.performance_time);
break;
default:
break;
}
return B_OK;
}
#endif
status_t
ESDSinkNode::GetParameterValue(int32 id, bigtime_t* last_change, void* value, size_t* ioSize)
{
CALLED();
if (!fDevice)
return B_ERROR;
switch (id) {
case PARAM_ENABLED:
if (*ioSize < sizeof(bool))
return B_NO_MEMORY;
*(bool *)value = fEnabled;
*ioSize = sizeof(bool);
return B_OK;
case PARAM_HOST:
{
BString s = fDevice->Host();
*ioSize = MIN(*ioSize, s.Length());
memcpy(value, s.String(), *ioSize);
return B_OK;
}
case PARAM_PORT:
{
BString s;
s << fDevice->Port();
*ioSize = MIN(*ioSize, s.Length());
memcpy(value, s.String(), *ioSize);
return B_OK;
}
default:
break;
}
#if 0
BParameter *parameter = NULL;
for(int32 i=0; i<fWeb->CountParameters(); i++) {
parameter = fWeb->ParameterAt(i);
if(parameter->ID() == id)
break;
}
#endif
return EINVAL;
}
void
ESDSinkNode::SetParameterValue(int32 id, bigtime_t performance_time, const void* value, size_t size)
{
CALLED();
PRINT(("id : %li, performance_time : %lld, size : %li\n", id, performance_time, size));
BParameter *parameter = NULL;
for(int32 i=0; i<fWeb->CountParameters(); i++) {
parameter = fWeb->ParameterAt(i);
if(parameter->ID() == id)
break;
}
switch (id) {
case PARAM_ENABLED:
if (size != sizeof(bool))
return;
fEnabled = *(bool *)value;
return;
case PARAM_HOST:
{
fprintf(stderr, "set HOST: %s\n", (const char *)value);
fHostname = (const char *)value;
#if 0
if (fDevice && fDevice->Connected()) {
if (fDevice->Connect(fHostname.String(), fPort) >= 0) {
fDevice->SetCommand();
fDevice->SetFormat(ESD_FMT, 2);
fInitCheckStatus = fDevice->SendDefaultCommand();
}
}
#endif
return;
}
case PARAM_PORT:
{
fprintf(stderr, "set PORT: %s\n", (const char *)value);
fPort = atoi((const char *)value);
#if 0
if (fDevice && fDevice->Connected()) {
if (fDevice->Connect(fHostname.String(), fPort) >= 0) {
fDevice->SetCommand();
fDevice->SetFormat(ESD_FMT, 2);
fInitCheckStatus = fDevice->SendDefaultCommand();
}
}
#endif
return;
}
default:
break;
}
}
BParameterWeb*
ESDSinkNode::MakeParameterWeb()
{
CALLED();
BParameterWeb* web = new BParameterWeb;
BParameterGroup *group = web->MakeGroup("Server");
BParameter *p;
p = group->MakeDiscreteParameter(PARAM_ENABLED, B_MEDIA_RAW_AUDIO, "Enable", B_ENABLE);
#if defined(B_BEOS_VERSION_DANO) || defined(__HAIKU__)
p = group->MakeTextParameter(PARAM_HOST, B_MEDIA_RAW_AUDIO, "Hostname", B_GENERIC, 128);
p = group->MakeTextParameter(PARAM_PORT, B_MEDIA_RAW_AUDIO, "Port", B_GENERIC, 16);
#endif
return web;
}
status_t
ESDSinkNode::GetConfigurationFor(BMessage * into_message)
{
CALLED();
BParameter *parameter = NULL;
void *buffer;
size_t size = 128;
bigtime_t last_change;
status_t err;
if (!into_message)
return B_BAD_VALUE;
buffer = malloc(size);
for(int32 i=0; i<fWeb->CountParameters(); i++) {
parameter = fWeb->ParameterAt(i);
if(parameter->Type() != BParameter::B_CONTINUOUS_PARAMETER
&& parameter->Type() != BParameter::B_DISCRETE_PARAMETER)
continue;
PRINT(("getting parameter %li\n", parameter->ID()));
size = 128;
while((err = GetParameterValue(parameter->ID(), &last_change, buffer, &size))==B_NO_MEMORY) {
size += 128;
free(buffer);
buffer = malloc(size);
}
if(err == B_OK && size > 0) {
into_message->AddInt32("parameterID", parameter->ID());
into_message->AddData("parameterData", B_RAW_TYPE, buffer, size, false);
} else {
PRINT(("parameter %li err : %s\n", parameter->ID(), strerror(err)));
}
}
return B_OK;
}
void ESDSinkNode::GetFlavor(flavor_info * outInfo, int32 id)
{
CALLED();
outInfo->flavor_flags = B_FLAVOR_IS_GLOBAL;
outInfo->possible_count = 1;
outInfo->in_format_count = 0;
outInfo->in_formats = 0;
outInfo->out_format_count = 0;
outInfo->out_formats = 0;
outInfo->internal_id = id;
outInfo->name = new char[256];
strcpy(outInfo->name, "ESounD Out");
outInfo->info = new char[256];
strcpy(outInfo->info, "The ESounD Sink node outputs a network Enlightenment Sound Daemon.");
outInfo->kinds = 0;
#if ENABLE_INPUT
outInfo->kinds |= B_BUFFER_PRODUCER | B_PHYSICAL_INPUT;
outInfo->out_format_count = 1;
media_format * outformats = new media_format[outInfo->out_format_count];
GetFormat(&outformats[0]);
outInfo->out_formats = outformats;
#endif
outInfo->kinds |= B_BUFFER_CONSUMER | B_PHYSICAL_OUTPUT;
outInfo->in_format_count = 1;
media_format * informats = new media_format[outInfo->in_format_count];
GetFormat(&informats[0]);
outInfo->in_formats = informats;
}
void ESDSinkNode::GetFormat(media_format * outFormat)
{
CALLED();
outFormat->type = B_MEDIA_RAW_AUDIO;
outFormat->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
outFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
outFormat->u.raw_audio = media_raw_audio_format::wildcard;
}