19b410c41SDario Casalinuovo/*
29b410c41SDario Casalinuovo * Copyright 2015, Dario Casalinuovo. All rights reserved.
39b410c41SDario Casalinuovo * Distributed under the terms of the MIT License.
49b410c41SDario Casalinuovo */
59b410c41SDario Casalinuovo
69b410c41SDario Casalinuovo#include "MediaClientNode.h"
79b410c41SDario Casalinuovo
89b410c41SDario Casalinuovo#include <MediaClient.h>
9f506f305SDario Casalinuovo#include <MediaConnection.h>
1065a94fbbSBarrett#include <MediaRoster.h>
119b410c41SDario Casalinuovo#include <scheduler.h>
129b410c41SDario Casalinuovo#include <TimeSource.h>
139b410c41SDario Casalinuovo
149b410c41SDario Casalinuovo#include <string.h>
159b410c41SDario Casalinuovo
16b84955d4SBarrett#include "MediaDebug.h"
179b410c41SDario Casalinuovo
189b410c41SDario Casalinuovo#define B_NEW_BUFFER (BTimedEventQueue::B_USER_EVENT + 1)
199b410c41SDario Casalinuovo
209b410c41SDario Casalinuovo
219b410c41SDario CasalinuovoBMediaClientNode::BMediaClientNode(const char* name,
229b410c41SDario Casalinuovo	BMediaClient* owner, media_type type)
239b410c41SDario Casalinuovo	:
249b410c41SDario Casalinuovo	BMediaNode(name),
259b410c41SDario Casalinuovo	BBufferConsumer(type),
269b410c41SDario Casalinuovo	BBufferProducer(type),
279b410c41SDario Casalinuovo	BMediaEventLooper(),
289b410c41SDario Casalinuovo	fOwner(owner)
299b410c41SDario Casalinuovo{
309b410c41SDario Casalinuovo	CALLED();
319b410c41SDario Casalinuovo
329b410c41SDario Casalinuovo	// Configure the node to do the requested jobs
33f1f09565SDario Casalinuovo	if (fOwner->Kinds() & B_MEDIA_PLAYER)
349b410c41SDario Casalinuovo		AddNodeKind(B_BUFFER_PRODUCER);
35f1f09565SDario Casalinuovo	if (fOwner->Kinds() & B_MEDIA_RECORDER)
369b410c41SDario Casalinuovo		AddNodeKind(B_BUFFER_CONSUMER);
37f1f09565SDario Casalinuovo	if (fOwner->Kinds() & B_MEDIA_CONTROLLABLE)
389b410c41SDario Casalinuovo		AddNodeKind(B_CONTROLLABLE);
399b410c41SDario Casalinuovo}
409b410c41SDario Casalinuovo
419b410c41SDario Casalinuovo
429b410c41SDario Casalinuovostatus_t
439b410c41SDario CasalinuovoBMediaClientNode::SendBuffer(BBuffer* buffer, BMediaConnection* conn)
449b410c41SDario Casalinuovo{
45d64dd7beSDario Casalinuovo	return BBufferProducer::SendBuffer(buffer, conn->_Source(), conn->_Destination());
469b410c41SDario Casalinuovo}
479b410c41SDario Casalinuovo
489b410c41SDario Casalinuovo
499b410c41SDario CasalinuovoBMediaAddOn*
509b410c41SDario CasalinuovoBMediaClientNode::AddOn(int32* id) const
519b410c41SDario Casalinuovo{
529b410c41SDario Casalinuovo	CALLED();
539b410c41SDario Casalinuovo
549b410c41SDario Casalinuovo	return fOwner->AddOn(id);
559b410c41SDario Casalinuovo}
569b410c41SDario Casalinuovo
579b410c41SDario Casalinuovo
589b410c41SDario Casalinuovovoid
599b410c41SDario CasalinuovoBMediaClientNode::NodeRegistered()
609b410c41SDario Casalinuovo{
619b410c41SDario Casalinuovo	CALLED();
629b410c41SDario Casalinuovo
63a6ac14c7SBarrett	fOwner->ClientRegistered();
64a6ac14c7SBarrett
659b410c41SDario Casalinuovo	Run();
669b410c41SDario Casalinuovo}
679b410c41SDario Casalinuovo
689b410c41SDario Casalinuovo
699b410c41SDario Casalinuovovoid
709b410c41SDario CasalinuovoBMediaClientNode::SetRunMode(run_mode mode)
719b410c41SDario Casalinuovo{
729b410c41SDario Casalinuovo	CALLED();
739b410c41SDario Casalinuovo
749b410c41SDario Casalinuovo	int32 priority;
759b410c41SDario Casalinuovo	if (mode == BMediaNode::B_OFFLINE)
769b410c41SDario Casalinuovo		priority = B_OFFLINE_PROCESSING;
779b410c41SDario Casalinuovo	else {
789b410c41SDario Casalinuovo		switch(ConsumerType()) {
799b410c41SDario Casalinuovo			case B_MEDIA_RAW_AUDIO:
809b410c41SDario Casalinuovo			case B_MEDIA_ENCODED_AUDIO:
819b410c41SDario Casalinuovo				priority = B_AUDIO_RECORDING;
829b410c41SDario Casalinuovo				break;
839b410c41SDario Casalinuovo
849b410c41SDario Casalinuovo			case B_MEDIA_RAW_VIDEO:
859b410c41SDario Casalinuovo			case B_MEDIA_ENCODED_VIDEO:
869b410c41SDario Casalinuovo				priority = B_VIDEO_RECORDING;
879b410c41SDario Casalinuovo				break;
889b410c41SDario Casalinuovo
899b410c41SDario Casalinuovo			default:
909b410c41SDario Casalinuovo				priority = B_DEFAULT_MEDIA_PRIORITY;
919b410c41SDario Casalinuovo		}
929b410c41SDario Casalinuovo	}
939b410c41SDario Casalinuovo
949b410c41SDario Casalinuovo	SetPriority(suggest_thread_priority(priority));
959b410c41SDario Casalinuovo	BMediaNode::SetRunMode(mode);
969b410c41SDario Casalinuovo}
979b410c41SDario Casalinuovo
989b410c41SDario Casalinuovo
999b410c41SDario Casalinuovovoid
1009b410c41SDario CasalinuovoBMediaClientNode::Start(bigtime_t performanceTime)
1019b410c41SDario Casalinuovo{
1029b410c41SDario Casalinuovo	CALLED();
1039b410c41SDario Casalinuovo
1049b410c41SDario Casalinuovo	BMediaEventLooper::Start(performanceTime);
1059b410c41SDario Casalinuovo}
1069b410c41SDario Casalinuovo
1079b410c41SDario Casalinuovo
1089b410c41SDario Casalinuovovoid
1099b410c41SDario CasalinuovoBMediaClientNode::Stop(bigtime_t performanceTime, bool immediate)
1109b410c41SDario Casalinuovo{
1119b410c41SDario Casalinuovo	CALLED();
1129b410c41SDario Casalinuovo
1139b410c41SDario Casalinuovo	BMediaEventLooper::Stop(performanceTime, immediate);
1149b410c41SDario Casalinuovo}
1159b410c41SDario Casalinuovo
1169b410c41SDario Casalinuovo
1179b410c41SDario Casalinuovovoid
1189b410c41SDario CasalinuovoBMediaClientNode::Seek(bigtime_t mediaTime, bigtime_t performanceTime)
1199b410c41SDario Casalinuovo{
1209b410c41SDario Casalinuovo	CALLED();
1219b410c41SDario Casalinuovo
1229b410c41SDario Casalinuovo	BMediaEventLooper::Seek(mediaTime, performanceTime);
1239b410c41SDario Casalinuovo}
1249b410c41SDario Casalinuovo
1259b410c41SDario Casalinuovo
1269b410c41SDario Casalinuovovoid
1279b410c41SDario CasalinuovoBMediaClientNode::TimeWarp(bigtime_t realTime, bigtime_t performanceTime)
1289b410c41SDario Casalinuovo{
1299b410c41SDario Casalinuovo	CALLED();
1309b410c41SDario Casalinuovo
1319b410c41SDario Casalinuovo	BMediaEventLooper::TimeWarp(realTime, performanceTime);
1329b410c41SDario Casalinuovo}
1339b410c41SDario Casalinuovo
1349b410c41SDario Casalinuovo
1359b410c41SDario Casalinuovostatus_t
1369b410c41SDario CasalinuovoBMediaClientNode::HandleMessage(int32 message,
1379b410c41SDario Casalinuovo	const void* data, size_t size)
1389b410c41SDario Casalinuovo{
1399b410c41SDario Casalinuovo	CALLED();
1409b410c41SDario Casalinuovo
1419b410c41SDario Casalinuovo	return B_ERROR;
1429b410c41SDario Casalinuovo}
1439b410c41SDario Casalinuovo
1449b410c41SDario Casalinuovo
1459b410c41SDario Casalinuovostatus_t
1469b410c41SDario CasalinuovoBMediaClientNode::AcceptFormat(const media_destination& dest,
1479b410c41SDario Casalinuovo	media_format* format)
1489b410c41SDario Casalinuovo{
1499b410c41SDario Casalinuovo	CALLED();
1509b410c41SDario Casalinuovo
151d64dd7beSDario Casalinuovo	BMediaInput* conn = fOwner->_FindInput(dest);
1529b410c41SDario Casalinuovo	if (conn == NULL)
1539b410c41SDario Casalinuovo		return B_MEDIA_BAD_DESTINATION;
1549b410c41SDario Casalinuovo
1556dc7d854SBarrett	return conn->AcceptFormat(format);
1569b410c41SDario Casalinuovo}
1579b410c41SDario Casalinuovo
1589b410c41SDario Casalinuovo
1599b410c41SDario Casalinuovostatus_t
1609b410c41SDario CasalinuovoBMediaClientNode::GetNextInput(int32* cookie,
1619b410c41SDario Casalinuovo	media_input* input)
1629b410c41SDario Casalinuovo{
1639b410c41SDario Casalinuovo	CALLED();
1649b410c41SDario Casalinuovo
1659b410c41SDario Casalinuovo	if (fOwner->CountInputs() == 0)
1669b410c41SDario Casalinuovo		return B_BAD_INDEX;
1679b410c41SDario Casalinuovo
1689ee6577eSDario Casalinuovo	if (*cookie < 0 || *cookie >= fOwner->CountInputs()) {
1699b410c41SDario Casalinuovo		*cookie = -1;
1709b410c41SDario Casalinuovo		input = NULL;
1719b410c41SDario Casalinuovo	} else {
1726d025521SDario Casalinuovo		BMediaInput* conn = fOwner->InputAt(*cookie);
1739b410c41SDario Casalinuovo		if (conn != NULL) {
1746dc7d854SBarrett			*input = conn->fConnection._BuildMediaInput();
1759b410c41SDario Casalinuovo			*cookie += 1;
1769b410c41SDario Casalinuovo			return B_OK;
1779b410c41SDario Casalinuovo		}
1789b410c41SDario Casalinuovo	}
1799b410c41SDario Casalinuovo	return B_BAD_INDEX;
1809b410c41SDario Casalinuovo}
1819b410c41SDario Casalinuovo
1829b410c41SDario Casalinuovo
1839b410c41SDario Casalinuovovoid
1849b410c41SDario CasalinuovoBMediaClientNode::DisposeInputCookie(int32 cookie)
1859b410c41SDario Casalinuovo{
1869b410c41SDario Casalinuovo	CALLED();
1879b410c41SDario Casalinuovo}
1889b410c41SDario Casalinuovo
1899b410c41SDario Casalinuovo
1909b410c41SDario Casalinuovovoid
1919b410c41SDario CasalinuovoBMediaClientNode::BufferReceived(BBuffer* buffer)
1929b410c41SDario Casalinuovo{
1939b410c41SDario Casalinuovo	CALLED();
1949b410c41SDario Casalinuovo
1959b410c41SDario Casalinuovo	EventQueue()->AddEvent(media_timed_event(buffer->Header()->start_time,
1969b410c41SDario Casalinuovo		BTimedEventQueue::B_HANDLE_BUFFER, buffer,
1979b410c41SDario Casalinuovo		BTimedEventQueue::B_RECYCLE_BUFFER));
1989b410c41SDario Casalinuovo}
1999b410c41SDario Casalinuovo
2009b410c41SDario Casalinuovo
2019b410c41SDario Casalinuovostatus_t
2029b410c41SDario CasalinuovoBMediaClientNode::GetLatencyFor(const media_destination& dest,
2039b410c41SDario Casalinuovo	bigtime_t* latency, media_node_id* timesource)
2049b410c41SDario Casalinuovo{
2059b410c41SDario Casalinuovo	CALLED();
2069b410c41SDario Casalinuovo
207d64dd7beSDario Casalinuovo	BMediaInput* conn = fOwner->_FindInput(dest);
2089b410c41SDario Casalinuovo	if (conn == NULL)
2099b410c41SDario Casalinuovo		return B_MEDIA_BAD_DESTINATION;
2109b410c41SDario Casalinuovo
211c61ffa96SBarrett	//*latency = conn->fLatency;
2129b410c41SDario Casalinuovo	*timesource = TimeSource()->ID();
2139b410c41SDario Casalinuovo	return B_OK;
2149b410c41SDario Casalinuovo}
2159b410c41SDario Casalinuovo
2169b410c41SDario Casalinuovo
2179b410c41SDario Casalinuovostatus_t
2189b410c41SDario CasalinuovoBMediaClientNode::Connected(const media_source& source,
219a546d1f8SDario Casalinuovo	const media_destination& dest, const media_format& format,
2209b410c41SDario Casalinuovo	media_input* outInput)
2219b410c41SDario Casalinuovo{
2229b410c41SDario Casalinuovo	CALLED();
2239b410c41SDario Casalinuovo
224d64dd7beSDario Casalinuovo	BMediaInput* conn = fOwner->_FindInput(dest);
2259b410c41SDario Casalinuovo	if (conn == NULL)
2269b410c41SDario Casalinuovo		return B_MEDIA_BAD_DESTINATION;
2279b410c41SDario Casalinuovo
2289ee6577eSDario Casalinuovo	conn->fConnection.source = source;
2296dc7d854SBarrett	conn->fConnection.format = format;
2309ee6577eSDario Casalinuovo
23165a94fbbSBarrett	// Retrieve the node without using GetNodeFor that's pretty inefficient.
23265a94fbbSBarrett	// Unfortunately we don't have an alternative which doesn't require us
23365a94fbbSBarrett	// to release the cloned node.
23465a94fbbSBarrett	// However, our node will not have flags set. Keep in mind this.
23565a94fbbSBarrett	conn->fConnection.remote_node.node
23665a94fbbSBarrett		= BMediaRoster::CurrentRoster()->NodeIDFor(source.port);
23765a94fbbSBarrett	conn->fConnection.remote_node.port = source.port;
23865a94fbbSBarrett
2399ee6577eSDario Casalinuovo	conn->Connected(format);
2409ee6577eSDario Casalinuovo
2416dc7d854SBarrett	*outInput = conn->fConnection._BuildMediaInput();
2429b410c41SDario Casalinuovo	return B_OK;
2439b410c41SDario Casalinuovo}
2449b410c41SDario Casalinuovo
2459b410c41SDario Casalinuovo
2469b410c41SDario Casalinuovovoid
2479b410c41SDario CasalinuovoBMediaClientNode::Disconnected(const media_source& source,
248a546d1f8SDario Casalinuovo	const media_destination& dest)
2499b410c41SDario Casalinuovo{
2509b410c41SDario Casalinuovo	CALLED();
2519b410c41SDario Casalinuovo
252d64dd7beSDario Casalinuovo	BMediaInput* conn = fOwner->_FindInput(dest);
2539b410c41SDario Casalinuovo	if (conn == NULL)
2549b410c41SDario Casalinuovo		return;
2559b410c41SDario Casalinuovo
2566072c6f1SBarrett	if (conn->_Source() == source) {
2576072c6f1SBarrett		// Cleanup the connection
2586072c6f1SBarrett		conn->fConnection.source = media_source::null;
2596072c6f1SBarrett		conn->fConnection.format = media_format();
2606072c6f1SBarrett
2616072c6f1SBarrett		conn->fConnection.remote_node.node = -1;
2626072c6f1SBarrett		conn->fConnection.remote_node.port = -1;
2636072c6f1SBarrett
264728c730cSDario Casalinuovo		conn->Disconnected();
2656072c6f1SBarrett	}
2669b410c41SDario Casalinuovo}
2679b410c41SDario Casalinuovo
2689b410c41SDario Casalinuovo
2699b410c41SDario Casalinuovostatus_t
2709b410c41SDario CasalinuovoBMediaClientNode::FormatChanged(const media_source& source,
271a546d1f8SDario Casalinuovo	const media_destination& dest,
2729b410c41SDario Casalinuovo	int32 tag, const media_format& format)
2739b410c41SDario Casalinuovo{
2749b410c41SDario Casalinuovo	CALLED();
275182ec76bSBarrett	return B_ERROR;
2769b410c41SDario Casalinuovo}
2779b410c41SDario Casalinuovo
2789b410c41SDario Casalinuovo
2799b410c41SDario Casalinuovostatus_t
2809b410c41SDario CasalinuovoBMediaClientNode::FormatSuggestionRequested(media_type type,
2819b410c41SDario Casalinuovo	int32 quality, media_format* format)
2829b410c41SDario Casalinuovo{
2839b410c41SDario Casalinuovo	CALLED();
2849b410c41SDario Casalinuovo
2859b410c41SDario Casalinuovo	if (type != ConsumerType()
2869b410c41SDario Casalinuovo			&& type != ProducerType()) {
2879b410c41SDario Casalinuovo		return B_MEDIA_BAD_FORMAT;
2889b410c41SDario Casalinuovo	}
2899b410c41SDario Casalinuovo
290d64dd7beSDario Casalinuovo	status_t ret = fOwner->FormatSuggestion(type, quality, format);
291ecb39585SDario Casalinuovo	if (ret != B_OK) {
2929b410c41SDario Casalinuovo		// In that case we return just a very generic format.
2939b410c41SDario Casalinuovo		media_format outFormat;
294f506f305SDario Casalinuovo		outFormat.type = fOwner->MediaType();
2959b410c41SDario Casalinuovo		*format = outFormat;
2969b410c41SDario Casalinuovo		return B_OK;
2979b410c41SDario Casalinuovo	}
298ecb39585SDario Casalinuovo
299ecb39585SDario Casalinuovo	return ret;
3009b410c41SDario Casalinuovo}
3019b410c41SDario Casalinuovo
3029b410c41SDario Casalinuovo
3039b410c41SDario Casalinuovostatus_t
3049b410c41SDario CasalinuovoBMediaClientNode::FormatProposal(const media_source& source,
3059b410c41SDario Casalinuovo	media_format* format)
3069b410c41SDario Casalinuovo{
3079b410c41SDario Casalinuovo	CALLED();
3089b410c41SDario Casalinuovo
309d64dd7beSDario Casalinuovo	BMediaOutput* conn = fOwner->_FindOutput(source);
3109b410c41SDario Casalinuovo	if (conn == NULL)
3119b410c41SDario Casalinuovo		return B_MEDIA_BAD_DESTINATION;
3129b410c41SDario Casalinuovo
3139ee6577eSDario Casalinuovo	return conn->FormatProposal(format);
3149b410c41SDario Casalinuovo}
3159b410c41SDario Casalinuovo
3169b410c41SDario Casalinuovo
3179b410c41SDario Casalinuovostatus_t
3189b410c41SDario CasalinuovoBMediaClientNode::FormatChangeRequested(const media_source& source,
3199b410c41SDario Casalinuovo	const media_destination& dest, media_format* format,
3209b410c41SDario Casalinuovo	int32* _deprecated_)
3219b410c41SDario Casalinuovo{
3229b410c41SDario Casalinuovo	CALLED();
3239b410c41SDario Casalinuovo
324182ec76bSBarrett	return B_ERROR;
3259b410c41SDario Casalinuovo}
3269b410c41SDario Casalinuovo
3279b410c41SDario Casalinuovo
3289b410c41SDario Casalinuovovoid
3299b410c41SDario CasalinuovoBMediaClientNode::LateNoticeReceived(const media_source& source,
3309b410c41SDario Casalinuovo	bigtime_t late, bigtime_t when)
3319b410c41SDario Casalinuovo{
3329b410c41SDario Casalinuovo	CALLED();
3339b410c41SDario Casalinuovo
3349b410c41SDario Casalinuovo}
3359b410c41SDario Casalinuovo
3369b410c41SDario Casalinuovo
3379b410c41SDario Casalinuovostatus_t
3389b410c41SDario CasalinuovoBMediaClientNode::GetNextOutput(int32* cookie, media_output* output)
3399b410c41SDario Casalinuovo{
3409b410c41SDario Casalinuovo	CALLED();
3419b410c41SDario Casalinuovo
3429b410c41SDario Casalinuovo	if (fOwner->CountOutputs() == 0)
3439b410c41SDario Casalinuovo		return B_BAD_INDEX;
3449b410c41SDario Casalinuovo
3459ee6577eSDario Casalinuovo	if (*cookie < 0 || *cookie >= fOwner->CountOutputs()) {
3469b410c41SDario Casalinuovo		*cookie = -1;
3479b410c41SDario Casalinuovo		output = NULL;
3489b410c41SDario Casalinuovo	} else {
3496d025521SDario Casalinuovo		BMediaOutput* conn = fOwner->OutputAt(*cookie);
3509b410c41SDario Casalinuovo		if (conn != NULL) {
3516dc7d854SBarrett			*output = conn->fConnection._BuildMediaOutput();
3529b410c41SDario Casalinuovo			*cookie += 1;
3539b410c41SDario Casalinuovo			return B_OK;
3549b410c41SDario Casalinuovo		}
3559b410c41SDario Casalinuovo	}
3569b410c41SDario Casalinuovo	return B_BAD_INDEX;
3579b410c41SDario Casalinuovo}
3589b410c41SDario Casalinuovo
3599b410c41SDario Casalinuovo
3609b410c41SDario Casalinuovostatus_t
3619b410c41SDario CasalinuovoBMediaClientNode::DisposeOutputCookie(int32 cookie)
3629b410c41SDario Casalinuovo{
3639b410c41SDario Casalinuovo	CALLED();
3649b410c41SDario Casalinuovo
3659b410c41SDario Casalinuovo	return B_OK;
3669b410c41SDario Casalinuovo}
3679b410c41SDario Casalinuovo
3689b410c41SDario Casalinuovo
3699b410c41SDario Casalinuovostatus_t
3709b410c41SDario CasalinuovoBMediaClientNode::SetBufferGroup(const media_source& source, BBufferGroup* group)
3719b410c41SDario Casalinuovo{
3729b410c41SDario Casalinuovo	CALLED();
3739b410c41SDario Casalinuovo
374d64dd7beSDario Casalinuovo	BMediaOutput* conn = fOwner->_FindOutput(source);
3759b410c41SDario Casalinuovo	if (conn == NULL)
3769b410c41SDario Casalinuovo		return B_MEDIA_BAD_SOURCE;
3779b410c41SDario Casalinuovo
3789b410c41SDario Casalinuovo	if (group == conn->fBufferGroup)
3799b410c41SDario Casalinuovo		return B_OK;
3809b410c41SDario Casalinuovo
3819b410c41SDario Casalinuovo	delete conn->fBufferGroup;
3829b410c41SDario Casalinuovo
3839b410c41SDario Casalinuovo	if (group != NULL) {
3849b410c41SDario Casalinuovo		conn->fBufferGroup = group;
3859b410c41SDario Casalinuovo		return B_OK;
3869b410c41SDario Casalinuovo	}
3879b410c41SDario Casalinuovo
3885854fc4aSDario Casalinuovo	conn->fBufferGroup = new BBufferGroup(conn->BufferSize(), 3);
3899b410c41SDario Casalinuovo	if (conn->fBufferGroup == NULL)
3909b410c41SDario Casalinuovo		return B_NO_MEMORY;
3919b410c41SDario Casalinuovo
3929b410c41SDario Casalinuovo	return conn->fBufferGroup->InitCheck();
3939b410c41SDario Casalinuovo}
3949b410c41SDario Casalinuovo
3959b410c41SDario Casalinuovo
3969b410c41SDario Casalinuovostatus_t
3979b410c41SDario CasalinuovoBMediaClientNode::PrepareToConnect(const media_source& source,
3989b410c41SDario Casalinuovo	const media_destination& dest, media_format* format,
3999b410c41SDario Casalinuovo	media_source* out_source, char *name)
4009b410c41SDario Casalinuovo{
4019b410c41SDario Casalinuovo	CALLED();
4029b410c41SDario Casalinuovo
403d64dd7beSDario Casalinuovo	BMediaOutput* conn = fOwner->_FindOutput(source);
4049b410c41SDario Casalinuovo	if (conn == NULL)
4059b410c41SDario Casalinuovo		return B_MEDIA_BAD_SOURCE;
4069b410c41SDario Casalinuovo
407d64dd7beSDario Casalinuovo	if (conn->_Destination() != media_destination::null)
4089b410c41SDario Casalinuovo		return B_MEDIA_ALREADY_CONNECTED;
4099b410c41SDario Casalinuovo
410300e9786SDario Casalinuovo	if (fOwner->MediaType() != B_MEDIA_UNKNOWN_TYPE
411300e9786SDario Casalinuovo			&& format->type != fOwner->MediaType()) {
4129b410c41SDario Casalinuovo		return B_MEDIA_BAD_FORMAT;
413300e9786SDario Casalinuovo	}
4149b410c41SDario Casalinuovo
415f506f305SDario Casalinuovo	conn->fConnection.destination = dest;
4169ee6577eSDario Casalinuovo
4179ee6577eSDario Casalinuovo	status_t err = conn->PrepareToConnect(format);
4189ee6577eSDario Casalinuovo	if (err != B_OK)
4199ee6577eSDario Casalinuovo		return err;
4209ee6577eSDario Casalinuovo
421d64dd7beSDario Casalinuovo	*out_source = conn->_Source();
4221c15261fSBarrett	strcpy(name, conn->Name());
4239ee6577eSDario Casalinuovo
4249b410c41SDario Casalinuovo	return B_OK;
4259b410c41SDario Casalinuovo}
4269b410c41SDario Casalinuovo
4279b410c41SDario Casalinuovo
4289b410c41SDario Casalinuovovoid
4299b410c41SDario CasalinuovoBMediaClientNode::Connect(status_t status, const media_source& source,
4309b410c41SDario Casalinuovo	const media_destination& dest, const media_format& format,
4319b410c41SDario Casalinuovo	char* name)
4329b410c41SDario Casalinuovo{
4339b410c41SDario Casalinuovo	CALLED();
4349b410c41SDario Casalinuovo
435d64dd7beSDario Casalinuovo	BMediaOutput* conn = fOwner->_FindOutput(source);
4369b410c41SDario Casalinuovo	if (conn == NULL)
4379b410c41SDario Casalinuovo		return;
4389b410c41SDario Casalinuovo
4399391114bSBarrett	// Connection failed, return.
4409391114bSBarrett	if (status != B_OK)
4419b410c41SDario Casalinuovo		return;
4429b410c41SDario Casalinuovo
4439ee6577eSDario Casalinuovo	conn->fConnection.destination = dest;
4446dc7d854SBarrett	conn->fConnection.format = format;
4456dc7d854SBarrett
44665a94fbbSBarrett	// Retrieve the node without using GetNodeFor that's pretty inefficient.
44765a94fbbSBarrett	// Unfortunately we don't have an alternative which doesn't require us
44865a94fbbSBarrett	// to release the cloned node.
44965a94fbbSBarrett	// However, our node will not have flags set. Keep in mind this.
45065a94fbbSBarrett	conn->fConnection.remote_node.node
45165a94fbbSBarrett		= BMediaRoster::CurrentRoster()->NodeIDFor(dest.port);
45265a94fbbSBarrett	conn->fConnection.remote_node.port = dest.port;
45365a94fbbSBarrett
45465a94fbbSBarrett	strcpy(name, conn->Name());
4559b410c41SDario Casalinuovo
4565854fc4aSDario Casalinuovo	// TODO: add correct latency estimate
4575854fc4aSDario Casalinuovo	SetEventLatency(1000);
4585854fc4aSDario Casalinuovo
4595854fc4aSDario Casalinuovo	conn->fBufferGroup = new BBufferGroup(conn->BufferSize(), 3);
4605854fc4aSDario Casalinuovo	if (conn->fBufferGroup == NULL)
4615854fc4aSDario Casalinuovo		TRACE("Can't allocate the buffer group\n");
4629ee6577eSDario Casalinuovo
4639ee6577eSDario Casalinuovo	conn->Connected(format);
4649b410c41SDario Casalinuovo}
4659b410c41SDario Casalinuovo
4669b410c41SDario Casalinuovo
4679b410c41SDario Casalinuovovoid
4689b410c41SDario CasalinuovoBMediaClientNode::Disconnect(const media_source& source,
4699b410c41SDario Casalinuovo	const media_destination& dest)
4709b410c41SDario Casalinuovo{
4719b410c41SDario Casalinuovo	CALLED();
4729b410c41SDario Casalinuovo
473d64dd7beSDario Casalinuovo	BMediaOutput* conn = fOwner->_FindOutput(source);
4749b410c41SDario Casalinuovo	if (conn == NULL)
4759b410c41SDario Casalinuovo		return;
4769b410c41SDario Casalinuovo
4776072c6f1SBarrett	if (conn->_Destination() == dest) {
4786072c6f1SBarrett		// Cleanup the connection
4796072c6f1SBarrett		delete conn->fBufferGroup;
4806072c6f1SBarrett		conn->fBufferGroup = NULL;
4819391114bSBarrett
4826072c6f1SBarrett		conn->fConnection.destination = media_destination::null;
4836072c6f1SBarrett		conn->fConnection.format = media_format();
4846072c6f1SBarrett
4856072c6f1SBarrett		conn->fConnection.remote_node.node = -1;
4866072c6f1SBarrett		conn->fConnection.remote_node.port = -1;
4876072c6f1SBarrett
4886072c6f1SBarrett		conn->Disconnected();
4896072c6f1SBarrett	}
4909b410c41SDario Casalinuovo}
4919b410c41SDario Casalinuovo
4929b410c41SDario Casalinuovo
4939b410c41SDario Casalinuovovoid
4949b410c41SDario CasalinuovoBMediaClientNode::EnableOutput(const media_source& source,
4959b410c41SDario Casalinuovo	bool enabled, int32* _deprecated_)
4969b410c41SDario Casalinuovo{
4979b410c41SDario Casalinuovo	CALLED();
4989b410c41SDario Casalinuovo
499d64dd7beSDario Casalinuovo	BMediaOutput* conn = fOwner->_FindOutput(source);
5002c9fa0f2SDario Casalinuovo	if (conn != NULL)
501befa252fSBarrett		conn->_SetEnabled(enabled);
5029b410c41SDario Casalinuovo}
5039b410c41SDario Casalinuovo
5049b410c41SDario Casalinuovo
5059b410c41SDario Casalinuovostatus_t
5069b410c41SDario CasalinuovoBMediaClientNode::GetLatency(bigtime_t* outLatency)
5079b410c41SDario Casalinuovo{
5089b410c41SDario Casalinuovo	CALLED();
5099b410c41SDario Casalinuovo
510d717df83SBarrett	return BBufferProducer::GetLatency(outLatency);
5119b410c41SDario Casalinuovo}
5129b410c41SDario Casalinuovo
5139b410c41SDario Casalinuovo
5149b410c41SDario Casalinuovovoid
5159b410c41SDario CasalinuovoBMediaClientNode::LatencyChanged(const media_source& source,
5169b410c41SDario Casalinuovo	const media_destination& dest, bigtime_t latency, uint32 flags)
5179b410c41SDario Casalinuovo{
5189b410c41SDario Casalinuovo	CALLED();
5199b410c41SDario Casalinuovo}
5209b410c41SDario Casalinuovo
5219b410c41SDario Casalinuovo
5229b410c41SDario Casalinuovovoid
5239b410c41SDario CasalinuovoBMediaClientNode::ProducerDataStatus(const media_destination& dest,
5249b410c41SDario Casalinuovo	int32 status, bigtime_t when)
5259b410c41SDario Casalinuovo{
5269b410c41SDario Casalinuovo	CALLED();
5279b410c41SDario Casalinuovo}
5289b410c41SDario Casalinuovo
5299b410c41SDario Casalinuovo
5309b410c41SDario Casalinuovovoid
5319b410c41SDario CasalinuovoBMediaClientNode::HandleEvent(const media_timed_event* event,
5329b410c41SDario Casalinuovo	bigtime_t late, bool realTimeEvent)
5339b410c41SDario Casalinuovo{
5349b410c41SDario Casalinuovo	CALLED();
5359b410c41SDario Casalinuovo
5369b410c41SDario Casalinuovo	switch (event->type) {
5379b410c41SDario Casalinuovo		// This event is used for inputs which consumes buffers
5382c9fa0f2SDario Casalinuovo		// or binded connections which also send them to an output.
5399b410c41SDario Casalinuovo		case BTimedEventQueue::B_HANDLE_BUFFER:
5409b410c41SDario Casalinuovo			_HandleBuffer((BBuffer*)event->pointer);
5419b410c41SDario Casalinuovo			break;
5429b410c41SDario Casalinuovo
5439b410c41SDario Casalinuovo		// This is used for connections which produce buffers only.
5449b410c41SDario Casalinuovo		case B_NEW_BUFFER:
5459b410c41SDario Casalinuovo			_ProduceNewBuffer(event, late);
5469b410c41SDario Casalinuovo			break;
5479b410c41SDario Casalinuovo
5489b410c41SDario Casalinuovo		case BTimedEventQueue::B_START:
5499b410c41SDario Casalinuovo		{
5509b410c41SDario Casalinuovo			if (RunState() != B_STARTED)
551ecb39585SDario Casalinuovo				fOwner->HandleStart(event->event_time);
5522c9fa0f2SDario Casalinuovo
553fdfd8a50SDario Casalinuovo			fStartTime = event->event_time;
554fdfd8a50SDario Casalinuovo
5552c9fa0f2SDario Casalinuovo			_ScheduleConnections(event->event_time);
5569b410c41SDario Casalinuovo			break;
5579b410c41SDario Casalinuovo		}
5589b410c41SDario Casalinuovo
5599b410c41SDario Casalinuovo		case BTimedEventQueue::B_STOP:
560ecb39585SDario Casalinuovo		{
561ecb39585SDario Casalinuovo			fOwner->HandleStop(event->event_time);
562ecb39585SDario Casalinuovo
563ecb39585SDario Casalinuovo			EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true,
564ecb39585SDario Casalinuovo				BTimedEventQueue::B_HANDLE_BUFFER);
5659b410c41SDario Casalinuovo			break;
566ecb39585SDario Casalinuovo		}
5679b410c41SDario Casalinuovo
5689b410c41SDario Casalinuovo		case BTimedEventQueue::B_SEEK:
569ecb39585SDario Casalinuovo			fOwner->HandleSeek(event->event_time, event->bigdata);
5709b410c41SDario Casalinuovo			break;
5719b410c41SDario Casalinuovo
5729b410c41SDario Casalinuovo		case BTimedEventQueue::B_WARP:
573d64dd7beSDario Casalinuovo			// NOTE: We have no need to handle it
5749b410c41SDario Casalinuovo			break;
5759b410c41SDario Casalinuovo	}
5769b410c41SDario Casalinuovo}
5779b410c41SDario Casalinuovo
5789b410c41SDario Casalinuovo
5799b410c41SDario CasalinuovoBMediaClientNode::~BMediaClientNode()
5809b410c41SDario Casalinuovo{
5819b410c41SDario Casalinuovo	CALLED();
5829b410c41SDario Casalinuovo
5839b410c41SDario Casalinuovo	Quit();
5849b410c41SDario Casalinuovo}
5859b410c41SDario Casalinuovo
5869b410c41SDario Casalinuovo
5872c9fa0f2SDario Casalinuovovoid
5882c9fa0f2SDario CasalinuovoBMediaClientNode::_ScheduleConnections(bigtime_t eventTime)
5892c9fa0f2SDario Casalinuovo{
5902c9fa0f2SDario Casalinuovo	for (int32 i = 0; i < fOwner->CountOutputs(); i++) {
5912c9fa0f2SDario Casalinuovo		BMediaOutput* output = fOwner->OutputAt(i);
5922c9fa0f2SDario Casalinuovo
5932c9fa0f2SDario Casalinuovo		if (output->HasBinding())
5942c9fa0f2SDario Casalinuovo			continue;
5952c9fa0f2SDario Casalinuovo
5962c9fa0f2SDario Casalinuovo		media_timed_event firstBufferEvent(eventTime,
5972c9fa0f2SDario Casalinuovo			B_NEW_BUFFER);
5982c9fa0f2SDario Casalinuovo
5992c9fa0f2SDario Casalinuovo		output->fFramesSent = 0;
6002c9fa0f2SDario Casalinuovo
6012c9fa0f2SDario Casalinuovo		firstBufferEvent.pointer = (void*) output;
6022c9fa0f2SDario Casalinuovo		EventQueue()->AddEvent(firstBufferEvent);
6032c9fa0f2SDario Casalinuovo	}
6042c9fa0f2SDario Casalinuovo}
6052c9fa0f2SDario Casalinuovo
6062c9fa0f2SDario Casalinuovo
6079b410c41SDario Casalinuovovoid
6089b410c41SDario CasalinuovoBMediaClientNode::_HandleBuffer(BBuffer* buffer)
6099b410c41SDario Casalinuovo{
6109b410c41SDario Casalinuovo	CALLED();
6119b410c41SDario Casalinuovo
6129b410c41SDario Casalinuovo	media_destination dest;
6139b410c41SDario Casalinuovo	dest.id = buffer->Header()->destination;
614d64dd7beSDario Casalinuovo	BMediaInput* conn = fOwner->_FindInput(dest);
6159b410c41SDario Casalinuovo
6169b410c41SDario Casalinuovo	if (conn != NULL)
6175854fc4aSDario Casalinuovo		conn->HandleBuffer(buffer);
6182c9fa0f2SDario Casalinuovo
6192c9fa0f2SDario Casalinuovo	// TODO: Investigate system level latency logging
6202c9fa0f2SDario Casalinuovo
6212c9fa0f2SDario Casalinuovo	if (conn->HasBinding()) {
6222c9fa0f2SDario Casalinuovo		BMediaOutput* output = dynamic_cast<BMediaOutput*>(conn->Binding());
6232c9fa0f2SDario Casalinuovo		output->SendBuffer(buffer);
6242c9fa0f2SDario Casalinuovo	}
6259b410c41SDario Casalinuovo}
6269b410c41SDario Casalinuovo
6279b410c41SDario Casalinuovo
6289b410c41SDario Casalinuovovoid
6299b410c41SDario CasalinuovoBMediaClientNode::_ProduceNewBuffer(const media_timed_event* event,
6309b410c41SDario Casalinuovo	bigtime_t late)
6319b410c41SDario Casalinuovo{
6329b410c41SDario Casalinuovo	CALLED();
6339b410c41SDario Casalinuovo
6349b410c41SDario Casalinuovo	if (RunState() != BMediaEventLooper::B_STARTED)
6359b410c41SDario Casalinuovo		return;
6369b410c41SDario Casalinuovo
6375854fc4aSDario Casalinuovo	// The connection is get through the event
6385854fc4aSDario Casalinuovo	BMediaOutput* output
6395854fc4aSDario Casalinuovo		= dynamic_cast<BMediaOutput*>((BMediaConnection*)event->pointer);
6405854fc4aSDario Casalinuovo	if (output == NULL)
6415854fc4aSDario Casalinuovo		return;
6425854fc4aSDario Casalinuovo
643befa252fSBarrett	if (output->_IsEnabled()) {
6445854fc4aSDario Casalinuovo		BBuffer* buffer = _GetNextBuffer(output, event->event_time);
6455854fc4aSDario Casalinuovo
6465854fc4aSDario Casalinuovo		if (buffer != NULL) {
6475854fc4aSDario Casalinuovo			if (output->SendBuffer(buffer) != B_OK) {
6485854fc4aSDario Casalinuovo				TRACE("BMediaClientNode: Failed to send buffer\n");
6495854fc4aSDario Casalinuovo				// The output failed, let's recycle the buffer
6505854fc4aSDario Casalinuovo				buffer->Recycle();
6515854fc4aSDario Casalinuovo			}
6525854fc4aSDario Casalinuovo		}
6535854fc4aSDario Casalinuovo	}
6545854fc4aSDario Casalinuovo
6555854fc4aSDario Casalinuovo	bigtime_t time = 0;
6566dc7d854SBarrett	media_format format = output->fConnection.format;
6575854fc4aSDario Casalinuovo	if (format.IsAudio()) {
6585854fc4aSDario Casalinuovo		size_t nFrames = format.u.raw_audio.buffer_size
6595854fc4aSDario Casalinuovo			/ ((format.u.raw_audio.format
6605854fc4aSDario Casalinuovo				& media_raw_audio_format::B_AUDIO_SIZE_MASK)
6615854fc4aSDario Casalinuovo			* format.u.raw_audio.channel_count);
6625854fc4aSDario Casalinuovo		output->fFramesSent += nFrames;
6635854fc4aSDario Casalinuovo
6645854fc4aSDario Casalinuovo		time = fStartTime + bigtime_t((1000000LL * output->fFramesSent)
6655854fc4aSDario Casalinuovo			/ (int32)format.u.raw_audio.frame_rate);
6665854fc4aSDario Casalinuovo	}
6675854fc4aSDario Casalinuovo
6685854fc4aSDario Casalinuovo	media_timed_event nextEvent(time, B_NEW_BUFFER);
6695854fc4aSDario Casalinuovo	EventQueue()->AddEvent(nextEvent);
6705854fc4aSDario Casalinuovo}
6715854fc4aSDario Casalinuovo
6725854fc4aSDario Casalinuovo
6735854fc4aSDario CasalinuovoBBuffer*
6745854fc4aSDario CasalinuovoBMediaClientNode::_GetNextBuffer(BMediaOutput* output, bigtime_t eventTime)
6755854fc4aSDario Casalinuovo{
6765854fc4aSDario Casalinuovo	CALLED();
6775854fc4aSDario Casalinuovo
678fcf7cbe7SAdrien Destugues	BBuffer* buffer
679fcf7cbe7SAdrien Destugues		= output->fBufferGroup->RequestBuffer(output->BufferSize(), 0);
680fcf7cbe7SAdrien Destugues	if (buffer == NULL) {
6815854fc4aSDario Casalinuovo		TRACE("MediaClientNode:::_GetNextBuffer: Failed to get the buffer\n");
6825854fc4aSDario Casalinuovo		return NULL;
6835854fc4aSDario Casalinuovo	}
6845854fc4aSDario Casalinuovo
6855854fc4aSDario Casalinuovo	media_header* header = buffer->Header();
6866dc7d854SBarrett	header->type = output->fConnection.format.type;
6875854fc4aSDario Casalinuovo	header->size_used = output->BufferSize();
6885854fc4aSDario Casalinuovo	header->time_source = TimeSource()->ID();
6895854fc4aSDario Casalinuovo	header->start_time = eventTime;
6909b410c41SDario Casalinuovo
6915854fc4aSDario Casalinuovo	return buffer;
6929b410c41SDario Casalinuovo}
693