xref: /haiku/src/kits/media/MediaRecorderNode.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
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 
21 BMediaRecorderNode::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 
44 BMediaRecorderNode::~BMediaRecorderNode()
45 {
46 	CALLED();
47 }
48 
49 
50 BMediaAddOn*
51 BMediaRecorderNode::AddOn(int32* id) const
52 {
53 	CALLED();
54 
55 	if (id)
56 		*id = -1;
57 
58 	return NULL;
59 }
60 
61 
62 void
63 BMediaRecorderNode::NodeRegistered()
64 {
65 	CALLED();
66 	Run();
67 }
68 
69 
70 void
71 BMediaRecorderNode::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 
102 void
103 BMediaRecorderNode::SetAcceptedFormat(const media_format& format)
104 {
105 	CALLED();
106 
107 	fInput.format = format;
108 	fOKFormat = format;
109 }
110 
111 
112 const media_format&
113 BMediaRecorderNode::AcceptedFormat() const
114 {
115 	CALLED();
116 
117 	return fInput.format;
118 }
119 
120 
121 void
122 BMediaRecorderNode::GetInput(media_input* outInput)
123 {
124 	CALLED();
125 
126 	fInput.node = Node();
127 	*outInput = fInput;
128 }
129 
130 
131 void
132 BMediaRecorderNode::SetDataEnabled(bool enabled)
133 {
134 	CALLED();
135 
136 	int32 tag;
137 
138 	SetOutputEnabled(fInput.source,
139 		fInput.destination, enabled, NULL, &tag);
140 }
141 
142 
143 void
144 BMediaRecorderNode::ActivateInternalConnect(bool connectMode)
145 {
146 	fConnectMode = connectMode;
147 }
148 
149 
150 void
151 BMediaRecorderNode::HandleEvent(const media_timed_event* event,
152 	bigtime_t lateness, bool realTimeEvent)
153 {
154 	CALLED();
155 
156 	// we ignore them all!
157 }
158 
159 
160 void
161 BMediaRecorderNode::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 
173 void
174 BMediaRecorderNode::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 
186 void
187 BMediaRecorderNode::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 
197 void
198 BMediaRecorderNode::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 
210 status_t
211 BMediaRecorderNode::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 
226 status_t
227 BMediaRecorderNode::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 
241 status_t
242 BMediaRecorderNode::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 
256 void
257 BMediaRecorderNode::DisposeInputCookie(int32 cookie)
258 {
259 	CALLED();
260 }
261 
262 
263 void
264 BMediaRecorderNode::BufferReceived(BBuffer* buffer)
265 {
266 	CALLED();
267 
268 	fRecorder->BufferReceived(buffer->Data(), buffer->SizeUsed(),
269 		*buffer->Header());
270 
271 	buffer->Recycle();
272 }
273 
274 
275 void
276 BMediaRecorderNode::ProducerDataStatus(
277 	const media_destination& forWhom, int32 status,
278 	bigtime_t performanceTime)
279 {
280 	CALLED();
281 }
282 
283 
284 status_t
285 BMediaRecorderNode::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 
297 status_t
298 BMediaRecorderNode::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 
326 void
327 BMediaRecorderNode::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 
340 status_t
341 BMediaRecorderNode::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