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