git-svn-id: file:///srv/svn/repos/haiku/trunk/current@86 a95241bf-73f2-0310-859d-f6bbb57e9c96
572 lines
16 KiB
C++
572 lines
16 KiB
C++
/***********************************************************************
|
|
* AUTHOR: Marcus Overhagen
|
|
* FILE: BufferProducer.cpp
|
|
* DESCR:
|
|
***********************************************************************/
|
|
#include <BufferProducer.h>
|
|
#include <BufferGroup.h>
|
|
#include <Buffer.h>
|
|
#include "PortPool.h"
|
|
#include "debug.h"
|
|
#include "ServerInterface.h"
|
|
|
|
/*************************************************************
|
|
* protected BBufferProducer
|
|
*************************************************************/
|
|
|
|
BBufferProducer::~BBufferProducer()
|
|
{
|
|
CALLED();
|
|
}
|
|
|
|
/*************************************************************
|
|
* public BBufferProducer
|
|
*************************************************************/
|
|
|
|
/* static */ status_t
|
|
BBufferProducer::ClipDataToRegion(int32 format,
|
|
int32 size,
|
|
const void *data,
|
|
BRegion *region)
|
|
{
|
|
CALLED();
|
|
|
|
if (format != B_CLIP_SHORT_RUNS)
|
|
return B_MEDIA_BAD_CLIP_FORMAT;
|
|
|
|
return clip_shorts_to_region((const int16 *)data, size / sizeof(int16), region);
|
|
}
|
|
|
|
media_type
|
|
BBufferProducer::ProducerType()
|
|
{
|
|
CALLED();
|
|
return fProducerType;
|
|
}
|
|
|
|
/*************************************************************
|
|
* protected BBufferProducer
|
|
*************************************************************/
|
|
|
|
/* explicit */
|
|
BBufferProducer::BBufferProducer(media_type producer_type) :
|
|
BMediaNode("called by BBufferProducer"),
|
|
fProducerType(producer_type),
|
|
fInitialLatency(0),
|
|
fInitialFlags(0)
|
|
{
|
|
CALLED();
|
|
|
|
AddNodeKind(B_BUFFER_PRODUCER);
|
|
}
|
|
|
|
|
|
status_t
|
|
BBufferProducer::VideoClippingChanged(const media_source &for_source,
|
|
int16 num_shorts,
|
|
int16 *clip_data,
|
|
const media_video_display_info &display,
|
|
int32 *_deprecated_)
|
|
{
|
|
CALLED();
|
|
// may be implemented by derived classes
|
|
return B_ERROR;
|
|
}
|
|
|
|
|
|
status_t
|
|
BBufferProducer::GetLatency(bigtime_t *out_lantency)
|
|
{
|
|
UNIMPLEMENTED();
|
|
|
|
// XXX The default implementation of GetLatency() finds the maximum
|
|
// latency of your currently-available outputs by iterating over
|
|
// them, and returns that value in outLatency
|
|
|
|
return B_ERROR;
|
|
}
|
|
|
|
|
|
status_t
|
|
BBufferProducer::SetPlayRate(int32 numer,
|
|
int32 denom)
|
|
{
|
|
CALLED();
|
|
// may be implemented by derived classes
|
|
return B_ERROR;
|
|
}
|
|
|
|
|
|
status_t
|
|
BBufferProducer::HandleMessage(int32 message,
|
|
const void *rawdata,
|
|
size_t size)
|
|
{
|
|
CALLED();
|
|
switch (message) {
|
|
|
|
case PRODUCER_FORMAT_SUGGESTION_REQUESTED:
|
|
{
|
|
const xfer_producer_format_suggestion_requested *data = (const xfer_producer_format_suggestion_requested *)rawdata;
|
|
xfer_producer_format_suggestion_requested_reply reply;
|
|
reply.result = FormatSuggestionRequested(data->type, data->quality, &reply.format);
|
|
write_port(data->reply_port, 0, &reply, sizeof(reply));
|
|
return B_OK;
|
|
}
|
|
|
|
case PRODUCER_FORMAT_PROPOSAL:
|
|
{
|
|
const xfer_producer_format_proposal *data = (const xfer_producer_format_proposal *)rawdata;
|
|
xfer_producer_format_proposal_reply reply;
|
|
reply.result = FormatProposal(data->output, (media_format *)&data->format);
|
|
write_port(data->reply_port, 0, &reply, sizeof(reply));
|
|
return B_OK;
|
|
}
|
|
|
|
case PRODUCER_PREPARE_TO_CONNECT:
|
|
{
|
|
const xfer_producer_prepare_to_connect *data = (const xfer_producer_prepare_to_connect *)rawdata;
|
|
xfer_producer_prepare_to_connect_reply reply;
|
|
reply.format = data->format;
|
|
reply.name[0] = 0;
|
|
reply.result = PrepareToConnect(data->source, data->destination, &reply.format, &reply.out_source, reply.name);
|
|
write_port(data->reply_port, 0, &reply, sizeof(reply));
|
|
return B_OK;
|
|
}
|
|
|
|
case PRODUCER_CONNECT:
|
|
{
|
|
const xfer_producer_connect *data = (const xfer_producer_connect *)rawdata;
|
|
xfer_producer_connect_reply reply;
|
|
memcpy(reply.name, data->name, B_MEDIA_NAME_LENGTH);
|
|
Connect(data->error, data->source, data->destination, data->format, reply.name);
|
|
write_port(data->reply_port, 0, &reply, sizeof(reply));
|
|
return B_OK;
|
|
}
|
|
|
|
case PRODUCER_DISCONNECT:
|
|
{
|
|
const xfer_producer_disconnect *data = (const xfer_producer_disconnect *)rawdata;
|
|
Disconnect(data->source, data->destination);
|
|
return B_OK;
|
|
}
|
|
|
|
case PRODUCER_GET_INITIAL_LATENCY:
|
|
{
|
|
const xfer_producer_get_initial_latency *data = (const xfer_producer_get_initial_latency *)rawdata;
|
|
xfer_producer_get_initial_latency_reply reply;
|
|
reply.initial_latency = fInitialLatency;
|
|
reply.flags = fInitialFlags;
|
|
write_port(data->reply_port, 0, &reply, sizeof(reply));
|
|
return B_OK;
|
|
}
|
|
|
|
case PRODUCER_SET_PLAY_RATE:
|
|
{
|
|
const xfer_producer_set_play_rate *data = (const xfer_producer_set_play_rate *)rawdata;
|
|
xfer_producer_set_play_rate_reply reply;
|
|
reply.result = SetPlayRate(data->numer, data->denom);
|
|
write_port(data->reply_port, 0, &reply, sizeof(reply));
|
|
return B_OK;
|
|
}
|
|
|
|
case PRODUCER_GET_LATENCY:
|
|
{
|
|
const xfer_producer_get_latency *data = (const xfer_producer_get_latency *)rawdata;
|
|
xfer_producer_get_latency_reply reply;
|
|
reply.result = GetLatency(&reply.latency);
|
|
write_port(data->reply_port, 0, &reply, sizeof(reply));
|
|
return B_OK;
|
|
}
|
|
|
|
case PRODUCER_GET_NEXT_OUTPUT:
|
|
{
|
|
const xfer_producer_get_next_output *data = (const xfer_producer_get_next_output *)rawdata;
|
|
xfer_producer_get_next_output_reply reply;
|
|
reply.cookie = data->cookie;
|
|
reply.result = GetNextOutput(&reply.cookie, &reply.output);
|
|
write_port(data->reply_port, 0, &reply, sizeof(reply));
|
|
return B_OK;
|
|
}
|
|
|
|
case PRODUCER_DISPOSE_OUTPUT_COOKIE:
|
|
{
|
|
const xfer_producer_dispose_output_cookie *data = (const xfer_producer_dispose_output_cookie *)rawdata;
|
|
DisposeOutputCookie(data->cookie);
|
|
return B_OK;
|
|
}
|
|
|
|
case PRODUCER_SET_BUFFER_GROUP:
|
|
{
|
|
const xfer_producer_set_buffer_group *data = (const xfer_producer_set_buffer_group *)rawdata;
|
|
xfer_node_request_completed reply;
|
|
BBufferGroup *group;
|
|
status_t rv;
|
|
group = data->buffer_count != 0 ? new BBufferGroup(data->buffer_count, data->buffers) : NULL;
|
|
rv = SetBufferGroup(data->source, group);
|
|
if (data->destination == media_destination::null)
|
|
return B_OK;
|
|
reply.info.what = media_request_info::B_SET_OUTPUT_BUFFERS_FOR;
|
|
reply.info.change_tag = data->change_tag;
|
|
reply.info.status = rv;
|
|
reply.info.cookie = (int32)group;
|
|
reply.info.user_data = data->user_data;
|
|
reply.info.source = data->source;
|
|
reply.info.destination = data->destination;
|
|
write_port(data->destination.port, NODE_REQUEST_COMPLETED, &reply, sizeof(reply));
|
|
return B_OK;
|
|
}
|
|
|
|
case PRODUCER_FORMAT_CHANGE_REQUESTED:
|
|
{
|
|
const xfer_producer_format_change_requested *data = (const xfer_producer_format_change_requested *)rawdata;
|
|
xfer_node_request_completed reply;
|
|
status_t rv;
|
|
reply.info.format = data->format;
|
|
rv = FormatChangeRequested(data->source, data->destination, &reply.info.format, NULL);
|
|
if (data->destination == media_destination::null)
|
|
return B_OK;
|
|
reply.info.what = media_request_info::B_REQUEST_FORMAT_CHANGE;
|
|
reply.info.change_tag = data->change_tag;
|
|
reply.info.status = rv;
|
|
//reply.info.cookie
|
|
reply.info.user_data = data->user_data;
|
|
reply.info.source = data->source;
|
|
reply.info.destination = data->destination;
|
|
write_port(data->destination.port, NODE_REQUEST_COMPLETED, &reply, sizeof(reply));
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
case PRODUCER_VIDEO_CLIPPING_CHANGED:
|
|
{
|
|
const xfer_producer_video_clipping_changed *data = (const xfer_producer_video_clipping_changed *)rawdata;
|
|
xfer_node_request_completed reply;
|
|
status_t rv;
|
|
rv = VideoClippingChanged(data->source, data->short_count, (int16 *)data->shorts, data->display, NULL);
|
|
if (data->destination == media_destination::null)
|
|
return B_OK;
|
|
reply.info.what = media_request_info::B_SET_VIDEO_CLIPPING_FOR;
|
|
reply.info.change_tag = data->change_tag;
|
|
reply.info.status = rv;
|
|
//reply.info.cookie
|
|
reply.info.user_data = data->user_data;
|
|
reply.info.source = data->source;
|
|
reply.info.destination = data->destination;
|
|
reply.info.format.type = B_MEDIA_RAW_VIDEO;
|
|
reply.info.format.u.raw_video.display = data->display;
|
|
write_port(data->destination.port, NODE_REQUEST_COMPLETED, &reply, sizeof(reply));
|
|
return B_OK;
|
|
}
|
|
|
|
case PRODUCER_ADDITIONAL_BUFFER_REQUESTED:
|
|
{
|
|
const xfer_producer_additional_buffer_requested *data = (const xfer_producer_additional_buffer_requested *)rawdata;
|
|
AdditionalBufferRequested(data->source, data->prev_buffer, data->prev_time, data->has_seek_tag ? &data->prev_tag : NULL);
|
|
return B_OK;
|
|
}
|
|
|
|
case PRODUCER_LATENCY_CHANGED:
|
|
{
|
|
const xfer_producer_latency_changed *data = (const xfer_producer_latency_changed *)rawdata;
|
|
LatencyChanged(data->source, data->destination, data->latency, data->flags);
|
|
return B_OK;
|
|
}
|
|
|
|
case PRODUCER_LATE_NOTICE_RECEIVED:
|
|
{
|
|
const xfer_producer_late_notice_received *data = (const xfer_producer_late_notice_received *)rawdata;
|
|
LateNoticeReceived(data->source, data->how_much, data->performance_time);
|
|
return B_OK;
|
|
}
|
|
|
|
case PRODUCER_ENABLE_OUTPUT:
|
|
{
|
|
const xfer_producer_enable_output *data = (const xfer_producer_enable_output *)rawdata;
|
|
xfer_node_request_completed reply;
|
|
EnableOutput(data->source, data->enabled, NULL);
|
|
if (data->destination == media_destination::null)
|
|
return B_OK;
|
|
reply.info.what = media_request_info::B_SET_OUTPUT_ENABLED;
|
|
reply.info.change_tag = data->change_tag;
|
|
reply.info.status = B_OK;
|
|
//reply.info.cookie
|
|
reply.info.user_data = data->user_data;
|
|
reply.info.source = data->source;
|
|
reply.info.destination = data->destination;
|
|
//reply.info.format
|
|
write_port(data->destination.port, NODE_REQUEST_COMPLETED, &reply, sizeof(reply));
|
|
return B_OK;
|
|
}
|
|
|
|
};
|
|
return B_ERROR;
|
|
}
|
|
|
|
|
|
void
|
|
BBufferProducer::AdditionalBufferRequested(const media_source &source,
|
|
media_buffer_id prev_buffer,
|
|
bigtime_t prev_time,
|
|
const media_seek_tag *prev_tag)
|
|
{
|
|
CALLED();
|
|
// may be implemented by derived classes
|
|
}
|
|
|
|
|
|
void
|
|
BBufferProducer::LatencyChanged(const media_source &source,
|
|
const media_destination &destination,
|
|
bigtime_t new_latency,
|
|
uint32 flags)
|
|
{
|
|
CALLED();
|
|
// may be implemented by derived classes
|
|
}
|
|
|
|
|
|
status_t
|
|
BBufferProducer::SendBuffer(BBuffer *buffer,
|
|
const media_destination &destination)
|
|
{
|
|
CALLED();
|
|
if (destination == media_destination::null)
|
|
return B_MEDIA_BAD_DESTINATION;
|
|
if (buffer == NULL)
|
|
return B_BAD_VALUE;
|
|
|
|
xfer_consumer_buffer_received data;
|
|
data.buffer = buffer->ID();
|
|
data.header = *(buffer->Header());
|
|
data.header.buffer = data.buffer;
|
|
data.header.destination = destination.id;
|
|
|
|
return write_port(destination.port, CONSUMER_BUFFER_RECEIVED, &data, sizeof(data));
|
|
}
|
|
|
|
|
|
status_t
|
|
BBufferProducer::SendDataStatus(int32 status,
|
|
const media_destination &destination,
|
|
bigtime_t at_time)
|
|
{
|
|
CALLED();
|
|
if (destination == media_destination::null)
|
|
return B_MEDIA_BAD_DESTINATION;
|
|
|
|
xfer_consumer_producer_data_status data;
|
|
data.for_whom = destination;
|
|
data.status = status;
|
|
data.at_performance_time = at_time;
|
|
|
|
return write_port(destination.port, CONSUMER_PRODUCER_DATA_STATUS, &data, sizeof(data));
|
|
}
|
|
|
|
|
|
status_t
|
|
BBufferProducer::ProposeFormatChange(media_format *format,
|
|
const media_destination &for_destination)
|
|
{
|
|
CALLED();
|
|
if (for_destination == media_destination::null)
|
|
return B_MEDIA_BAD_DESTINATION;
|
|
|
|
status_t rv;
|
|
int32 code;
|
|
xfer_consumer_accept_format data;
|
|
xfer_consumer_accept_format_reply reply;
|
|
|
|
data.dest = for_destination;
|
|
data.format = *format;
|
|
data.reply_port = _PortPool->GetPort();
|
|
|
|
rv = write_port(for_destination.port, CONSUMER_ACCEPT_FORMAT, &data, sizeof(data));
|
|
if (rv != B_OK) {
|
|
_PortPool->PutPort(data.reply_port);
|
|
return rv;
|
|
}
|
|
|
|
rv = read_port(data.reply_port, &code, &reply, sizeof(reply));
|
|
_PortPool->PutPort(data.reply_port);
|
|
if (rv < B_OK)
|
|
return rv;
|
|
|
|
*format = reply.format;
|
|
|
|
return reply.result;
|
|
}
|
|
|
|
|
|
status_t
|
|
BBufferProducer::ChangeFormat(const media_source &for_source,
|
|
const media_destination &for_destination,
|
|
media_format *format)
|
|
{
|
|
CALLED();
|
|
if (for_source == media_source::null)
|
|
return B_MEDIA_BAD_SOURCE;
|
|
if (for_destination == media_destination::null)
|
|
return B_MEDIA_BAD_DESTINATION;
|
|
|
|
status_t rv;
|
|
int32 code;
|
|
xfer_consumer_format_changed data;
|
|
xfer_consumer_format_changed_reply reply;
|
|
|
|
data.producer = for_source;
|
|
data.consumer = for_destination;
|
|
data.format = *format;
|
|
data.reply_port = _PortPool->GetPort();
|
|
|
|
rv = write_port(for_destination.port, CONSUMER_FORMAT_CHANGED, &data, sizeof(data));
|
|
if (rv != B_OK) {
|
|
_PortPool->PutPort(data.reply_port);
|
|
return rv;
|
|
}
|
|
|
|
rv = read_port(data.reply_port, &code, &reply, sizeof(reply));
|
|
_PortPool->PutPort(data.reply_port);
|
|
if (rv < B_OK)
|
|
return rv;
|
|
|
|
return reply.result;
|
|
}
|
|
|
|
|
|
status_t
|
|
BBufferProducer::FindLatencyFor(const media_destination &for_destination,
|
|
bigtime_t *out_latency,
|
|
media_node_id *out_timesource)
|
|
{
|
|
CALLED();
|
|
if (for_destination == media_destination::null)
|
|
return B_MEDIA_BAD_DESTINATION;
|
|
|
|
status_t rv;
|
|
int32 code;
|
|
xfer_consumer_get_latency_for data;
|
|
xfer_consumer_get_latency_for_reply reply;
|
|
|
|
data.for_whom = for_destination;
|
|
data.reply_port = _PortPool->GetPort();
|
|
|
|
rv = write_port(for_destination.port, CONSUMER_GET_LATENCY_FOR, &data, sizeof(data));
|
|
if (rv != B_OK) {
|
|
_PortPool->PutPort(data.reply_port);
|
|
return rv;
|
|
}
|
|
|
|
rv = read_port(data.reply_port, &code, &reply, sizeof(reply));
|
|
_PortPool->PutPort(data.reply_port);
|
|
if (rv < B_OK)
|
|
return rv;
|
|
|
|
*out_latency = reply.latency;
|
|
*out_timesource = reply.timesource;
|
|
|
|
return reply.result;
|
|
}
|
|
|
|
|
|
status_t
|
|
BBufferProducer::FindSeekTag(const media_destination &for_destination,
|
|
bigtime_t in_target_time,
|
|
media_seek_tag *out_tag,
|
|
bigtime_t *out_tagged_time,
|
|
uint32 *out_flags,
|
|
uint32 in_flags)
|
|
{
|
|
CALLED();
|
|
if (for_destination == media_destination::null)
|
|
return B_MEDIA_BAD_DESTINATION;
|
|
|
|
status_t rv;
|
|
int32 code;
|
|
xfer_consumer_seek_tag_requested data;
|
|
xfer_consumer_seek_tag_requested_reply reply;
|
|
|
|
data.destination = for_destination;
|
|
data.target_time = in_target_time;
|
|
data.flags = in_flags;
|
|
data.reply_port = _PortPool->GetPort();
|
|
|
|
rv = write_port(for_destination.port, CONSUMER_SEEK_TAG_REQUESTED, &data, sizeof(data));
|
|
if (rv != B_OK) {
|
|
_PortPool->PutPort(data.reply_port);
|
|
return rv;
|
|
}
|
|
|
|
rv = read_port(data.reply_port, &code, &reply, sizeof(reply));
|
|
_PortPool->PutPort(data.reply_port);
|
|
if (rv < B_OK)
|
|
return rv;
|
|
|
|
*out_tag = reply.seek_tag;
|
|
*out_tagged_time = reply.tagged_time;
|
|
*out_flags = reply.flags;
|
|
|
|
return reply.result;
|
|
}
|
|
|
|
|
|
void
|
|
BBufferProducer::SetInitialLatency(bigtime_t inInitialLatency,
|
|
uint32 flags)
|
|
{
|
|
fInitialLatency = inInitialLatency;
|
|
fInitialFlags = flags;
|
|
}
|
|
|
|
/*************************************************************
|
|
* private BBufferProducer
|
|
*************************************************************/
|
|
|
|
/*
|
|
private unimplemented
|
|
BBufferProducer::BBufferProducer()
|
|
BBufferProducer::BBufferProducer(const BBufferProducer &clone)
|
|
BBufferProducer & BBufferProducer::operator=(const BBufferProducer &clone)
|
|
*/
|
|
|
|
status_t BBufferProducer::_Reserved_BufferProducer_0(void *) { return B_ERROR; }
|
|
status_t BBufferProducer::_Reserved_BufferProducer_1(void *) { return B_ERROR; }
|
|
status_t BBufferProducer::_Reserved_BufferProducer_2(void *) { return B_ERROR; }
|
|
status_t BBufferProducer::_Reserved_BufferProducer_3(void *) { return B_ERROR; }
|
|
status_t BBufferProducer::_Reserved_BufferProducer_4(void *) { return B_ERROR; }
|
|
status_t BBufferProducer::_Reserved_BufferProducer_5(void *) { return B_ERROR; }
|
|
status_t BBufferProducer::_Reserved_BufferProducer_6(void *) { return B_ERROR; }
|
|
status_t BBufferProducer::_Reserved_BufferProducer_7(void *) { return B_ERROR; }
|
|
status_t BBufferProducer::_Reserved_BufferProducer_8(void *) { return B_ERROR; }
|
|
status_t BBufferProducer::_Reserved_BufferProducer_9(void *) { return B_ERROR; }
|
|
status_t BBufferProducer::_Reserved_BufferProducer_10(void *) { return B_ERROR; }
|
|
status_t BBufferProducer::_Reserved_BufferProducer_11(void *) { return B_ERROR; }
|
|
status_t BBufferProducer::_Reserved_BufferProducer_12(void *) { return B_ERROR; }
|
|
status_t BBufferProducer::_Reserved_BufferProducer_13(void *) { return B_ERROR; }
|
|
status_t BBufferProducer::_Reserved_BufferProducer_14(void *) { return B_ERROR; }
|
|
status_t BBufferProducer::_Reserved_BufferProducer_15(void *) { return B_ERROR; }
|
|
|
|
|
|
status_t
|
|
BBufferProducer::clip_shorts_to_region(const int16 *data,
|
|
int count,
|
|
BRegion *output)
|
|
{
|
|
UNIMPLEMENTED();
|
|
|
|
return B_ERROR;
|
|
}
|
|
|
|
|
|
status_t
|
|
BBufferProducer::clip_region_to_shorts(const BRegion *input,
|
|
int16 *data,
|
|
int max_count,
|
|
int *out_count)
|
|
{
|
|
UNIMPLEMENTED();
|
|
|
|
return B_ERROR;
|
|
}
|
|
|