1 /* 2 * Copyright 2015, Hamish Morrison <hamishm53@gmail.com> 3 * Copyright 2014-2016, Dario Casalinuovo 4 * Copyright 1999, Be Incorporated 5 * All Rights Reserved. 6 * This file may be used under the terms of the Be Sample Code License. 7 */ 8 9 10 #include <MediaRecorder.h> 11 12 #include <MediaAddOn.h> 13 #include <MediaRoster.h> 14 #include <TimeSource.h> 15 16 #include "MediaDebug.h" 17 #include "MediaRecorderNode.h" 18 19 20 BMediaRecorder::BMediaRecorder(const char* name, media_type type) 21 : 22 fInitErr(B_OK), 23 fConnected(false), 24 fRunning(false), 25 fReleaseOutputNode(false), 26 fRecordHook(NULL), 27 fNotifyHook(NULL), 28 fNode(NULL), 29 fBufferCookie(NULL) 30 { 31 CALLED(); 32 33 BMediaRoster::Roster(&fInitErr); 34 35 if (fInitErr == B_OK) { 36 fNode = new(std::nothrow) BMediaRecorderNode(name, this, type); 37 if (fNode == NULL) 38 fInitErr = B_NO_MEMORY; 39 40 fInitErr = BMediaRoster::CurrentRoster()->RegisterNode(fNode); 41 } 42 } 43 44 45 BMediaRecorder::~BMediaRecorder() 46 { 47 CALLED(); 48 49 if (fNode != NULL) { 50 Stop(); 51 Disconnect(); 52 fNode->Release(); 53 } 54 } 55 56 57 status_t 58 BMediaRecorder::InitCheck() const 59 { 60 CALLED(); 61 62 return fInitErr; 63 } 64 65 66 void 67 BMediaRecorder::SetAcceptedFormat(const media_format& format) 68 { 69 CALLED(); 70 71 fNode->SetAcceptedFormat(format); 72 } 73 74 75 const media_format& 76 BMediaRecorder::AcceptedFormat() const 77 { 78 CALLED(); 79 80 return fNode->AcceptedFormat(); 81 } 82 83 84 status_t 85 BMediaRecorder::SetHooks(ProcessFunc recordFunc, NotifyFunc notifyFunc, 86 void* cookie) 87 { 88 CALLED(); 89 90 fRecordHook = recordFunc; 91 fNotifyHook = notifyFunc; 92 fBufferCookie = cookie; 93 94 return B_OK; 95 } 96 97 98 void 99 BMediaRecorder::BufferReceived(void* buffer, size_t size, 100 const media_header& header) 101 { 102 CALLED(); 103 104 if (fRecordHook) { 105 (*fRecordHook)(fBufferCookie, header.start_time, 106 buffer, size, Format()); 107 } 108 } 109 110 111 status_t 112 BMediaRecorder::Connect(const media_format& format) 113 { 114 CALLED(); 115 116 if (fInitErr != B_OK) 117 return fInitErr; 118 119 if (fConnected) 120 return B_MEDIA_ALREADY_CONNECTED; 121 122 status_t err = B_OK; 123 media_node node; 124 125 switch (format.type) { 126 // switch on format for default 127 case B_MEDIA_RAW_AUDIO: 128 err = BMediaRoster::Roster()->GetAudioMixer(&node); 129 break; 130 case B_MEDIA_RAW_VIDEO: 131 case B_MEDIA_ENCODED_VIDEO: 132 err = BMediaRoster::Roster()->GetVideoInput(&node); 133 break; 134 // give up? 135 default: 136 return B_MEDIA_BAD_FORMAT; 137 } 138 139 if (err != B_OK) 140 return err; 141 142 fReleaseOutputNode = true; 143 144 err = _Connect(node, NULL, format); 145 146 if (err != B_OK) { 147 BMediaRoster::Roster()->ReleaseNode(node); 148 fReleaseOutputNode = false; 149 } 150 151 return err; 152 } 153 154 155 status_t 156 BMediaRecorder::Connect(const dormant_node_info& dormantNode, 157 const media_format& format) 158 { 159 CALLED(); 160 161 if (fInitErr != B_OK) 162 return fInitErr; 163 164 if (fConnected) 165 return B_MEDIA_ALREADY_CONNECTED; 166 167 media_node node; 168 status_t err = BMediaRoster::Roster()->InstantiateDormantNode(dormantNode, 169 &node, B_FLAVOR_IS_GLOBAL); 170 171 if (err != B_OK) 172 return err; 173 174 fReleaseOutputNode = true; 175 176 err = _Connect(node, NULL, format); 177 178 if (err != B_OK) { 179 BMediaRoster::Roster()->ReleaseNode(node); 180 fReleaseOutputNode = false; 181 } 182 183 return err; 184 } 185 186 187 status_t 188 BMediaRecorder::Connect(const media_node& node, 189 const media_output* output, const media_format* format) 190 { 191 CALLED(); 192 193 if (fInitErr != B_OK) 194 return fInitErr; 195 196 if (fConnected) 197 return B_MEDIA_ALREADY_CONNECTED; 198 199 if (format == NULL && output != NULL) 200 format = &output->format; 201 202 return _Connect(node, output, *format); 203 } 204 205 206 status_t 207 BMediaRecorder::Disconnect() 208 { 209 CALLED(); 210 211 status_t err = B_OK; 212 213 if (fInitErr != B_OK) 214 return fInitErr; 215 216 if (!fConnected) 217 return B_MEDIA_NOT_CONNECTED; 218 219 if (!fNode) 220 return B_ERROR; 221 222 if (fRunning) 223 err = Stop(); 224 225 if (err != B_OK) 226 return err; 227 228 media_input ourInput; 229 fNode->GetInput(&ourInput); 230 231 // do the disconnect 232 err = BMediaRoster::CurrentRoster()->Disconnect( 233 fOutputNode.node, fOutputSource, 234 fNode->Node().node, ourInput.destination); 235 236 if (fReleaseOutputNode) { 237 BMediaRoster::Roster()->ReleaseNode(fOutputNode); 238 fReleaseOutputNode = false; 239 } 240 241 fConnected = false; 242 fRunning = false; 243 244 return err; 245 } 246 247 248 status_t 249 BMediaRecorder::Start(bool force) 250 { 251 CALLED(); 252 253 if (fInitErr != B_OK) 254 return fInitErr; 255 256 if (!fConnected) 257 return B_MEDIA_NOT_CONNECTED; 258 259 if (fRunning && !force) 260 return EALREADY; 261 262 if (!fNode) 263 return B_ERROR; 264 265 // start node here 266 status_t err = B_OK; 267 268 if ((fOutputNode.kind & B_TIME_SOURCE) != 0) 269 err = BMediaRoster::CurrentRoster()->StartTimeSource( 270 fOutputNode, BTimeSource::RealTime()); 271 else 272 err = BMediaRoster::CurrentRoster()->StartNode( 273 fOutputNode, fNode->TimeSource()->Now()); 274 275 // then un-mute it 276 if (err == B_OK) { 277 fNode->SetDataEnabled(true); 278 fRunning = true; 279 } else 280 fRunning = false; 281 282 return err; 283 } 284 285 286 status_t 287 BMediaRecorder::Stop(bool force) 288 { 289 CALLED(); 290 291 if (fInitErr != B_OK) 292 return fInitErr; 293 294 if (!fRunning && !force) 295 return EALREADY; 296 297 if (!fNode) 298 return B_ERROR; 299 300 // should have the Node mute the output here 301 fNode->SetDataEnabled(false); 302 303 fRunning = false; 304 305 return BMediaRoster::CurrentRoster()->StopNode(fNode->Node(), 0); 306 } 307 308 309 bool 310 BMediaRecorder::IsRunning() const 311 { 312 CALLED(); 313 314 return fRunning; 315 } 316 317 318 bool 319 BMediaRecorder::IsConnected() const 320 { 321 CALLED(); 322 323 return fConnected; 324 } 325 326 327 const media_source& 328 BMediaRecorder::MediaSource() const 329 { 330 CALLED(); 331 332 return fOutputSource; 333 } 334 335 336 const media_input& 337 BMediaRecorder::MediaInput() const 338 { 339 CALLED(); 340 341 media_input* input = NULL; 342 fNode->GetInput(input); 343 return *input; 344 } 345 346 347 const media_format& 348 BMediaRecorder::Format() const 349 { 350 CALLED(); 351 352 return fNode->AcceptedFormat(); 353 } 354 355 356 status_t 357 BMediaRecorder::SetUpConnection(media_source outputSource) 358 { 359 fOutputSource = outputSource; 360 361 // Perform the connection 362 media_node timeSource; 363 if ((fOutputNode.kind & B_TIME_SOURCE) != 0) 364 timeSource = fOutputNode; 365 else 366 BMediaRoster::Roster()->GetTimeSource(&timeSource); 367 368 // Set time source 369 return BMediaRoster::Roster()->SetTimeSourceFor(fNode->Node().node, 370 timeSource.node); 371 } 372 373 374 status_t 375 BMediaRecorder::_Connect(const media_node& node, 376 const media_output* output, const media_format& format) 377 { 378 CALLED(); 379 380 status_t err = B_OK; 381 media_format ourFormat = format; 382 media_output ourOutput; 383 384 if (fNode == NULL) 385 return B_ERROR; 386 387 fNode->SetAcceptedFormat(ourFormat); 388 389 fOutputNode = node; 390 391 // Figure out the output provided 392 if (output != NULL) { 393 ourOutput = *output; 394 } else if (err == B_OK) { 395 media_output outputs[10]; 396 int32 count = 10; 397 398 err = BMediaRoster::Roster()->GetFreeOutputsFor(fOutputNode, 399 outputs, count, &count, ourFormat.type); 400 401 if (err != B_OK) 402 return err; 403 404 for (int i = 0; i < count; i++) { 405 if (format_is_compatible(outputs[i].format, ourFormat)) { 406 ourOutput = outputs[i]; 407 ourFormat = outputs[i].format; 408 break; 409 } 410 } 411 } 412 413 if (ourOutput.source == media_source::null) 414 return B_MEDIA_BAD_SOURCE; 415 416 // Find our Node's free input 417 media_input ourInput; 418 fNode->GetInput(&ourInput); 419 420 // Acknowledge the node that we already know 421 // who is our producer node. 422 fNode->ActivateInternalConnect(false); 423 424 return BMediaRoster::CurrentRoster()->Connect(ourOutput.source, 425 ourInput.destination, &ourFormat, &ourOutput, &ourInput, 426 BMediaRoster::B_CONNECT_MUTED); 427 } 428 429 430 void BMediaRecorder::_ReservedMediaRecorder0() { } 431 void BMediaRecorder::_ReservedMediaRecorder1() { } 432 void BMediaRecorder::_ReservedMediaRecorder2() { } 433 void BMediaRecorder::_ReservedMediaRecorder3() { } 434 void BMediaRecorder::_ReservedMediaRecorder4() { } 435 void BMediaRecorder::_ReservedMediaRecorder5() { } 436 void BMediaRecorder::_ReservedMediaRecorder6() { } 437 void BMediaRecorder::_ReservedMediaRecorder7() { } 438 439