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