xref: /haiku/src/tests/kits/media/nodetest/ProducerNode.cpp (revision 508f54795f39c3e7552d87c95aae9dd8ec6f505b)
1 #include "ProducerNode.h"
2 
3 #include <string.h>
4 
5 #include <Buffer.h>
6 #include <BufferGroup.h>
7 #include <TimeSource.h>
8 
9 #include "misc.h"
10 
11 
12 #define DELAY 2000000
13 
14 
15 ProducerNode::ProducerNode()
16 	:
17 	BBufferProducer(B_MEDIA_RAW_AUDIO),
18 	BMediaEventLooper(),
19 	BMediaNode("ProducerNode"),
20 	mBufferGroup(0),
21 	mBufferProducerSem(-1),
22 	mBufferProducer(-1),
23 	mOutputEnabled(false)
24 {
25 	out("ProducerNode::ProducerNode\n");
26 	mBufferGroup = new BBufferGroup(4096,3);
27 }
28 
29 
30 ProducerNode::~ProducerNode()
31 {
32 	out("ProducerNode::~ProducerNode\n");
33 	Quit();
34 	delete mBufferGroup;
35 }
36 
37 
38 void
39 ProducerNode::NodeRegistered()
40 {
41 	out("ProducerNode::NodeRegistered\n");
42 	InitializeOutput();
43 	SetPriority(108);
44 	Run();
45 }
46 
47 
48 status_t
49 ProducerNode::FormatSuggestionRequested(media_type type, int32 quality,
50 	media_format* format)
51 {
52 	out("ProducerNode::FormatSuggestionRequested\n");
53 
54 	if (type != B_MEDIA_RAW_AUDIO)
55 		return B_MEDIA_BAD_FORMAT;
56 
57 	format->u.raw_audio = media_raw_audio_format::wildcard;
58 	format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT;
59 	format->u.raw_audio.channel_count = 1;
60 	format->u.raw_audio.frame_rate = 44100;
61 	format->u.raw_audio.byte_order = (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN;
62 
63 	return B_OK;
64 }
65 
66 
67 status_t
68 ProducerNode::FormatProposal(const media_source& output, media_format* format)
69 {
70 	out("ProducerNode::FormatProposal\n");
71 
72 	if (format == NULL)
73 		return B_BAD_VALUE;
74 
75 	if (output != mOutput.source)
76 		return B_MEDIA_BAD_SOURCE;
77 
78 	return B_OK;
79 }
80 
81 
82 status_t
83 ProducerNode::FormatChangeRequested(const media_source& source,
84 	const media_destination& destination, media_format* _format,
85 	int32* _deprecated_)
86 {
87 	out("ProducerNode::FormatChangeRequested\n");
88 	return B_ERROR;
89 }
90 
91 
92 status_t
93 ProducerNode::GetNextOutput(int32* cookie, media_output* _output)
94 {
95 	out("ProducerNode::GetNextOutput\n");
96 	if (++(*cookie) > 1)
97 		return B_BAD_INDEX;
98 
99 	mOutput.node = Node();
100 	*_output = mOutput;
101 	return B_OK;
102 }
103 
104 
105 status_t
106 ProducerNode::DisposeOutputCookie(int32 cookie)
107 {
108 	out("ProducerNode::DisposeOutputCookie\n");
109 	return B_OK;
110 }
111 
112 
113 /*!	In this function, you should either pass on the group to your upstream guy,
114 	or delete your current group and hang on to this group. Deleting the
115 	previous group (unless you passed it on with the reclaim flag set to false)
116 	is very important, else you will 1) leak memory and 2) block someone who may
117 	want to reclaim the buffers living in that group.
118 */
119 status_t
120 ProducerNode::SetBufferGroup(const media_source& forSource, BBufferGroup* group)
121 {
122 	out("ProducerNode::SetBufferGroup\n");
123 
124 	if (forSource != mOutput.source)
125 		return B_MEDIA_BAD_SOURCE;
126 
127 #if 0
128 	if (mBufferGroup != NULL && mBufferGroup != mOwnBufferGroup) {
129 		// fixme! really delete if it isn't ours ?
130 		trace("deleting buffer group!...\n");
131 		delete mBufferGroup;
132 		trace("done!\n");
133 	}
134 
135 	/* release the previous buffer group */
136 	if (mOwnBufferGroup != NULL) {
137 		delete_own_buffer_group();
138 	}
139 
140 	mBufferGroup = group;
141 
142 	/* allocate new buffer group if necessary */
143 	if (mBufferGroup == NULL) {
144 		create_own_buffer_group();
145 		mBufferGroup = mOwnBufferGroup;
146 	}
147 	return B_OK;
148 #endif
149 
150 	return B_ERROR;
151 }
152 
153 
154 status_t
155 ProducerNode::VideoClippingChanged(const media_source& forSource,
156 	int16 numShorts, int16* clipData, const media_video_display_info& display,
157 	int32* _deprecated_)
158 {
159 	out("ProducerNode::VideoClippingChanged\n");
160 	return B_ERROR;
161 }
162 
163 
164 status_t
165 ProducerNode::GetLatency(bigtime_t* _latency)
166 {
167 	out("ProducerNode::GetLatency\n");
168 	*_latency = 23000;
169 	return B_OK;
170 }
171 
172 
173 status_t
174 ProducerNode::PrepareToConnect(const media_source& what,
175 	const media_destination& where, media_format* format, media_source* _source,
176 	char* _name)
177 {
178 	out("ProducerNode::PrepareToConnect\n");
179 
180 	if (mOutput.source != what)
181 		return B_MEDIA_BAD_SOURCE;
182 
183 	if (mOutput.destination != media_destination::null)
184 		return B_MEDIA_ALREADY_CONNECTED;
185 
186 	if (format == NULL || _source == NULL || _name == NULL)
187 		return B_BAD_VALUE;
188 
189 #if 0
190 	ASSERT(mOutputEnabled == false);
191 
192 	trace("old format:\n");
193 	dump_format(format);
194 
195 	status_t status;
196 
197 	status = specialize_format_to_inputformat(format);
198 	if (status != B_OK)
199 		return status;
200 
201 #endif
202 
203 
204 	*_source = mOutput.source;
205 	strcpy(_name, mOutput.name);
206 	//mOutput.destination = where; //really now? fixme
207 
208 	return B_OK;
209 }
210 
211 
212 void
213 ProducerNode::Connect(status_t error, const media_source& source,
214 	const media_destination& destination, const media_format& format,
215 	char* name)
216 {
217 	out("ProducerNode::Connect\n");
218 
219 	if (error != B_OK) {
220 		InitializeOutput();
221 		return;
222 	}
223 /*
224 	if (mOutput.destination != destination) { //if connected in PrepareToConnect fixme?
225 		trace("error mOutput.destination != destination\n");
226 		return;
227 	}
228 */
229 	mOutput.destination = destination;
230 
231 	if (mOutput.source != source) {
232 		out("error mOutput.source != source\n");
233 		return;
234 	}
235 
236 	strcpy(name, mOutput.name);
237 
238 #if 0
239 	trace("format (final and approved):\n");
240 	dump_format(&format);
241 #endif
242 
243 	mOutputEnabled = true;
244 
245 	return;
246 }
247 
248 
249 void
250 ProducerNode::Disconnect(const media_source& what,
251 	const media_destination& where)
252 {
253 	out("ProducerNode::Disconnect\n");
254 	mOutputEnabled = false;
255 
256 	// unreserve connection
257 	InitializeOutput();
258 }
259 
260 
261 void
262 ProducerNode::LateNoticeReceived(const media_source& what, bigtime_t howMuch,
263 	bigtime_t performanceTime)
264 {
265 	out("ProducerNode::LateNoticeReceived\n");
266 	return;
267 }
268 
269 
270 void
271 ProducerNode::EnableOutput(const media_source& what, bool enabled,
272 	int32* _deprecated_)
273 {
274 	out("ProducerNode::EnableOutput\n");
275 	mOutputEnabled = enabled;
276 	return;
277 }
278 
279 
280 BMediaAddOn*
281 ProducerNode::AddOn(int32* internalID) const
282 {
283 	out("ProducerNode::AddOn\n");
284 	return NULL;
285 }
286 
287 
288 void
289 ProducerNode::HandleEvent(const media_timed_event* event, bigtime_t lateness,
290 	bool realTimeEvent)
291 {
292 	out("ProducerNode::HandleEvent\n");
293 	switch (event->type) {
294 		case BTimedEventQueue::B_HANDLE_BUFFER:
295 			out("B_HANDLE_BUFFER (should not happen)\n");
296 			break;
297 
298 		case BTimedEventQueue::B_PARAMETER:
299 			out("B_PARAMETER\n");
300 			break;
301 
302 		case BTimedEventQueue::B_START:
303 		{
304 			out("B_START\n");
305 			if (mBufferProducer != -1) {
306 				out("already running\n");
307 				break;
308 			}
309 			mBufferProducerSem = create_sem(0, "producer blocking sem");
310 			mBufferProducer = spawn_thread(_bufferproducer, "Buffer Producer",
311 				B_NORMAL_PRIORITY, this);
312 			resume_thread(mBufferProducer);
313 			break;
314 		}
315 
316 		case BTimedEventQueue::B_STOP:
317 		{
318 			out("B_STOP\n");
319 			if (mBufferProducer == -1) {
320 				out("not running\n");
321 				break;
322 			}
323 			status_t err;
324 			delete_sem(mBufferProducerSem);
325 			wait_for_thread(mBufferProducer,&err);
326 			mBufferProducer = -1;
327 			mBufferProducerSem = -1;
328 
329 			// stopping implies not handling any more buffers.  So, we flush
330 			// all pending buffers out of the event queue before returning to
331 			// the event loop.
332 			EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true,
333 				BTimedEventQueue::B_HANDLE_BUFFER);
334 			break;
335 		}
336 
337 		case BTimedEventQueue::B_SEEK:
338 			out("B_SEEK\n");
339 			break;
340 
341 		case BTimedEventQueue::B_WARP:
342 			out("B_WARP\n");
343 			// similarly, time warps aren't meaningful to the logger, so just
344 			// record it and return
345 			//mLogger->Log(LOG_WARP_HANDLED, logMsg);
346 			break;
347 
348 		case BTimedEventQueue::B_DATA_STATUS:
349 			out("B_DATA_STATUS\n");
350 			break;
351 
352 		default:
353 			out("default\n");
354 			break;
355 	}
356 }
357 
358 
359 status_t
360 ProducerNode::HandleMessage(int32 message,const void *data, size_t size)
361 {
362 	out("ProducerNode::HandleMessage %lx\n",message);
363 	if (B_OK == BBufferProducer::HandleMessage(message,data,size))
364 		return B_OK;
365 	if (B_OK == BMediaEventLooper::HandleMessage(message,data,size))
366 		return B_OK;
367 	return BMediaNode::HandleMessage(message,data,size);
368 }
369 
370 
371 void
372 ProducerNode::AdditionalBufferRequested(const media_source& source,
373 	media_buffer_id previousBuffer, bigtime_t previousTime,
374 	const media_seek_tag* previousTag)
375 {
376 	out("ProducerNode::AdditionalBufferRequested\n");
377 	release_sem(mBufferProducerSem);
378 }
379 
380 
381 void
382 ProducerNode::LatencyChanged(const media_source& source,
383 	const media_destination& destination, bigtime_t newLatency, uint32 flags)
384 {
385 	out("ProducerNode::LatencyChanged\n");
386 }
387 
388 
389 void
390 ProducerNode::InitializeOutput()
391 {
392 	out("ConsumerNode::InitializeOutput()\n");
393 	mOutput.source.port = ControlPort();
394 	mOutput.source.id = 0;
395 	mOutput.destination = media_destination::null;
396 	mOutput.node = Node();
397 	mOutput.format.type = B_MEDIA_RAW_AUDIO;
398 	mOutput.format.u.raw_audio = media_raw_audio_format::wildcard;
399 	mOutput.format.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT;
400 	mOutput.format.u.raw_audio.channel_count = 1;
401 	mOutput.format.u.raw_audio.frame_rate = 44100;
402 	mOutput.format.u.raw_audio.byte_order = B_HOST_IS_BENDIAN
403 		? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN;
404 	strcpy(mOutput.name, "this way out");
405 }
406 
407 
408 int32
409 ProducerNode::_bufferproducer(void* arg)
410 {
411 	((ProducerNode*)arg)->BufferProducer();
412 	return 0;
413 }
414 
415 
416 void
417 ProducerNode::BufferProducer()
418 {
419 	// this thread produces one buffer each two seconds,
420 	// and shedules it to be handled one second later than produced
421 	// assuming a realtime timesource
422 
423 	status_t rv;
424 	for (;;) {
425 		rv = acquire_sem_etc(mBufferProducerSem, 1, B_RELATIVE_TIMEOUT, DELAY);
426 		if (rv == B_INTERRUPTED) {
427 			continue;
428 		} else if (rv == B_OK) {
429 			// triggered by AdditionalBufferRequested
430 			release_sem(mBufferProducerSem);
431 		} else if (rv != B_TIMED_OUT) {
432 			// triggered by deleting the semaphore (stop request)
433 			break;
434 		}
435 		if (!mOutputEnabled)
436 			continue;
437 
438 		BBuffer *buffer;
439 //		out("ProducerNode: RequestBuffer\n");
440 		buffer = mBufferGroup->RequestBuffer(2048);
441 		if (!buffer) {
442 		}
443 		buffer->Header()->start_time = TimeSource()->Now() + DELAY / 2;
444 		out("ProducerNode: SendBuffer, sheduled time = %5.4f\n",
445 			buffer->Header()->start_time / 1E6);
446 		rv = SendBuffer(buffer, mOutput.destination);
447 		if (rv != B_OK) {
448 		}
449 	}
450 }
451