2 * Copyright 2002-2010, Haiku.
3 * Distributed under the terms of the MIT License.
11 /*! This is the BBufferProducer used internally by BSoundPlayer.
15 #include "SoundPlayNode.h"
21 #include <TimeSource.h>
22 #include <MediaRoster.h>
26 #define SEND_NEW_BUFFER_EVENT (BTimedEventQueue::B_USER_EVENT + 1)
32 SoundPlayNode::SoundPlayNode(const char* name
, BSoundPlayer
* player
)
35 BBufferProducer(B_MEDIA_RAW_AUDIO
),
45 fOutput
.format
.type
= B_MEDIA_RAW_AUDIO
;
46 fOutput
.format
.u
.raw_audio
= media_multi_audio_format::wildcard
;
50 SoundPlayNode::~SoundPlayNode()
58 SoundPlayNode::IsPlaying()
60 return RunState() == B_STARTED
;
65 SoundPlayNode::CurrentTime()
67 int frameRate
= (int)fOutput
.format
.u
.raw_audio
.frame_rate
;
68 return frameRate
== 0 ? 0
69 : bigtime_t((1000000LL * fFramesSent
) / frameRate
);
73 media_multi_audio_format
74 SoundPlayNode::Format() const
76 return fOutput
.format
.u
.raw_audio
;
80 // #pragma mark - implementation of BMediaNode
84 SoundPlayNode::AddOn(int32
* _internalID
) const
87 // This only gets called if we are in an add-on.
93 SoundPlayNode::Preroll()
96 // TODO: Performance opportunity
97 BMediaNode::Preroll();
102 SoundPlayNode::HandleMessage(int32 message
, const void* data
, size_t size
)
110 SoundPlayNode::NodeRegistered()
114 if (fInitStatus
!= B_OK
) {
115 ReportError(B_NODE_IN_DISTRESS
);
119 SetPriority(B_URGENT_PRIORITY
);
121 fOutput
.format
.type
= B_MEDIA_RAW_AUDIO
;
122 fOutput
.format
.u
.raw_audio
= media_multi_audio_format::wildcard
;
123 fOutput
.destination
= media_destination::null
;
124 fOutput
.source
.port
= ControlPort();
125 fOutput
.source
.id
= 0;
126 fOutput
.node
= Node();
127 strcpy(fOutput
.name
, Name());
134 SoundPlayNode::RequestCompleted(const media_request_info
& info
)
142 SoundPlayNode::SetTimeSource(BTimeSource
* timeSource
)
145 BMediaNode::SetTimeSource(timeSource
);
150 SoundPlayNode::SetRunMode(run_mode mode
)
152 TRACE("SoundPlayNode::SetRunMode mode:%i\n", mode
);
153 BMediaNode::SetRunMode(mode
);
157 // #pragma mark - implementation for BBufferProducer
161 SoundPlayNode::FormatSuggestionRequested(media_type type
, int32
/*quality*/,
162 media_format
* format
)
164 // FormatSuggestionRequested() is not necessarily part of the format
165 // negotiation process; it's simply an interrogation -- the caller wants
166 // to see what the node's preferred data format is, given a suggestion by
170 // a wildcard type is okay; but we only support raw audio
171 if (type
!= B_MEDIA_RAW_AUDIO
&& type
!= B_MEDIA_UNKNOWN_TYPE
)
172 return B_MEDIA_BAD_FORMAT
;
174 // this is the format we'll be returning (our preferred format)
175 format
->type
= B_MEDIA_RAW_AUDIO
;
176 format
->u
.raw_audio
= media_multi_audio_format::wildcard
;
183 SoundPlayNode::FormatProposal(const media_source
& output
, media_format
* format
)
185 // FormatProposal() is the first stage in the BMediaRoster::Connect()
186 // process. We hand out a suggested format, with wildcards for any
187 // variations we support.
190 // is this a proposal for our one output?
191 if (output
!= fOutput
.source
) {
192 TRACE("SoundPlayNode::FormatProposal returning B_MEDIA_BAD_SOURCE\n");
193 return B_MEDIA_BAD_SOURCE
;
196 // if wildcard, change it to raw audio
197 if (format
->type
== B_MEDIA_UNKNOWN_TYPE
)
198 format
->type
= B_MEDIA_RAW_AUDIO
;
200 // if not raw audio, we can't support it
201 if (format
->type
!= B_MEDIA_RAW_AUDIO
) {
202 TRACE("SoundPlayNode::FormatProposal returning B_MEDIA_BAD_FORMAT\n");
203 return B_MEDIA_BAD_FORMAT
;
208 string_for_format(*format
, buf
, sizeof(buf
));
209 TRACE("SoundPlayNode::FormatProposal: format %s\n", buf
);
217 SoundPlayNode::FormatChangeRequested(const media_source
& source
,
218 const media_destination
& destination
, media_format
* _format
,
219 int32
* /* deprecated */)
223 // we don't support any other formats, so we just reject any format changes.
229 SoundPlayNode::GetNextOutput(int32
* cookie
, media_output
* _output
)
244 SoundPlayNode::DisposeOutputCookie(int32 cookie
)
247 // do nothing because we don't use the cookie for anything special
253 SoundPlayNode::SetBufferGroup(const media_source
& forSource
,
254 BBufferGroup
* newGroup
)
258 // is this our output?
259 if (forSource
!= fOutput
.source
) {
260 TRACE("SoundPlayNode::SetBufferGroup returning B_MEDIA_BAD_SOURCE\n");
261 return B_MEDIA_BAD_SOURCE
;
264 // Are we being passed the buffer group we're already using?
265 if (newGroup
== fBufferGroup
)
268 // Ahh, someone wants us to use a different buffer group. At this point we
269 // delete the one we are using and use the specified one instead.
270 // If the specified group is NULL, we need to recreate one ourselves, and
271 // use *that*. Note that if we're caching a BBuffer that we requested
272 // earlier, we have to Recycle() that buffer *before* deleting the buffer
273 // group, otherwise we'll deadlock waiting for that buffer to be recycled!
275 // waits for all buffers to recycle
277 if (newGroup
!= NULL
) {
278 // we were given a valid group; just use that one from now on
279 fBufferGroup
= newGroup
;
283 // we were passed a NULL group pointer; that means we construct
284 // our own buffer group to use from now on
285 return AllocateBuffers();
290 SoundPlayNode::GetLatency(bigtime_t
* _latency
)
294 // report our *total* latency: internal plus downstream plus scheduling
295 *_latency
= EventLatency() + SchedulingLatency();
301 SoundPlayNode::PrepareToConnect(const media_source
& what
,
302 const media_destination
& where
, media_format
* format
,
303 media_source
* _source
, char* _name
)
305 // PrepareToConnect() is the second stage of format negotiations that
306 // happens inside BMediaRoster::Connect(). At this point, the consumer's
307 // AcceptFormat() method has been called, and that node has potentially
308 // changed the proposed format. It may also have left wildcards in the
309 // format. PrepareToConnect() *must* fully specialize the format before
313 // is this our output?
314 if (what
!= fOutput
.source
) {
315 TRACE("SoundPlayNode::PrepareToConnect returning "
316 "B_MEDIA_BAD_SOURCE\n");
317 return B_MEDIA_BAD_SOURCE
;
320 // are we already connected?
321 if (fOutput
.destination
!= media_destination::null
)
322 return B_MEDIA_ALREADY_CONNECTED
;
324 // the format may not yet be fully specialized (the consumer might have
325 // passed back some wildcards). Finish specializing it now, and return an
326 // error if we don't support the requested format.
330 string_for_format(*format
, buf
, sizeof(buf
));
331 TRACE("SoundPlayNode::PrepareToConnect: input format %s\n", buf
);
334 // if not raw audio, we can't support it
335 if (format
->type
!= B_MEDIA_UNKNOWN_TYPE
336 && format
->type
!= B_MEDIA_RAW_AUDIO
) {
337 TRACE("SoundPlayNode::PrepareToConnect: non raw format, returning "
338 "B_MEDIA_BAD_FORMAT\n");
339 return B_MEDIA_BAD_FORMAT
;
342 // the haiku mixer might have a hint
343 // for us, so check for it
344 #define FORMAT_USER_DATA_TYPE 0x7294a8f3
345 #define FORMAT_USER_DATA_MAGIC_1 0xc84173bd
346 #define FORMAT_USER_DATA_MAGIC_2 0x4af62b7d
347 uint32 channel_count
= 0;
348 float frame_rate
= 0;
349 if (format
->user_data_type
== FORMAT_USER_DATA_TYPE
350 && *(uint32
*)&format
->user_data
[0] == FORMAT_USER_DATA_MAGIC_1
351 && *(uint32
*)&format
->user_data
[44] == FORMAT_USER_DATA_MAGIC_2
) {
352 channel_count
= *(uint32
*)&format
->user_data
[4];
353 frame_rate
= *(float *)&format
->user_data
[20];
354 TRACE("SoundPlayNode::PrepareToConnect: found mixer info: "
355 "channel_count %" B_PRId32
" , frame_rate %.1f\n", channel_count
, frame_rate
);
358 media_format default_format
;
359 default_format
.type
= B_MEDIA_RAW_AUDIO
;
360 default_format
.u
.raw_audio
.frame_rate
= frame_rate
> 0 ? frame_rate
: 44100;
361 default_format
.u
.raw_audio
.channel_count
= channel_count
> 0
363 default_format
.u
.raw_audio
.format
= media_raw_audio_format::B_AUDIO_FLOAT
;
364 default_format
.u
.raw_audio
.byte_order
= B_MEDIA_HOST_ENDIAN
;
365 default_format
.u
.raw_audio
.buffer_size
= 0;
366 format
->SpecializeTo(&default_format
);
368 if (format
->u
.raw_audio
.buffer_size
== 0) {
369 format
->u
.raw_audio
.buffer_size
370 = BMediaRoster::Roster()->AudioBufferSizeFor(
371 format
->u
.raw_audio
.channel_count
, format
->u
.raw_audio
.format
,
372 format
->u
.raw_audio
.frame_rate
);
376 string_for_format(*format
, buf
, sizeof(buf
));
377 TRACE("SoundPlayNode::PrepareToConnect: output format %s\n", buf
);
380 // Now reserve the connection, and return information about it
381 fOutput
.destination
= where
;
382 fOutput
.format
= *format
;
383 *_source
= fOutput
.source
;
384 strcpy(_name
, Name());
390 SoundPlayNode::Connect(status_t error
, const media_source
& source
,
391 const media_destination
& destination
, const media_format
& format
,
396 // is this our output?
397 if (source
!= fOutput
.source
) {
398 TRACE("SoundPlayNode::Connect returning\n");
402 // If something earlier failed, Connect() might still be called, but with
403 // a non-zero error code. When that happens we simply unreserve the
404 // connection and do nothing else.
406 fOutput
.destination
= media_destination::null
;
407 fOutput
.format
.type
= B_MEDIA_RAW_AUDIO
;
408 fOutput
.format
.u
.raw_audio
= media_multi_audio_format::wildcard
;
412 // Okay, the connection has been confirmed. Record the destination and
413 // format that we agreed on, and report our connection name again.
414 fOutput
.destination
= destination
;
415 fOutput
.format
= format
;
416 strcpy(name
, Name());
418 // Now that we're connected, we can determine our downstream latency.
419 // Do so, then make sure we get our events early enough.
421 FindLatencyFor(fOutput
.destination
, &fLatency
, &id
);
422 TRACE("SoundPlayNode::Connect: downstream latency = %" B_PRId64
"\n",
425 // reset our buffer duration, etc. to avoid later calculations
426 bigtime_t duration
= ((fOutput
.format
.u
.raw_audio
.buffer_size
* 1000000LL)
427 / ((fOutput
.format
.u
.raw_audio
.format
428 & media_raw_audio_format::B_AUDIO_SIZE_MASK
)
429 * fOutput
.format
.u
.raw_audio
.channel_count
))
430 / (int32
)fOutput
.format
.u
.raw_audio
.frame_rate
;
431 SetBufferDuration(duration
);
432 TRACE("SoundPlayNode::Connect: buffer duration is %" B_PRId64
"\n",
435 fInternalLatency
= (3 * BufferDuration()) / 4;
436 TRACE("SoundPlayNode::Connect: using %" B_PRId64
" as internal latency\n",
438 SetEventLatency(fLatency
+ fInternalLatency
);
440 // Set up the buffer group for our connection, as long as nobody handed us
441 // a buffer group (via SetBufferGroup()) prior to this.
442 // That can happen, for example, if the consumer calls SetOutputBuffersFor()
443 // on us from within its Connected() method.
450 SoundPlayNode::Disconnect(const media_source
& what
,
451 const media_destination
& where
)
455 // is this our output?
456 if (what
!= fOutput
.source
) {
457 TRACE("SoundPlayNode::Disconnect returning\n");
461 // Make sure that our connection is the one being disconnected
462 if (where
== fOutput
.destination
&& what
== fOutput
.source
) {
463 fOutput
.destination
= media_destination::null
;
464 fOutput
.format
.type
= B_MEDIA_RAW_AUDIO
;
465 fOutput
.format
.u
.raw_audio
= media_multi_audio_format::wildcard
;
469 fprintf(stderr
, "\tDisconnect() called with wrong source/destination "
470 "(%" B_PRId32
"/%" B_PRId32
"), ours is (%" B_PRId32
"/%" B_PRId32
471 ")\n", what
.id
, where
.id
, fOutput
.source
.id
,
472 fOutput
.destination
.id
);
478 SoundPlayNode::LateNoticeReceived(const media_source
& what
, bigtime_t howMuch
,
479 bigtime_t performanceTime
)
483 TRACE("SoundPlayNode::LateNoticeReceived, %" B_PRId64
" too late at %"
484 B_PRId64
"\n", howMuch
, performanceTime
);
486 // is this our output?
487 if (what
!= fOutput
.source
) {
488 TRACE("SoundPlayNode::LateNoticeReceived returning\n");
492 if (RunMode() != B_DROP_DATA
) {
493 // We're late, and our run mode dictates that we try to produce buffers
494 // earlier in order to catch up. This argues that the downstream nodes are
495 // not properly reporting their latency, but there's not much we can do about
496 // that at the moment, so we try to start producing buffers earlier to
499 fInternalLatency
+= howMuch
;
501 if (fInternalLatency
> 30000) // avoid getting a too high latency
502 fInternalLatency
= 30000;
504 SetEventLatency(fLatency
+ fInternalLatency
);
505 TRACE("SoundPlayNode::LateNoticeReceived: increasing latency to %"
506 B_PRId64
"\n", fLatency
+ fInternalLatency
);
508 // The other run modes dictate various strategies for sacrificing data quality
509 // in the interests of timely data delivery. The way *we* do this is to skip
510 // a buffer, which catches us up in time by one buffer duration.
512 size_t nFrames
= fOutput
.format
.u
.raw_audio
.buffer_size
513 / ((fOutput
.format
.u
.raw_audio
.format
& media_raw_audio_format::B_AUDIO_SIZE_MASK
)
514 * fOutput
.format
.u
.raw_audio
.channel_count
);
516 fFramesSent
+= nFrames
;
518 TRACE("SoundPlayNode::LateNoticeReceived: skipping a buffer to try to catch up\n");
524 SoundPlayNode::EnableOutput(const media_source
& what
, bool enabled
,
525 int32
* /* deprecated */)
529 // If I had more than one output, I'd have to walk my list of output
530 // records to see which one matched the given source, and then
531 // enable/disable that one.
532 // But this node only has one output, so I just make sure the given source
533 // matches, then set the enable state accordingly.
535 // is this our output?
536 if (what
!= fOutput
.source
) {
537 fprintf(stderr
, "SoundPlayNode::EnableOutput returning\n");
541 fOutputEnabled
= enabled
;
546 SoundPlayNode::AdditionalBufferRequested(const media_source
& source
,
547 media_buffer_id previousBuffer
, bigtime_t previousTime
,
548 const media_seek_tag
* previousTag
)
551 // we don't support offline mode
557 SoundPlayNode::LatencyChanged(const media_source
& source
,
558 const media_destination
& destination
, bigtime_t newLatency
, uint32 flags
)
562 TRACE("SoundPlayNode::LatencyChanged: new_latency %" B_PRId64
"\n",
565 // something downstream changed latency, so we need to start producing
566 // buffers earlier (or later) than we were previously. Make sure that the
567 // connection that changed is ours, and adjust to the new downstream
569 if (source
== fOutput
.source
&& destination
== fOutput
.destination
) {
570 fLatency
= newLatency
;
571 SetEventLatency(fLatency
+ fInternalLatency
);
573 TRACE("SoundPlayNode::LatencyChanged: ignored\n");
578 // #pragma mark - implementation for BMediaEventLooper
582 SoundPlayNode::HandleEvent(const media_timed_event
* event
, bigtime_t lateness
,
586 switch (event
->type
) {
587 case BTimedEventQueue::B_START
:
588 HandleStart(event
,lateness
,realTimeEvent
);
590 case BTimedEventQueue::B_SEEK
:
591 HandleSeek(event
,lateness
,realTimeEvent
);
593 case BTimedEventQueue::B_WARP
:
594 HandleWarp(event
,lateness
,realTimeEvent
);
596 case BTimedEventQueue::B_STOP
:
597 HandleStop(event
,lateness
,realTimeEvent
);
599 case BTimedEventQueue::B_HANDLE_BUFFER
:
600 // we don't get any buffers
602 case SEND_NEW_BUFFER_EVENT
:
603 if (RunState() == BMediaEventLooper::B_STARTED
)
604 SendNewBuffer(event
, lateness
, realTimeEvent
);
606 case BTimedEventQueue::B_DATA_STATUS
:
607 HandleDataStatus(event
,lateness
,realTimeEvent
);
609 case BTimedEventQueue::B_PARAMETER
:
610 HandleParameter(event
,lateness
,realTimeEvent
);
613 fprintf(stderr
," unknown event type: %" B_PRId32
"\n", event
->type
);
619 // #pragma mark - protected methods
622 // how should we handle late buffers? drop them?
623 // notify the producer?
625 SoundPlayNode::SendNewBuffer(const media_timed_event
* event
,
626 bigtime_t lateness
, bool realTimeEvent
)
629 // TRACE("latency = %12Ld, event = %12Ld, sched = %5Ld, arrive at %12Ld, now %12Ld, current lateness %12Ld\n", EventLatency() + SchedulingLatency(), EventLatency(), SchedulingLatency(), event->event_time, TimeSource()->Now(), lateness);
631 // make sure we're both started *and* connected before delivering a buffer
632 if (RunState() != BMediaEventLooper::B_STARTED
633 || fOutput
.destination
== media_destination::null
)
636 // The event->event_time is the time at which the buffer we are preparing
637 // here should arrive at it's destination. The MediaEventLooper should have
638 // scheduled us early enough (based on EventLatency() and the
639 // SchedulingLatency()) to make this possible.
640 // lateness is independent of EventLatency()!
642 if (lateness
> (BufferDuration() / 3) ) {
643 TRACE("SoundPlayNode::SendNewBuffer, event scheduled much too late, "
644 "lateness is %" B_PRId64
"\n", lateness
);
647 // skip buffer creation if output not enabled
648 if (fOutputEnabled
) {
650 // Get the next buffer of data
651 BBuffer
* buffer
= FillNextBuffer(event
->event_time
);
655 // If we are ready way too early, decrase internal latency
657 bigtime_t how_early = event->event_time - TimeSource()->Now() - fLatency - fInternalLatency;
658 if (how_early > 5000) {
660 TRACE("SoundPlayNode::SendNewBuffer, event scheduled too early, how_early is %Ld\n", how_early);
662 if (fTooEarlyCount++ == 5) {
663 fInternalLatency -= how_early;
664 if (fInternalLatency < 500)
665 fInternalLatency = 500;
666 TRACE("SoundPlayNode::SendNewBuffer setting internal latency to %Ld\n", fInternalLatency);
667 SetEventLatency(fLatency + fInternalLatency);
672 // send the buffer downstream if and only if output is enabled
673 if (SendBuffer(buffer
, fOutput
.source
, fOutput
.destination
)
675 // we need to recycle the buffer
676 // if the call to SendBuffer() fails
677 TRACE("SoundPlayNode::SendNewBuffer: Buffer sending "
684 // track how much media we've delivered so far
685 size_t nFrames
= fOutput
.format
.u
.raw_audio
.buffer_size
686 / ((fOutput
.format
.u
.raw_audio
.format
687 & media_raw_audio_format::B_AUDIO_SIZE_MASK
)
688 * fOutput
.format
.u
.raw_audio
.channel_count
);
689 fFramesSent
+= nFrames
;
691 // The buffer is on its way; now schedule the next one to go
692 // nextEvent is the time at which the buffer should arrive at it's
694 bigtime_t nextEvent
= fStartTime
+ bigtime_t((1000000LL * fFramesSent
)
695 / (int32
)fOutput
.format
.u
.raw_audio
.frame_rate
);
696 media_timed_event
nextBufferEvent(nextEvent
, SEND_NEW_BUFFER_EVENT
);
697 EventQueue()->AddEvent(nextBufferEvent
);
704 SoundPlayNode::HandleDataStatus(const media_timed_event
* event
,
705 bigtime_t lateness
, bool realTimeEvent
)
707 TRACE("SoundPlayNode::HandleDataStatus status: %" B_PRId32
", lateness: %"
708 B_PRId64
"\n", event
->data
, lateness
);
710 switch (event
->data
) {
711 case B_DATA_NOT_AVAILABLE
:
713 case B_DATA_AVAILABLE
:
715 case B_PRODUCER_STOPPED
:
725 SoundPlayNode::HandleStart(const media_timed_event
* event
, bigtime_t lateness
,
729 // don't do anything if we're already running
730 if (RunState() != B_STARTED
) {
731 // We want to start sending buffers now, so we set up the buffer-sending
732 // bookkeeping and fire off the first "produce a buffer" event.
735 fStartTime
= event
->event_time
;
736 media_timed_event
firstBufferEvent(event
->event_time
,
737 SEND_NEW_BUFFER_EVENT
);
739 // Alternatively, we could call HandleEvent() directly with this event,
740 // to avoid a trip through the event queue, like this:
742 // this->HandleEvent(&firstBufferEvent, 0, false);
744 EventQueue()->AddEvent(firstBufferEvent
);
751 SoundPlayNode::HandleSeek(const media_timed_event
* event
, bigtime_t lateness
,
755 TRACE("SoundPlayNode::HandleSeek(t=%" B_PRId64
", d=%" B_PRId32
", bd=%"
756 B_PRId64
")\n", event
->event_time
, event
->data
, event
->bigdata
);
762 SoundPlayNode::HandleWarp(const media_timed_event
* event
, bigtime_t lateness
,
771 SoundPlayNode::HandleStop(const media_timed_event
* event
, bigtime_t lateness
,
775 // flush the queue so downstreamers don't get any more
776 EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS
, true,
777 SEND_NEW_BUFFER_EVENT
);
784 SoundPlayNode::HandleParameter(const media_timed_event
* event
,
785 bigtime_t lateness
, bool realTimeEvent
)
793 SoundPlayNode::AllocateBuffers()
797 // allocate enough buffers to span our downstream latency, plus one
798 size_t size
= fOutput
.format
.u
.raw_audio
.buffer_size
;
799 int32 count
= int32(fLatency
/ BufferDuration() + 1 + 1);
801 TRACE("SoundPlayNode::AllocateBuffers: latency = %" B_PRId64
", buffer "
802 "duration = %" B_PRId64
", count %" B_PRId32
"\n", fLatency
,
803 BufferDuration(), count
);
808 TRACE("SoundPlayNode::AllocateBuffers: creating group of %" B_PRId32
809 " buffers, size = %" B_PRIuSIZE
"\n", count
, size
);
811 fBufferGroup
= new BBufferGroup(size
, count
);
812 if (fBufferGroup
->InitCheck() != B_OK
) {
813 ERROR("SoundPlayNode::AllocateBuffers: BufferGroup::InitCheck() "
817 return fBufferGroup
->InitCheck();
822 SoundPlayNode::FillNextBuffer(bigtime_t eventTime
)
826 // get a buffer from our buffer group
827 BBuffer
* buffer
= fBufferGroup
->RequestBuffer(
828 fOutput
.format
.u
.raw_audio
.buffer_size
, BufferDuration() / 2);
830 // If we fail to get a buffer (for example, if the request times out), we
831 // skip this buffer and go on to the next, to avoid locking up the control
833 if (buffer
== NULL
) {
834 ERROR("SoundPlayNode::FillNextBuffer: RequestBuffer failed\n");
838 if (fPlayer
->HasData()) {
839 fPlayer
->PlayBuffer(buffer
->Data(),
840 fOutput
.format
.u
.raw_audio
.buffer_size
, fOutput
.format
.u
.raw_audio
);
842 memset(buffer
->Data(), 0, fOutput
.format
.u
.raw_audio
.buffer_size
);
844 // fill in the buffer header
845 media_header
* header
= buffer
->Header();
846 header
->type
= B_MEDIA_RAW_AUDIO
;
847 header
->size_used
= fOutput
.format
.u
.raw_audio
.buffer_size
;
848 header
->time_source
= TimeSource()->ID();
849 header
->start_time
= eventTime
;
855 } // namespace BPrivate