haiku/src/kits/media/MediaRecorderNode.cpp

354 lines
6.0 KiB
C++

/*
* Copyright 2014-2016, Dario Casalinuovo
* Copyright 1999, Be Incorporated
* All Rights Reserved.
* This file may be used under the terms of the Be Sample Code License.
*/
#include "MediaRecorderNode.h"
#include <Buffer.h>
#include <scheduler.h>
#include <MediaRoster.h>
#include <MediaRosterEx.h>
#include <TimedEventQueue.h>
#include <TimeSource.h>
#include "MediaDebug.h"
BMediaRecorderNode::BMediaRecorderNode(const char* name,
BMediaRecorder* recorder, media_type type)
:
BMediaNode(name),
BMediaEventLooper(),
BBufferConsumer(type),
fRecorder(recorder),
fConnectMode(true)
{
CALLED();
fInput.node = Node();
fInput.destination.id = 1;
fInput.destination.port = ControlPort();
fName.SetTo(name);
BString str(name);
str << " Input";
strcpy(fInput.name, str.String());
}
BMediaRecorderNode::~BMediaRecorderNode()
{
CALLED();
}
BMediaAddOn*
BMediaRecorderNode::AddOn(int32* id) const
{
CALLED();
if (id)
*id = -1;
return NULL;
}
void
BMediaRecorderNode::NodeRegistered()
{
CALLED();
Run();
}
void
BMediaRecorderNode::SetRunMode(run_mode mode)
{
CALLED();
int32 priority;
if (mode == BMediaNode::B_OFFLINE)
priority = B_OFFLINE_PROCESSING;
else {
switch(ConsumerType()) {
case B_MEDIA_RAW_AUDIO:
case B_MEDIA_ENCODED_AUDIO:
priority = B_AUDIO_RECORDING;
break;
case B_MEDIA_RAW_VIDEO:
case B_MEDIA_ENCODED_VIDEO:
priority = B_VIDEO_RECORDING;
break;
default:
priority = B_DEFAULT_MEDIA_PRIORITY;
}
}
SetPriority(suggest_thread_priority(priority));
BMediaNode::SetRunMode(mode);
}
void
BMediaRecorderNode::SetAcceptedFormat(const media_format& format)
{
CALLED();
fInput.format = format;
fOKFormat = format;
}
const media_format&
BMediaRecorderNode::AcceptedFormat() const
{
CALLED();
return fInput.format;
}
void
BMediaRecorderNode::GetInput(media_input* outInput)
{
CALLED();
fInput.node = Node();
*outInput = fInput;
}
void
BMediaRecorderNode::SetDataEnabled(bool enabled)
{
CALLED();
int32 tag;
SetOutputEnabled(fInput.source,
fInput.destination, enabled, NULL, &tag);
}
void
BMediaRecorderNode::ActivateInternalConnect(bool connectMode)
{
fConnectMode = connectMode;
}
void
BMediaRecorderNode::HandleEvent(const media_timed_event* event,
bigtime_t lateness, bool realTimeEvent)
{
CALLED();
// we ignore them all!
}
void
BMediaRecorderNode::Start(bigtime_t performanceTime)
{
CALLED();
if (fRecorder->fNotifyHook)
(*fRecorder->fNotifyHook)(fRecorder->fBufferCookie,
BMediaRecorder::B_WILL_START, performanceTime);
fRecorder->fRunning = true;
}
void
BMediaRecorderNode::Stop(bigtime_t performanceTime, bool immediate)
{
CALLED();
if (fRecorder->fNotifyHook)
(*fRecorder->fNotifyHook)(fRecorder->fBufferCookie,
BMediaRecorder::B_WILL_STOP, performanceTime, immediate);
fRecorder->fRunning = false;
}
void
BMediaRecorderNode::Seek(bigtime_t mediaTime, bigtime_t performanceTime)
{
CALLED();
if (fRecorder->fNotifyHook)
(*fRecorder->fNotifyHook)(fRecorder->fBufferCookie,
BMediaRecorder::B_WILL_SEEK, performanceTime, mediaTime);
}
void
BMediaRecorderNode::TimeWarp(bigtime_t realTime, bigtime_t performanceTime)
{
CALLED();
// Since buffers will come pre-time-stamped, we only need to look
// at them, so we can ignore the time warp as a consumer.
if (fRecorder->fNotifyHook)
(*fRecorder->fNotifyHook)(fRecorder->fBufferCookie,
BMediaRecorder::B_WILL_TIMEWARP, realTime, performanceTime);
}
status_t
BMediaRecorderNode::HandleMessage(int32 message,
const void* data, size_t size)
{
CALLED();
if (BBufferConsumer::HandleMessage(message, data, size) < 0
&& BMediaEventLooper::HandleMessage(message, data, size) < 0
&& BMediaNode::HandleMessage(message, data, size) < 0) {
HandleBadMessage(message, data, size);
return B_ERROR;
}
return B_OK;
}
status_t
BMediaRecorderNode::AcceptFormat(const media_destination& dest,
media_format* format)
{
CALLED();
if (format_is_compatible(*format, fOKFormat))
return B_OK;
*format = fOKFormat;
return B_MEDIA_BAD_FORMAT;
}
status_t
BMediaRecorderNode::GetNextInput(int32* cookie, media_input* outInput)
{
CALLED();
if (*cookie == 0) {
*cookie = -1;
*outInput = fInput;
return B_OK;
}
return B_BAD_INDEX;
}
void
BMediaRecorderNode::DisposeInputCookie(int32 cookie)
{
CALLED();
}
void
BMediaRecorderNode::BufferReceived(BBuffer* buffer)
{
CALLED();
fRecorder->BufferReceived(buffer->Data(), buffer->SizeUsed(),
*buffer->Header());
buffer->Recycle();
}
void
BMediaRecorderNode::ProducerDataStatus(
const media_destination& forWhom, int32 status,
bigtime_t performanceTime)
{
CALLED();
}
status_t
BMediaRecorderNode::GetLatencyFor(const media_destination& forWhom,
bigtime_t* outLatency, media_node_id* outTimesource)
{
CALLED();
*outLatency = 0;
*outTimesource = TimeSource()->ID();
return B_OK;
}
status_t
BMediaRecorderNode::Connected(const media_source &producer,
const media_destination &where, const media_format &withFormat,
media_input* outInput)
{
CALLED();
fInput.source = producer;
fInput.format = withFormat;
*outInput = fInput;
if (fConnectMode == true) {
// This is a workaround needed for us to get the node
// so that our owner class can do it's operations.
media_node node;
BMediaRosterEx* roster = MediaRosterEx(BMediaRoster::CurrentRoster());
if (roster->GetNodeFor(roster->NodeIDFor(producer.port), &node) != B_OK)
return B_MEDIA_BAD_NODE;
fRecorder->fOutputNode = node;
fRecorder->fReleaseOutputNode = true;
}
fRecorder->SetUpConnection(producer);
fRecorder->fConnected = true;
return B_OK;
}
void
BMediaRecorderNode::Disconnected(const media_source& producer,
const media_destination& where)
{
CALLED();
fInput.source = media_source::null;
// Reset the connection mode
fConnectMode = true;
fRecorder->fConnected = false;
fInput.format = fOKFormat;
}
status_t
BMediaRecorderNode::FormatChanged(const media_source& producer,
const media_destination& consumer, int32 tag,
const media_format& format)
{
CALLED();
if (!format_is_compatible(format, fOKFormat))
return B_MEDIA_BAD_FORMAT;
fInput.format = format;
return B_OK;
}