Re: Continuous Memory Player

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Glad you solved it. I figured it might be not of much help.

It helps me a bunch though. I'm always getting into messes like that where I even just need to print what the buffer sizes are resolving to. I get mixed up a bunch with simple things in C/C++ like order of operations and floating point/non-floating point maths.

For example, to calculate the buffer frames required for a given period I use this:

                template<typename Rep,typename Period>
                static size_t calculateBufferFrames( const std::chrono::duration<Rep,Period> &period, size_t samplerate )
                {
                    // Now how much period is in a second (because the samplerate is a full second)
                    auto per_second = std::chrono::duration_cast<std::chrono::duration<Rep,Period>>( std::chrono::seconds( 1 ) );

                    // Now do the math
                    return( period.count()*samplerate/per_second.count() );
                }
I used to have ( period.count()/per_second.count() )*samplerate which works fine if you do it with a calculator, but will produce 0 if done here. That caused me a bit of grief with the buffers until I did some print lines.

Maybe I'm just inexperienced :D.

Michael A. Leonetti
As warm as green tea
On 9/22/19 10:34 PM, Jonathan Brockerville wrote:
Thanks, Michael. That is some serious console debugging code.  :)

Turns out I may have fluked into solving it. I can't explain it just yet, but it feels right. I was trying buffers with different sample rates, byte rates, and number of channels. One test didn't do the repeating thing. It was a buffer size of double the byte rate. I changed all my tests to allocate a buffer of double the byte rate and they all worked. We'll see if that holds true with more rigorous testing though.  :P



On Fri, 20 Sep 2019 at 15:13, Michael A. Leonetti <michael@xxxxxxxxxxxxxxx> wrote:

