/* * Copyright 2015, Hamish Morrison * 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 #include #include #include #include "MediaDebug.h" #include "MediaRecorderNode.h" BMediaRecorder::BMediaRecorder(const char* name, media_type type) : fInitErr(B_OK), fConnected(false), fRunning(false), fReleaseOutputNode(false), fRecordHook(NULL), fNotifyHook(NULL), fNode(NULL), fBufferCookie(NULL) { CALLED(); BMediaRoster::Roster(&fInitErr); if (fInitErr == B_OK) { fNode = new(std::nothrow) BMediaRecorderNode(name, this, type); if (fNode == NULL) fInitErr = B_NO_MEMORY; fInitErr = BMediaRoster::CurrentRoster()->RegisterNode(fNode); } } BMediaRecorder::~BMediaRecorder() { CALLED(); if (fNode != NULL) { Stop(); Disconnect(); fNode->Release(); } } status_t BMediaRecorder::InitCheck() const { CALLED(); return fInitErr; } void BMediaRecorder::SetAcceptedFormat(const media_format& format) { CALLED(); fNode->SetAcceptedFormat(format); } const media_format& BMediaRecorder::AcceptedFormat() const { CALLED(); return fNode->AcceptedFormat(); } status_t BMediaRecorder::SetHooks(ProcessFunc recordFunc, NotifyFunc notifyFunc, void* cookie) { CALLED(); fRecordHook = recordFunc; fNotifyHook = notifyFunc; fBufferCookie = cookie; return B_OK; } void BMediaRecorder::BufferReceived(void* buffer, size_t size, const media_header& header) { CALLED(); if (fRecordHook) { (*fRecordHook)(fBufferCookie, header.start_time, buffer, size, Format()); } } status_t BMediaRecorder::Connect(const media_format& format) { CALLED(); if (fInitErr != B_OK) return fInitErr; if (fConnected) return B_MEDIA_ALREADY_CONNECTED; status_t err = B_OK; media_node node; switch (format.type) { // switch on format for default case B_MEDIA_RAW_AUDIO: err = BMediaRoster::Roster()->GetAudioMixer(&node); break; case B_MEDIA_RAW_VIDEO: case B_MEDIA_ENCODED_VIDEO: err = BMediaRoster::Roster()->GetVideoInput(&node); break; // give up? default: return B_MEDIA_BAD_FORMAT; } if (err != B_OK) return err; fReleaseOutputNode = true; err = _Connect(node, NULL, format); if (err != B_OK) { BMediaRoster::Roster()->ReleaseNode(node); fReleaseOutputNode = false; } return err; } status_t BMediaRecorder::Connect(const dormant_node_info& dormantNode, const media_format& format) { CALLED(); if (fInitErr != B_OK) return fInitErr; if (fConnected) return B_MEDIA_ALREADY_CONNECTED; media_node node; status_t err = BMediaRoster::Roster()->InstantiateDormantNode(dormantNode, &node, B_FLAVOR_IS_GLOBAL); if (err != B_OK) return err; fReleaseOutputNode = true; err = _Connect(node, NULL, format); if (err != B_OK) { BMediaRoster::Roster()->ReleaseNode(node); fReleaseOutputNode = false; } return err; } status_t BMediaRecorder::Connect(const media_node& node, const media_output* output, const media_format* format) { CALLED(); if (fInitErr != B_OK) return fInitErr; if (fConnected) return B_MEDIA_ALREADY_CONNECTED; if (format == NULL && output != NULL) format = &output->format; return _Connect(node, output, *format); } status_t BMediaRecorder::Disconnect() { CALLED(); status_t err = B_OK; if (fInitErr != B_OK) return fInitErr; if (!fConnected) return B_MEDIA_NOT_CONNECTED; if (!fNode) return B_ERROR; if (fRunning) err = Stop(); if (err != B_OK) return err; media_input ourInput; fNode->GetInput(&ourInput); // do the disconnect err = BMediaRoster::CurrentRoster()->Disconnect( fOutputNode.node, fOutputSource, fNode->Node().node, ourInput.destination); if (fReleaseOutputNode) { BMediaRoster::Roster()->ReleaseNode(fOutputNode); fReleaseOutputNode = false; } fConnected = false; fRunning = false; return err; } status_t BMediaRecorder::Start(bool force) { CALLED(); if (fInitErr != B_OK) return fInitErr; if (!fConnected) return B_MEDIA_NOT_CONNECTED; if (fRunning && !force) return EALREADY; if (!fNode) return B_ERROR; // start node here status_t err = B_OK; if ((fOutputNode.kind & B_TIME_SOURCE) != 0) err = BMediaRoster::CurrentRoster()->StartTimeSource( fOutputNode, BTimeSource::RealTime()); else err = BMediaRoster::CurrentRoster()->StartNode( fOutputNode, fNode->TimeSource()->Now()); // then un-mute it if (err == B_OK) { fNode->SetDataEnabled(true); fRunning = true; } else fRunning = false; return err; } status_t BMediaRecorder::Stop(bool force) { CALLED(); if (fInitErr != B_OK) return fInitErr; if (!fRunning && !force) return EALREADY; if (!fNode) return B_ERROR; // should have the Node mute the output here fNode->SetDataEnabled(false); fRunning = false; return BMediaRoster::CurrentRoster()->StopNode(fNode->Node(), 0); } bool BMediaRecorder::IsRunning() const { CALLED(); return fRunning; } bool BMediaRecorder::IsConnected() const { CALLED(); return fConnected; } const media_source& BMediaRecorder::MediaSource() const { CALLED(); return fOutputSource; } const media_input BMediaRecorder::MediaInput() const { CALLED(); media_input input; fNode->GetInput(&input); return input; } const media_format& BMediaRecorder::Format() const { CALLED(); return fNode->AcceptedFormat(); } status_t BMediaRecorder::SetUpConnection(media_source outputSource) { fOutputSource = outputSource; // Perform the connection media_node timeSource; if ((fOutputNode.kind & B_TIME_SOURCE) != 0) timeSource = fOutputNode; else BMediaRoster::Roster()->GetTimeSource(&timeSource); // Set time source return BMediaRoster::Roster()->SetTimeSourceFor(fNode->Node().node, timeSource.node); } status_t BMediaRecorder::_Connect(const media_node& node, const media_output* output, const media_format& format) { CALLED(); status_t err = B_OK; media_format ourFormat = format; media_output ourOutput; if (fNode == NULL) return B_ERROR; fNode->SetAcceptedFormat(ourFormat); fOutputNode = node; // Figure out the output provided if (output != NULL) { ourOutput = *output; } else if (err == B_OK) { media_output outputs[10]; int32 count = 10; err = BMediaRoster::Roster()->GetFreeOutputsFor(fOutputNode, outputs, count, &count, ourFormat.type); if (err != B_OK) return err; for (int i = 0; i < count; i++) { if (format_is_compatible(outputs[i].format, ourFormat)) { ourOutput = outputs[i]; ourFormat = outputs[i].format; break; } } } if (ourOutput.source == media_source::null) return B_MEDIA_BAD_SOURCE; // Find our Node's free input media_input ourInput; fNode->GetInput(&ourInput); // Acknowledge the node that we already know // who is our producer node. fNode->ActivateInternalConnect(false); return BMediaRoster::CurrentRoster()->Connect(ourOutput.source, ourInput.destination, &ourFormat, &ourOutput, &ourInput, BMediaRoster::B_CONNECT_MUTED); } void BMediaRecorder::_ReservedMediaRecorder0() { } void BMediaRecorder::_ReservedMediaRecorder1() { } void BMediaRecorder::_ReservedMediaRecorder2() { } void BMediaRecorder::_ReservedMediaRecorder3() { } void BMediaRecorder::_ReservedMediaRecorder4() { } void BMediaRecorder::_ReservedMediaRecorder5() { } void BMediaRecorder::_ReservedMediaRecorder6() { } void BMediaRecorder::_ReservedMediaRecorder7() { }