1/*
2 * Copyright 2014-2016, Dario Casalinuovo
3 * Copyright 1999, Be Incorporated
4 * All Rights Reserved.
5 * This file may be used under the terms of the Be Sample Code License.
6 */
7
8
9#include "MediaRecorderNode.h"
10
11#include <Buffer.h>
12#include <scheduler.h>
13#include <MediaRoster.h>
14#include <MediaRosterEx.h>
15#include <TimedEventQueue.h>
16#include <TimeSource.h>
17
18#include "MediaDebug.h"
19
20
21BMediaRecorderNode::BMediaRecorderNode(const char* name,
22	BMediaRecorder* recorder, media_type type)
23	:
24	BMediaNode(name),
25	BMediaEventLooper(),
26	BBufferConsumer(type),
27	fRecorder(recorder),
28	fConnectMode(true)
29{
30	CALLED();
31
32	fInput.node = Node();
33	fInput.destination.id = 1;
34	fInput.destination.port = ControlPort();
35
36	fName.SetTo(name);
37
38	BString str(name);
39	str << " Input";
40	strcpy(fInput.name, str.String());
41}
42
43
44BMediaRecorderNode::~BMediaRecorderNode()
45{
46	CALLED();
47}
48
49
50BMediaAddOn*
51BMediaRecorderNode::AddOn(int32* id) const
52{
53	CALLED();
54
55	if (id)
56		*id = -1;
57
58	return NULL;
59}
60
61
62void
63BMediaRecorderNode::NodeRegistered()
64{
65	CALLED();
66	Run();
67}
68
69
70void
71BMediaRecorderNode::SetRunMode(run_mode mode)
72{
73	CALLED();
74
75	int32 priority;
76
77	if (mode == BMediaNode::B_OFFLINE)
78		priority = B_OFFLINE_PROCESSING;
79	else {
80		switch(ConsumerType()) {
81			case B_MEDIA_RAW_AUDIO:
82			case B_MEDIA_ENCODED_AUDIO:
83				priority = B_AUDIO_RECORDING;
84				break;
85
86			case B_MEDIA_RAW_VIDEO:
87			case B_MEDIA_ENCODED_VIDEO:
88				priority = B_VIDEO_RECORDING;
89				break;
90
91			default:
92				priority = B_DEFAULT_MEDIA_PRIORITY;
93		}
94	}
95
96	SetPriority(suggest_thread_priority(priority));
97
98	BMediaNode::SetRunMode(mode);
99}
100
101
102void
103BMediaRecorderNode::SetAcceptedFormat(const media_format& format)
104{
105	CALLED();
106
107	fInput.format = format;
108	fOKFormat = format;
109}
110
111
112const media_format&
113BMediaRecorderNode::AcceptedFormat() const
114{
115	CALLED();
116
117	return fInput.format;
118}
119
120
121void
122BMediaRecorderNode::GetInput(media_input* outInput)
123{
124	CALLED();
125
126	fInput.node = Node();
127	*outInput = fInput;
128}
129
130
131void
132BMediaRecorderNode::SetDataEnabled(bool enabled)
133{
134	CALLED();
135
136	int32 tag;
137
138	SetOutputEnabled(fInput.source,
139		fInput.destination, enabled, NULL, &tag);
140}
141
142
143void
144BMediaRecorderNode::ActivateInternalConnect(bool connectMode)
145{
146	fConnectMode = connectMode;
147}
148
149
150void
151BMediaRecorderNode::HandleEvent(const media_timed_event* event,
152	bigtime_t lateness, bool realTimeEvent)
153{
154	CALLED();
155
156	// we ignore them all!
157}
158
159
160void
161BMediaRecorderNode::Start(bigtime_t performanceTime)
162{
163	CALLED();
164
165	if (fRecorder->fNotifyHook)
166		(*fRecorder->fNotifyHook)(fRecorder->fBufferCookie,
167			BMediaRecorder::B_WILL_START, performanceTime);
168
169	fRecorder->fRunning = true;
170}
171
172
173void
174BMediaRecorderNode::Stop(bigtime_t performanceTime, bool immediate)
175{
176	CALLED();
177
178	if (fRecorder->fNotifyHook)
179		(*fRecorder->fNotifyHook)(fRecorder->fBufferCookie,
180			BMediaRecorder::B_WILL_STOP, performanceTime, immediate);
181
182	fRecorder->fRunning = false;
183}
184
185
186void
187BMediaRecorderNode::Seek(bigtime_t mediaTime, bigtime_t performanceTime)
188{
189	CALLED();
190
191	if (fRecorder->fNotifyHook)
192		(*fRecorder->fNotifyHook)(fRecorder->fBufferCookie,
193			BMediaRecorder::B_WILL_SEEK, performanceTime, mediaTime);
194}
195
196
197void
198BMediaRecorderNode::TimeWarp(bigtime_t realTime, bigtime_t performanceTime)
199{
200	CALLED();
201
202	// Since buffers will come pre-time-stamped, we only need to look
203	// at them, so we can ignore the time warp as a consumer.
204	if (fRecorder->fNotifyHook)
205		(*fRecorder->fNotifyHook)(fRecorder->fBufferCookie,
206			BMediaRecorder::B_WILL_TIMEWARP, realTime, performanceTime);
207}
208
209
210status_t
211BMediaRecorderNode::HandleMessage(int32 message,
212	const void* data, size_t size)
213{
214	CALLED();
215
216	if (BBufferConsumer::HandleMessage(message, data, size) < 0
217		&& BMediaEventLooper::HandleMessage(message, data, size) < 0
218		&& BMediaNode::HandleMessage(message, data, size) < 0) {
219		HandleBadMessage(message, data, size);
220		return B_ERROR;
221	}
222	return B_OK;
223}
224
225
226status_t
227BMediaRecorderNode::AcceptFormat(const media_destination& dest,
228	media_format* format)
229{
230	CALLED();
231
232	if (format_is_compatible(*format, fOKFormat))
233		return B_OK;
234
235	*format = fOKFormat;
236
237	return B_MEDIA_BAD_FORMAT;
238}
239
240
241status_t
242BMediaRecorderNode::GetNextInput(int32* cookie, media_input* outInput)
243{
244	CALLED();
245
246	if (*cookie == 0) {
247		*cookie = -1;
248		*outInput = fInput;
249		return B_OK;
250	}
251
252	return B_BAD_INDEX;
253}
254
255
256void
257BMediaRecorderNode::DisposeInputCookie(int32 cookie)
258{
259	CALLED();
260}
261
262
263void
264BMediaRecorderNode::BufferReceived(BBuffer* buffer)
265{
266	CALLED();
267
268	fRecorder->BufferReceived(buffer->Data(), buffer->SizeUsed(),
269		*buffer->Header());
270
271	buffer->Recycle();
272}
273
274
275void
276BMediaRecorderNode::ProducerDataStatus(
277	const media_destination& forWhom, int32 status,
278	bigtime_t performanceTime)
279{
280	CALLED();
281}
282
283
284status_t
285BMediaRecorderNode::GetLatencyFor(const media_destination& forWhom,
286	bigtime_t* outLatency, media_node_id* outTimesource)
287{
288	CALLED();
289
290	*outLatency = 0;
291	*outTimesource = TimeSource()->ID();
292
293	return B_OK;
294}
295
296
297status_t
298BMediaRecorderNode::Connected(const media_source &producer,
299	const media_destination &where, const media_format &withFormat,
300	media_input* outInput)
301{
302	CALLED();
303
304	fInput.source = producer;
305	fInput.format = withFormat;
306	*outInput = fInput;
307
308	if (fConnectMode == true) {
309		// This is a workaround needed for us to get the node
310		// so that our owner class can do it's operations.
311		media_node node;
312		BMediaRosterEx* roster = MediaRosterEx(BMediaRoster::CurrentRoster());
313		if (roster->GetNodeFor(roster->NodeIDFor(producer.port), &node) != B_OK)
314			return B_MEDIA_BAD_NODE;
315
316		fRecorder->fOutputNode = node;
317		fRecorder->fReleaseOutputNode = true;
318	}
319	fRecorder->SetUpConnection(producer);
320	fRecorder->fConnected = true;
321
322	return B_OK;
323}
324
325
326void
327BMediaRecorderNode::Disconnected(const media_source& producer,
328	const media_destination& where)
329{
330	CALLED();
331
332	fInput.source = media_source::null;
333	// Reset the connection mode
334	fConnectMode = true;
335	fRecorder->fConnected = false;
336	fInput.format = fOKFormat;
337}
338
339
340status_t
341BMediaRecorderNode::FormatChanged(const media_source& producer,
342	const media_destination& consumer, int32 tag,
343	const media_format& format)
344{
345	CALLED();
346
347	if (!format_is_compatible(format, fOKFormat))
348		return B_MEDIA_BAD_FORMAT;
349
350	fInput.format = format;
351
352	return B_OK;
353}
354