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