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