<div dir="ltr"><div><div>Hi Ross - <br><br>Thanks again for your help here. I understand what you're saying with using an event trigger for when additional data is available, but I'm having no luck implementing as my C++ is fairly bad. Coming from C# and other higher-level languages is proving to be a bit of a learning curve for me!<br><br></div>I have a very simple circular buffer in my code as RtAudio code (for ASIO input device) calls back my code, and the Live555 code also calls back my code, both at their own regular intervals. Below, I've posted my AudioBufferSource::doGetNextFrame(), in hopes you might be able to provide a more verbose suggestion... I understand if you don't have the time.<br><br>Thanks again!<br><br></div>- James<br><br>void AudioBufferSource::doGetNextFrame() { <br><br> signed availableFrames = fBufferManager->_writeCnt - fBufferManager->_readCnt;<br> while (availableFrames < 64)<br> {<br> availableFrames = fBufferManager->_writeCnt - fBufferManager->_readCnt;<br> }<br><br> fFrameSize = 0;<br><br> if (fLimitNumBytesToStream && fNumBytesToStream < fMaxSize) {<br> fMaxSize = fNumBytesToStream;<br> }<br> if (fPreferredFrameSize < fMaxSize) {<br> fMaxSize = fPreferredFrameSize;<br> }<br><br> unsigned bytesPerSample = (fNumChannels*fBitsPerSample) / 8;<br> if (bytesPerSample == 0) bytesPerSample = 1; // because we can't read less than a byte at a time<br><br> unsigned numberOfPCMFramesToGet = fMaxSize / bytesPerSample;<br> unsigned pcmFramesGotten = fBufferManager->getFrames((int16_t*)fTo, numberOfPCMFramesToGet);<br><br> unsigned numBytesRead = pcmFramesGotten * bytesPerSample;<br> fFrameSize += numBytesRead;<br> fTo += numBytesRead;<br> fMaxSize -= numBytesRead;<br> fNumBytesToStream -= numBytesRead;<br><br> // Set the 'presentation time' and 'duration' of this RTP frame<br> if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) {<br> // This is the first frame, so use the current time:<br> gettimeofday(&fPresentationTime, NULL);<br> }<br> else {<br> // Increment by the play time of the previous RTP frame<br> unsigned uSeconds = fPresentationTime.tv_usec + fLastPlayTime;<br> fPresentationTime.tv_sec += uSeconds / 1000000;<br> fPresentationTime.tv_usec = uSeconds % 1000000;<br> }<br><br> // Remember the play time of this RTP frame<br> fDurationInMicroseconds = fLastPlayTime = (unsigned)((fPlayTimePerSample*fFrameSize) / bytesPerSample);<br><br> // Inform the reader that he has data:<br> // To avoid possible infinite recursion, we need to return to the event loop to do this:<br> nextTask() = envir().taskScheduler().scheduleDelayedTask(0, (TaskFunc*)FramedSource::afterGetting, this);<br>}<br><div><br><br><div><br></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Oct 11, 2014 at 8:14 AM, Ross Finlayson <span dir="ltr"><<a href="mailto:finlayson@live555.com" target="_blank">finlayson@live555.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><span class=""><blockquote type="cite"><div dir="ltr"><div>I see what you mean, and fDurationInMicroseconds is being calculated correctly. For my fragmentation issue, If I don't call afterGetting() then doGetNextFrame() is not ever re-invoked, so the server essentially stops on the first partial read. <br><br>Is there a method or variable I should set to indicate to Live555 that I want to continue accumulating data?</div></div></blockquote><div><br></div></span>Your "doGetNextFrame()" implementation should call "FramedSource::afterGetting()" *only* when you have a complete frame that you want to deliver to the downstream object. If you don't yet have a complete frame, then simply return, without calling "FramedSource::afterGetting()". If you do that, then "doGetNextFrame()" won't get called again in the meantime.</div><div><br></div><div>But, you're probably thinking, if "doGetNextFrame()" simply returns without completing delivery of a frame, and doesn't get called again, then how can I figure out when I later get enough data to deliver? Basically, that has to be an 'event' that gets handled within the event loop. One way to do this is by 'polling' - i.e., by scheduling a periodic delayed task (using "TaskScheduler::scheduleDelayedTask()") that checks whether you have enough data (and then calls "FramedSource::afterGetting()" when you do have enough data). Another way is to have a separate thread that's gathering data, and then have this thread use an 'event trigger' (by calling "TaskScheduler::triggerEvent()") to signal when data is ready to be delivered. For an example of this, see the 'DeviceSource' code in "liveMedia/DeviceSource.cpp". (Note that if you do this, then "TaskScheduler::triggerEvent()" is the *only* LIVE555 function that the separate 'data gathering' thread is allowed to call; see <<a href="http://www.live555.com/liveMedia/faq.html#threads" target="_blank">http://www.live555.com/liveMedia/faq.html#threads</a>>).</div><span class=""><br><br><div>
<span style="border-collapse:separate;color:rgb(0,0,0);font-family:Helvetica;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:-webkit-auto;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="border-collapse:separate;color:rgb(0,0,0);font-family:Helvetica;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:-webkit-auto;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">Ross Finlayson<br>Live Networks, Inc.<br><a href="http://www.live555.com/" target="_blank">http://www.live555.com/</a></span></span>
</div>
<br></span></div><br>_______________________________________________<br>
live-devel mailing list<br>
<a href="mailto:live-devel@lists.live555.com">live-devel@lists.live555.com</a><br>
<a href="http://lists.live555.com/mailman/listinfo/live-devel" target="_blank">http://lists.live555.com/mailman/listinfo/live-devel</a><br>
<br></blockquote></div><br></div>