1 /* 2 * Copyright 2015, Hamish Morrison <hamishm53@gmail.com> 3 * Copyright 2014, 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 status_t 76 BMediaRecorder::SetHooks(ProcessFunc recordFunc, NotifyFunc notifyFunc, 77 void* cookie) 78 { 79 CALLED(); 80 81 fRecordHook = recordFunc; 82 fNotifyHook = notifyFunc; 83 fBufferCookie = cookie; 84 85 return B_OK; 86 } 87 88 89 void 90 BMediaRecorder::BufferReceived(void* buffer, size_t size, 91 const media_header& header) 92 { 93 CALLED(); 94 95 if (fRecordHook) { 96 (*fRecordHook)(fBufferCookie, header.start_time, 97 buffer, size, Format()); 98 } 99 } 100 101 102 status_t 103 BMediaRecorder::Connect(const media_format& format) 104 { 105 CALLED(); 106 107 if (fInitErr != B_OK) 108 return fInitErr; 109 110 if (fConnected) 111 return B_MEDIA_ALREADY_CONNECTED; 112 113 status_t err = B_OK; 114 media_node node; 115 116 switch (format.type) { 117 // switch on format for default 118 case B_MEDIA_RAW_AUDIO: 119 err = BMediaRoster::Roster()->GetAudioMixer(&node); 120 break; 121 case B_MEDIA_RAW_VIDEO: 122 case B_MEDIA_ENCODED_VIDEO: 123 err = BMediaRoster::Roster()->GetVideoInput(&node); 124 break; 125 // give up? 126 default: 127 return B_MEDIA_BAD_FORMAT; 128 } 129 130 if (err != B_OK) 131 return err; 132 133 fReleaseOutputNode = true; 134 135 err = _Connect(node, NULL, format); 136 137 if (err != B_OK) { 138 BMediaRoster::Roster()->ReleaseNode(node); 139 fReleaseOutputNode = false; 140 } 141 142 return err; 143 } 144 145 146 status_t 147 BMediaRecorder::Connect(const dormant_node_info& dormantNode, 148 const media_format& format) 149 { 150 CALLED(); 151 152 if (fInitErr != B_OK) 153 return fInitErr; 154 155 if (fConnected) 156 return B_MEDIA_ALREADY_CONNECTED; 157 158 media_node node; 159 status_t err = BMediaRoster::Roster()->InstantiateDormantNode(dormantNode, 160 &node, B_FLAVOR_IS_GLOBAL); 161 162 if (err != B_OK) 163 return err; 164 165 fReleaseOutputNode = true; 166 167 err = _Connect(node, NULL, format); 168 169 if (err != B_OK) { 170 BMediaRoster::Roster()->ReleaseNode(node); 171 fReleaseOutputNode = false; 172 } 173 174 return err; 175 } 176 177 178 status_t 179 BMediaRecorder::Connect(const media_node& node, 180 const media_output* output, const media_format* format) 181 { 182 CALLED(); 183 184 if (fInitErr != B_OK) 185 return fInitErr; 186 187 if (fConnected) 188 return B_MEDIA_ALREADY_CONNECTED; 189 190 if (format == NULL && output != NULL) 191 format = &output->format; 192 193 return _Connect(node, output, *format); 194 } 195 196 197 status_t 198 BMediaRecorder::Disconnect() 199 { 200 CALLED(); 201 202 status_t err = B_OK; 203 204 if (fInitErr != B_OK) 205 return fInitErr; 206 207 if (!fConnected) 208 return B_MEDIA_NOT_CONNECTED; 209 210 if (!fNode) 211 return B_ERROR; 212 213 if (fRunning) 214 err = Stop(); 215 216 if (err != B_OK) 217 return err; 218 219 // do the disconnect 220 err = BMediaRoster::CurrentRoster()->Disconnect( 221 fOutputNode.node, fOutput.source, 222 fNode->Node().node, fInput.destination); 223 224 if (fReleaseOutputNode) { 225 BMediaRoster::Roster()->ReleaseNode(fOutputNode); 226 fReleaseOutputNode = false; 227 } 228 229 fConnected = false; 230 fRunning = false; 231 232 return err; 233 } 234 235 236 status_t 237 BMediaRecorder::Start(bool force) 238 { 239 CALLED(); 240 241 if (fInitErr != B_OK) 242 return fInitErr; 243 244 if (!fConnected) 245 return B_MEDIA_NOT_CONNECTED; 246 247 if (fRunning && !force) 248 return EALREADY; 249 250 if (!fNode) 251 return B_ERROR; 252 253 // start node here 254 status_t err = B_OK; 255 256 if ((fOutputNode.kind & B_TIME_SOURCE) != 0) 257 err = BMediaRoster::CurrentRoster()->StartTimeSource( 258 fOutputNode, BTimeSource::RealTime()); 259 else 260 err = BMediaRoster::CurrentRoster()->StartNode( 261 fOutputNode, fNode->TimeSource()->Now()); 262 263 // then un-mute it 264 if (err == B_OK) { 265 fNode->SetDataEnabled(true); 266 fRunning = true; 267 } else 268 fRunning = false; 269 270 return err; 271 } 272 273 274 status_t 275 BMediaRecorder::Stop(bool force) 276 { 277 CALLED(); 278 279 if (fInitErr != B_OK) 280 return fInitErr; 281 282 if (!fRunning && !force) 283 return EALREADY; 284 285 if (!fNode) 286 return B_ERROR; 287 288 // should have the Node mute the output here 289 fNode->SetDataEnabled(false); 290 291 fRunning = false; 292 293 return BMediaRoster::CurrentRoster()->StopNode(fNode->Node(), 0); 294 } 295 296 297 bool 298 BMediaRecorder::IsRunning() const 299 { 300 CALLED(); 301 302 return fRunning; 303 } 304 305 306 bool 307 BMediaRecorder::IsConnected() const 308 { 309 CALLED(); 310 311 return fConnected; 312 } 313 314 315 const media_output& 316 BMediaRecorder::MediaOutput() const 317 { 318 CALLED(); 319 320 return fOutput; 321 } 322 323 324 const media_input& 325 BMediaRecorder::MediaInput() const 326 { 327 CALLED(); 328 329 return fInput; 330 } 331 332 333 const media_format& 334 BMediaRecorder::Format() const 335 { 336 CALLED(); 337 338 return fOutput.format; 339 } 340 341 342 status_t 343 BMediaRecorder::_Connect(const media_node& node, 344 const media_output* output, const media_format& format) 345 { 346 CALLED(); 347 348 status_t err = B_OK; 349 media_format ourFormat = format; 350 media_output ourOutput; 351 352 if (fNode == NULL) 353 return B_ERROR; 354 355 fNode->SetAcceptedFormat(ourFormat); 356 357 fOutputNode = node; 358 359 // figure out the output provided 360 if (output != NULL) { 361 ourOutput = *output; 362 } else if (err == B_OK) { 363 media_output outputs[10]; 364 int32 count = 10; 365 366 err = BMediaRoster::Roster()->GetFreeOutputsFor(fOutputNode, 367 outputs, count, &count, ourFormat.type); 368 369 if (err != B_OK) 370 return err; 371 372 for (int i = 0; i < count; i++) { 373 if (format_is_compatible(outputs[i].format, ourFormat)) { 374 ourOutput = outputs[i]; 375 ourFormat = outputs[i].format; 376 break; 377 } 378 } 379 } 380 381 if (ourOutput.source == media_source::null) 382 return B_MEDIA_BAD_SOURCE; 383 384 // find our Node's free input 385 media_input ourInput; 386 err = fNode->GetInput(&ourInput); 387 if (err != B_OK) 388 return err; 389 390 media_node timeSource; 391 if ((node.kind & B_TIME_SOURCE) != 0) 392 timeSource = node; 393 else 394 BMediaRoster::Roster()->GetTimeSource(&timeSource); 395 396 // set time source 397 err = BMediaRoster::Roster()->SetTimeSourceFor(fNode->Node().node, 398 timeSource.node); 399 400 if (err != B_OK) 401 return err; 402 403 // start the recorder node (it's always running) 404 err = BMediaRoster::CurrentRoster()->StartNode(fOutputNode, 405 fNode->TimeSource()->Now()); 406 407 if (err != B_OK) 408 return err; 409 410 // perform the connection 411 fOutput = ourOutput; 412 fInput = ourInput; 413 414 err = BMediaRoster::CurrentRoster()->Connect(fOutput.source, 415 fInput.destination, &ourFormat, &fOutput, &fInput, 416 BMediaRoster::B_CONNECT_MUTED); 417 418 if (err != B_OK) 419 return err; 420 421 fConnected = true; 422 return B_OK; 423 } 424 425 426 void BMediaRecorder::_ReservedMediaRecorder0() { } 427 void BMediaRecorder::_ReservedMediaRecorder1() { } 428 void BMediaRecorder::_ReservedMediaRecorder2() { } 429 void BMediaRecorder::_ReservedMediaRecorder3() { } 430 void BMediaRecorder::_ReservedMediaRecorder4() { } 431 void BMediaRecorder::_ReservedMediaRecorder5() { } 432 void BMediaRecorder::_ReservedMediaRecorder6() { } 433 void BMediaRecorder::_ReservedMediaRecorder7() { } 434 435