headers/bsd: Add sys/queue.h.
[haiku.git] / src / kits / media / MediaRecorder.cpp
blob8278900833d28fe00816b4dc699f54ccb9154355
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 */
10 #include <MediaRecorder.h>
12 #include <MediaAddOn.h>
13 #include <MediaRoster.h>
14 #include <TimeSource.h>
16 #include "MediaDebug.h"
17 #include "MediaRecorderNode.h"
20 BMediaRecorder::BMediaRecorder(const char* name, media_type type)
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)
31 CALLED();
33 BMediaRoster::Roster(&fInitErr);
35 if (fInitErr == B_OK) {
36 fNode = new(std::nothrow) BMediaRecorderNode(name, this, type);
37 if (fNode == NULL)
38 fInitErr = B_NO_MEMORY;
40 fInitErr = BMediaRoster::CurrentRoster()->RegisterNode(fNode);
45 BMediaRecorder::~BMediaRecorder()
47 CALLED();
49 if (fNode != NULL) {
50 Stop();
51 Disconnect();
52 fNode->Release();
57 status_t
58 BMediaRecorder::InitCheck() const
60 CALLED();
62 return fInitErr;
66 void
67 BMediaRecorder::SetAcceptedFormat(const media_format& format)
69 CALLED();
71 fNode->SetAcceptedFormat(format);
75 const media_format&
76 BMediaRecorder::AcceptedFormat() const
78 CALLED();
80 return fNode->AcceptedFormat();
84 status_t
85 BMediaRecorder::SetHooks(ProcessFunc recordFunc, NotifyFunc notifyFunc,
86 void* cookie)
88 CALLED();
90 fRecordHook = recordFunc;
91 fNotifyHook = notifyFunc;
92 fBufferCookie = cookie;
94 return B_OK;
98 void
99 BMediaRecorder::BufferReceived(void* buffer, size_t size,
100 const media_header& header)
102 CALLED();
104 if (fRecordHook) {
105 (*fRecordHook)(fBufferCookie, header.start_time,
106 buffer, size, Format());
111 status_t
112 BMediaRecorder::Connect(const media_format& format)
114 CALLED();
116 if (fInitErr != B_OK)
117 return fInitErr;
119 if (fConnected)
120 return B_MEDIA_ALREADY_CONNECTED;
122 status_t err = B_OK;
123 media_node node;
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;
139 if (err != B_OK)
140 return err;
142 fReleaseOutputNode = true;
144 err = _Connect(node, NULL, format);
146 if (err != B_OK) {
147 BMediaRoster::Roster()->ReleaseNode(node);
148 fReleaseOutputNode = false;
151 return err;
155 status_t
156 BMediaRecorder::Connect(const dormant_node_info& dormantNode,
157 const media_format& format)
159 CALLED();
161 if (fInitErr != B_OK)
162 return fInitErr;
164 if (fConnected)
165 return B_MEDIA_ALREADY_CONNECTED;
167 media_node node;
168 status_t err = BMediaRoster::Roster()->InstantiateDormantNode(dormantNode,
169 &node, B_FLAVOR_IS_GLOBAL);
171 if (err != B_OK)
172 return err;
174 fReleaseOutputNode = true;
176 err = _Connect(node, NULL, format);
178 if (err != B_OK) {
179 BMediaRoster::Roster()->ReleaseNode(node);
180 fReleaseOutputNode = false;
183 return err;
187 status_t
188 BMediaRecorder::Connect(const media_node& node,
189 const media_output* output, const media_format* format)
191 CALLED();
193 if (fInitErr != B_OK)
194 return fInitErr;
196 if (fConnected)
197 return B_MEDIA_ALREADY_CONNECTED;
199 if (format == NULL && output != NULL)
200 format = &output->format;
202 return _Connect(node, output, *format);
206 status_t
207 BMediaRecorder::Disconnect()
209 CALLED();
211 status_t err = B_OK;
213 if (fInitErr != B_OK)
214 return fInitErr;
216 if (!fConnected)
217 return B_MEDIA_NOT_CONNECTED;
219 if (!fNode)
220 return B_ERROR;
222 if (fRunning)
223 err = Stop();
225 if (err != B_OK)
226 return err;
228 media_input ourInput;
229 fNode->GetInput(&ourInput);
231 // do the disconnect
232 err = BMediaRoster::CurrentRoster()->Disconnect(
233 fOutputNode.node, fOutputSource,
234 fNode->Node().node, ourInput.destination);
236 if (fReleaseOutputNode) {
237 BMediaRoster::Roster()->ReleaseNode(fOutputNode);
238 fReleaseOutputNode = false;
241 fConnected = false;
242 fRunning = false;
244 return err;
248 status_t
249 BMediaRecorder::Start(bool force)
251 CALLED();
253 if (fInitErr != B_OK)
254 return fInitErr;
256 if (!fConnected)
257 return B_MEDIA_NOT_CONNECTED;
259 if (fRunning && !force)
260 return EALREADY;
262 if (!fNode)
263 return B_ERROR;
265 // start node here
266 status_t err = B_OK;
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());
275 // then un-mute it
276 if (err == B_OK) {
277 fNode->SetDataEnabled(true);
278 fRunning = true;
279 } else
280 fRunning = false;
282 return err;
286 status_t
287 BMediaRecorder::Stop(bool force)
289 CALLED();
291 if (fInitErr != B_OK)
292 return fInitErr;
294 if (!fRunning && !force)
295 return EALREADY;
297 if (!fNode)
298 return B_ERROR;
300 // should have the Node mute the output here
301 fNode->SetDataEnabled(false);
303 fRunning = false;
305 return BMediaRoster::CurrentRoster()->StopNode(fNode->Node(), 0);
309 bool
310 BMediaRecorder::IsRunning() const
312 CALLED();
314 return fRunning;
318 bool
319 BMediaRecorder::IsConnected() const
321 CALLED();
323 return fConnected;
327 const media_source&
328 BMediaRecorder::MediaSource() const
330 CALLED();
332 return fOutputSource;
336 const media_input&
337 BMediaRecorder::MediaInput() const
339 CALLED();
341 media_input* input = NULL;
342 fNode->GetInput(input);
343 return *input;
347 const media_format&
348 BMediaRecorder::Format() const
350 CALLED();
352 return fNode->AcceptedFormat();
356 status_t
357 BMediaRecorder::SetUpConnection(media_source outputSource)
359 fOutputSource = outputSource;
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);
368 // Set time source
369 return BMediaRoster::Roster()->SetTimeSourceFor(fNode->Node().node,
370 timeSource.node);
374 status_t
375 BMediaRecorder::_Connect(const media_node& node,
376 const media_output* output, const media_format& format)
378 CALLED();
380 status_t err = B_OK;
381 media_format ourFormat = format;
382 media_output ourOutput;
384 if (fNode == NULL)
385 return B_ERROR;
387 fNode->SetAcceptedFormat(ourFormat);
389 fOutputNode = node;
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;
398 err = BMediaRoster::Roster()->GetFreeOutputsFor(fOutputNode,
399 outputs, count, &count, ourFormat.type);
401 if (err != B_OK)
402 return err;
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;
413 if (ourOutput.source == media_source::null)
414 return B_MEDIA_BAD_SOURCE;
416 // Find our Node's free input
417 media_input ourInput;
418 fNode->GetInput(&ourInput);
420 // Acknowledge the node that we already know
421 // who is our producer node.
422 fNode->ActivateInternalConnect(false);
424 return BMediaRoster::CurrentRoster()->Connect(ourOutput.source,
425 ourInput.destination, &ourFormat, &ourOutput, &ourInput,
426 BMediaRoster::B_CONNECT_MUTED);
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() { }