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