Maybe not helpful, but if it were me I'd std::cout the heck out of the code to see in what sequence everything occurs. I would, do this:

  1. Use some serious print lines as many places as you can, especially on the EOF function, and the functions where you're writing your audio source also with memory locations.
  2. Create output files with whatever the same data is that you write to the media buffers, write to the files (name them each differently each time EOF occurs close the file and reopen). Afterwards open the files with audacity or something (especially if they're raw PCM) and hear what they sound like.

This is how I debug stuff like this. If the output files are also weird, then that might tell you something about what's going on.

Here's a quick and dirty (and ugly) library I wrote for just such occasions that you can easily turn on and off.

// Intelligent debug COUT code to stop code duplication

#ifndef DEBUGCOUTS_H
#define DEBUGCOUTS_H

#if defined( DEBUG )
#include <iomanip>
#include <iostream>
#include <string>
#include <thread>
#include <chrono>
#endif

// Define the couts
#define COUT_LOG_INFO( PREFIX ) PREFIX##_INFO() << '[' << __LINE__ << ' ' << __PRETTY_FUNCTION__ << "]: "
#define COUT_LOG_WARN( PREFIX ) PREFIX##_WARN() << '[' << __LINE__ << ' ' << __PRETTY_FUNCTION__ << "]: "
#define COUT_LOG_ERROR( PREFIX ) PREFIX##_ERROR() << '[' << __LINE__ << ' ' << __PRETTY_FUNCTION__ << "]: "

// Quick class for differentiating when we don't have a string
class DebugCouts_NoStringType : public std::string {}; // Make it a string type

#endif

/**
 * Prefix name of the logger functions you want.
 * For example DEBUG_COUTS( MyClassFile, true )
 * will make the log functions COUT_LOG_INFO, COUT_LOG_WARN, COUT_LOG_ERROR
 * For use like
 * COUT_LOG_INFO( MyClassFile ) << "This will get thinged?";
 * Or just
 * COUT_LOG_INFO( MyClassFile );
 * Setting the second parameter ACTIVE to "false" causes everything to be compiled out except for the iostream code which adds some bloat
 */
#if defined( DEBUG )

#define DEBUG_COUTS( PREFIX, ACTIVE ) template<bool ENABLED> \
class PREFIX##_Log \
{ \
    public: \
    template<typename STRING_TYPE=DebugCouts_NoStringType> PREFIX##_Log( STRING_TYPE level=STRING_TYPE() ) \
    { \
        if( ENABLED and !std::is_same<STRING_TYPE,DebugCouts_NoStringType>::value ) \
    { \
        auto now = std::chrono::system_clock::now(); \
        auto seconds = std::chrono::time_point_cast<std::chrono::seconds>( now ); \
        auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>( now-seconds ); \
        auto t = std::chrono::system_clock::to_time_t( now ); \
            char b[ 64 ]; \
            if( !std::strftime( b, sizeof( b ), "%F, %T", std::localtime( &t ) ) ) \
            { \
                b[ 0 ] = 0; \
            } \
        std::cout << "["#PREFIX" " << level << ' ' << b << '.' << microseconds.count() << "] (" << std::hex << std::this_thread::get_id() << std::dec << ") "; \
    } \
    } \
    template<class T> \
        PREFIX##_Log &operator <<( const T &v ) \
        { \
            if( ENABLED ) \
                std::cout << v; \
            return( *this ); \
        } \
    ~PREFIX##_Log() \
    { \
        if( ENABLED ) \
        std::cout << std::endl; \
    } \
}; \
template<typename STRING_TYPE=DebugCouts_NoStringType> PREFIX##_Log<ACTIVE> PREFIX##_ERROR( STRING_TYPE message=STRING_TYPE() ) \
{ \
    if( !ACTIVE ) \
        return( PREFIX##_Log<ACTIVE>() ); \
    PREFIX##_Log<ACTIVE> log( "ERROR" ); \
    if( !std::is_same<STRING_TYPE,DebugCouts_NoStringType>::value ) \
        log << message << ": "; \
    return( log ); \
} \
template<typename STRING_TYPE=DebugCouts_NoStringType> PREFIX##_Log<ACTIVE> PREFIX##_WARN( STRING_TYPE message=STRING_TYPE() ) \
{ \
    if( !ACTIVE ) \
        return( PREFIX##_Log<ACTIVE>() ); \
    PREFIX##_Log<ACTIVE> log( "WARN" ); \
    if( !std::is_same<STRING_TYPE,DebugCouts_NoStringType>::value ) \
        log << message << ": "; \
    return( log ); \
} \
template<typename STRING_TYPE=DebugCouts_NoStringType> PREFIX##_Log<ACTIVE> PREFIX##_INFO( STRING_TYPE message=STRING_TYPE() ) \
{ \
    if( !ACTIVE ) \
        return( PREFIX##_Log<ACTIVE>() ); \
    PREFIX##_Log<ACTIVE> log( "INFO" ); \
    if( !std::is_same<STRING_TYPE,DebugCouts_NoStringType>::value ) \
        log << message << ": "; \
    return( log ); \
}

#else

// Blank ones
#define DEBUG_COUTS( PREFIX, ACTIVE ) template<bool ENABLED> \
class PREFIX##_Log \
{ \
    public: \
    template<typename STRING_TYPE=DebugCouts_NoStringType> PREFIX##_Log( STRING_TYPE level=STRING_TYPE() ) \
    { \
    } \
    template<class T> \
        PREFIX##_Log &operator <<( const T &v ) \
        { \
            return( *this ); \
        } \
    ~PREFIX##_Log() \
    { \
    } \
}; \
template<typename STRING_TYPE=DebugCouts_NoStringType> PREFIX##_Log<ACTIVE> PREFIX##_ERROR( STRING_TYPE message=STRING_TYPE() ) \
{ \
    return( PREFIX##_Log<ACTIVE>() ); \
} \
template<typename STRING_TYPE=DebugCouts_NoStringType> PREFIX##_Log<ACTIVE> PREFIX##_WARN( STRING_TYPE message=STRING_TYPE() ) \
{ \
    return( PREFIX##_Log<ACTIVE>() ); \
} \
template<typename STRING_TYPE=DebugCouts_NoStringType> PREFIX##_Log<ACTIVE> PREFIX##_INFO( STRING_TYPE message=STRING_TYPE() ) \
{ \
    return( PREFIX##_Log<ACTIVE>() ); \
}

#endif


Michael A. Leonetti
As warm as green tea
On 9/20/19 2:44 PM, Jonathan Brockerville wrote:
Hi,

I'm trying to create a continuous memory player (for lack of a better description). Here's what I'm doing. Create a memory player with looping enabled. When it gets to EOF the callback method is invoked. I update the memory with new audio data and return true. This basically works, however, I keep getting a little snippet of the previous audio data. It's as if the callback is invoked slightly after the rewind happens. I assumed that execution would be: play memory, EOF callback, rewind memory, play memory, etc. That doesn't seem to be the case. What am I getting wrong here?

I also tried disabling looping, but I couldn't figure out how to manually rewind the memory and transmit again. Destroying the memory player, re-creating it, and pointing at the same but updated buffer seems heavy handed.

I've essentially copied and pasted the AudioMediaPlayer class and used the memory player methods under the hood. That is, https://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__MEM__PLAYER.htm 

Should I be approaching this differently or...?

Thanks,
-brock

 

_______________________________________________
Visit our blog: http://blog.pjsip.org

pjsip mailing list
pjsip@xxxxxxxxxxxxxxx
http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org
_______________________________________________
Visit our blog: http://blog.pjsip.org

pjsip mailing list
pjsip@xxxxxxxxxxxxxxx
http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org

_______________________________________________
Visit our blog: http://blog.pjsip.org

pjsip mailing list
pjsip@xxxxxxxxxxxxxxx
http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org
_______________________________________________
Visit our blog: http://blog.pjsip.org

pjsip mailing list
pjsip@xxxxxxxxxxxxxxx
http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org

[Index of Archives]     [Asterisk Users]     [Asterisk App Development]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [Linux API]
  Powered by Linux