App-MHFS

 view release on metacpan or  search on metacpan

lib/App/MHFS.pm  view on Meta::CPAN

}; # BEGIN

# You must provide event handlers for the events you are listening for
# return undef to have them removed from poll's structures
package MHFS::EventLoop::Poll::Base {
    use strict; use warnings;
    use feature 'say';
    use POSIX ":sys_wait_h";
    use IO::Poll qw(POLLIN POLLOUT POLLHUP);
    use Time::HiRes qw( usleep clock_gettime CLOCK_REALTIME CLOCK_MONOTONIC);
    use Scalar::Util qw(looks_like_number);
    use Data::Dumper;
    use Devel::Peek;
    #use Devel::Refcount qw( refcount );

    use constant POLLRDHUP => 0;
    use constant ALWAYSMASK => (POLLRDHUP | POLLHUP);

    sub _decode_status {
        my ($rc) = @_;
        print "$rc: normal exit with code ". WEXITSTATUS($rc)."\n" if WIFEXITED(  $rc);

lib/App/MHFS.pm  view on Meta::CPAN


package MHFS::HTTP::Server::Client {
    use strict; use warnings;
    use feature 'say';
    use Time::HiRes qw( usleep clock_gettime CLOCK_REALTIME CLOCK_MONOTONIC);
    use IO::Socket::INET;
    use Errno qw(EINTR EIO :POSIX);
    use Fcntl qw(:seek :mode);
    use File::stat;
    use IO::Poll qw(POLLIN POLLOUT POLLHUP);
    use Scalar::Util qw(looks_like_number weaken);
    use Data::Dumper;
    use Carp;
    $SIG{ __DIE__ } = sub { Carp::confess( @_ ) };

    sub new {
        my ($class, $sock, $server, $serverhostinfo, $ip) = @_;
        $sock->blocking(0);
        my %self = ('sock' => $sock, 'server' => $server, 'time' => clock_gettime(CLOCK_MONOTONIC), 'inbuf' => '', 'serverhostname' => $serverhostinfo->{'hostname'}, 'absurl' => $serverhostinfo->{'absurl'}, 'ip' => $ip, 'X-MHFS-PROXY-KEY' => $serverh...
        $self{'CONN-ID'} = int($self{'time'} * rand()); # insecure uid
        $self{'outheaders'}{'X-MHFS-CONN-ID'} = sprintf("%X", $self{'CONN-ID'});

lib/App/MHFS.pm  view on Meta::CPAN

    }

    1;
}

package MHFS::FD::Reader {
    use strict; use warnings;
    use feature 'say';
    use Time::HiRes qw( usleep clock_gettime CLOCK_MONOTONIC);
    use IO::Poll qw(POLLIN POLLOUT POLLHUP);
    use Scalar::Util qw(looks_like_number weaken);
    sub new {
        my ($class, $process, $fd, $func) = @_;
        my %self = ('time' => clock_gettime(CLOCK_MONOTONIC), 'process' => $process, 'fd' => $fd, 'onReadReady' => $func);
        say "PID " . $self{'process'}{'pid'} . 'FD ' . $self{'fd'};
        weaken($self{'process'});
        return bless \%self, $class;
    }

    sub onReadReady {
        my ($self) = @_;

lib/App/MHFS.pm  view on Meta::CPAN

    }

    1;
 }

 package MHFS::FD::Writer {
    use strict; use warnings;
    use feature 'say';
    use Time::HiRes qw( usleep clock_gettime CLOCK_MONOTONIC);
    use IO::Poll qw(POLLIN POLLOUT POLLHUP);
    use Scalar::Util qw(looks_like_number weaken);
    sub new {
        my ($class, $process, $fd, $func) = @_;
        my %self = ('time' => clock_gettime(CLOCK_MONOTONIC), 'process' => $process, 'fd' => $fd, 'onWriteReady' => $func);
        say "PID " . $self{'process'}{'pid'} . 'FD ' . $self{'fd'};
        weaken($self{'process'});
        return bless \%self, $class;
    }

    sub onWriteReady {
        my ($self) = @_;

lib/App/MHFS.pm  view on Meta::CPAN

    use feature 'say';
    use Symbol 'gensym';
    use Time::HiRes qw( usleep clock_gettime CLOCK_REALTIME CLOCK_MONOTONIC);
    use POSIX ":sys_wait_h";
    use IO::Socket::INET;
    use IO::Poll qw(POLLIN POLLOUT POLLHUP);
    use Errno qw(EINTR EIO :POSIX);
    use Fcntl qw(:seek :mode);
    use File::stat;
    use IPC::Open3;
    use Scalar::Util qw(looks_like_number weaken);
    use Data::Dumper;
    use Devel::Peek;

    use Carp;
    $SIG{ __DIE__ } = sub { Carp::confess( @_ ) };

    #my %CHILDREN;
    #$SIG{CHLD} = sub {
    #    while((my $child = waitpid(-1, WNOHANG)) > 0) {
    #        my ($wstatus, $exitcode) = ($?, $?>> 8);

lib/App/MHFS.pm  view on Meta::CPAN

    use strict; use warnings;
    use feature 'say';
    use Cwd qw(abs_path getcwd);
    use File::Find;
    use Data::Dumper;
    use Devel::Peek;
    use Fcntl ':mode';
    use File::stat;
    use File::Basename;
    use File::Path qw(make_path);
    use Scalar::Util qw(looks_like_number);
    MHFS::Util->import();
    BEGIN {
        if( ! (eval "use JSON; 1")) {
            eval "use JSON::PP; 1" or die "No implementation of JSON available";
            warn __PACKAGE__.": Using PurePerl version of JSON (JSON::PP)";
        }
    }
    use Encode qw(decode encode);
    use URI::Escape;
    use Storable qw(dclone);
    use Fcntl ':mode';
    use Time::HiRes qw( usleep clock_gettime CLOCK_REALTIME CLOCK_MONOTONIC);
    use Scalar::Util qw(looks_like_number weaken);
    use POSIX qw/ceil/;
    use Storable qw( freeze thaw);
    #use ExtUtils::testlib;
    use FindBin;
    use File::Spec;
    use List::Util qw[min max];
    use HTML::Template;

    # Optional dependency, MHFS::XS
    BEGIN {

lib/App/MHFS.pm  view on Meta::CPAN

    1;
}

package MHFS::Plugin::Youtube {
    use strict; use warnings;
    use feature 'say';
    use Data::Dumper;
    use feature 'state';
    use Encode;
    use URI::Escape;
    use Scalar::Util qw(looks_like_number weaken);
    use File::stat;
    MHFS::Util->import();
    BEGIN {
        if( ! (eval "use JSON; 1")) {
            eval "use JSON::PP; 1" or die "No implementation of JSON available";
            warn __PACKAGE__.": Using PurePerl version of JSON (JSON::PP)";
        }
    }

    sub searchbox {

share/public_html/static/music_inc/src/dr_flac.h  view on Meta::CPAN

                __cpuid(info, fid);
            }
        #else
            #define DRFLAC_NO_CPUID
        #endif
    #else
        #if defined(__GNUC__) || defined(__clang__)
            static void drflac__cpuid(int info[4], int fid)
            {
                /*
                It looks like the -fPIC option uses the ebx register which GCC complains about. We can work around this by just using a different register, the
                specific register of which I'm letting the compiler decide on. The "k" prefix is used to specify a 32-bit register. The {...} syntax is for
                supporting different assembly dialects.

                What's basically happening is that we're saving and restoring the ebx register manually.
                */
                #if defined(DRFLAC_X86) && defined(__PIC__)
                    __asm__ __volatile__ (
                        "xchg{l} {%%}ebx, %k1;"
                        "cpuid;"
                        "xchg{l} {%%}ebx, %k1;"

share/public_html/static/music_inc/src/miniaudio.h  view on Meta::CPAN

            {
                return _xgetbv(reg);
            }
        #else
            #define MA_NO_XGETBV
        #endif
    #elif (defined(__GNUC__) || defined(__clang__)) && !defined(MA_ANDROID)
        static MA_INLINE void ma_cpuid(int info[4], int fid)
        {
            /*
            It looks like the -fPIC option uses the ebx register which GCC complains about. We can work around this by just using a different register, the
            specific register of which I'm letting the compiler decide on. The "k" prefix is used to specify a 32-bit register. The {...} syntax is for
            supporting different assembly dialects.
            
            What's basically happening is that we're saving and restoring the ebx register manually.
            */
            #if defined(DRFLAC_X86) && defined(__PIC__)
                __asm__ __volatile__ (
                    "xchg{l} {%%}ebx, %k1;"
                    "cpuid;"
                    "xchg{l} {%%}ebx, %k1;"

share/public_html/static/music_inc/src/miniaudio.h  view on Meta::CPAN

        case ma_backend_opensl:     return "OpenSL|ES";
        case ma_backend_webaudio:   return "Web Audio";
        case ma_backend_null:       return "Null";
        default:                    return "Unknown";
    }
}

MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend)
{
    /*
    This looks a little bit gross, but we want all backends to be included in the switch to avoid warnings on some compilers
    about some enums not being handled by the switch statement.
    */
    switch (backend)
    {
        case ma_backend_wasapi:
        #if defined(MA_HAS_WASAPI)
            return MA_TRUE;
        #else
            return MA_FALSE;
        #endif

share/public_html/static/music_inc/src/miniaudio.h  view on Meta::CPAN

            }
        }

        if (!isDeviceOpen) {
            return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed when trying to open an appropriate default device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
        }
    } else {
        /*
        We're trying to open a specific device. There's a few things to consider here:
        
        miniaudio recongnizes a special format of device id that excludes the "hw", "dmix", etc. prefix. It looks like this: ":0,0", ":0,1", etc. When
        an ID of this format is specified, it indicates to miniaudio that it can try different combinations of plugins ("hw", "dmix", etc.) until it
        finds an appropriate one that works. This comes in very handy when trying to open a device in shared mode ("dmix"), vs exclusive mode ("hw").
        */

        /* May end up needing to make small adjustments to the ID, so make a copy. */
        ma_device_id deviceID = *pDeviceID;
        int resultALSA = -ENODEV;

        if (deviceID.alsa[0] != ':') {
            /* The ID is not in ":0,0" format. Use the ID exactly as-is. */

share/public_html/static/music_inc/src/miniaudio.h  view on Meta::CPAN

        }

        if (NAME != NULL) {
            if (pContext->alsa.useVerboseDeviceEnumeration) {
                /* Verbose mode. Use the name exactly as-is. */
                ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1);
            } else {
                /* Simplified mode. Use ":%d,%d" format. */
                if (ma_convert_device_name_to_hw_format__alsa(pContext, hwid, sizeof(hwid), NAME) == 0) {
                    /*
                    At this point, hwid looks like "hw:0,0". In simplified enumeration mode, we actually want to strip off the
                    plugin name so it looks like ":0,0". The reason for this is that this special format is detected at device
                    initialization time and is used as an indicator to try and use the most appropriate plugin depending on the
                    device type and sharing mode.
                    */
                    char* dst = hwid;
                    char* src = hwid+2;
                    while ((*dst++ = *src++));
                } else {
                    /* Conversion to "hw:%d,%d" failed. Just use the name as-is. */
                    ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1);
                }

share/public_html/static/music_inc/src/miniaudio.h  view on Meta::CPAN


    /* Sample Rate */
    {
        unsigned int sampleRate;

        /*
        It appears there's either a bug in ALSA, a bug in some drivers, or I'm doing something silly; but having resampling enabled causes
        problems with some device configurations when used in conjunction with MMAP access mode. To fix this problem we need to disable
        resampling.
        
        To reproduce this problem, open the "plug:dmix" device, and set the sample rate to 44100. Internally, it looks like dmix uses a
        sample rate of 48000. The hardware parameters will get set correctly with no errors, but it looks like the 44100 -> 48000 resampling
        doesn't work properly - but only with MMAP access mode. You will notice skipping/crackling in the audio, and it'll run at a slightly
        faster rate.
        
        miniaudio has built-in support for sample rate conversion (albeit low quality at the moment), so disabling resampling should be fine
        for us. The only problem is that it won't be taking advantage of any kind of hardware-accelerated resampling and it won't be very
        good quality until I get a chance to improve the quality of miniaudio's software sample rate conversion.
        
        I don't currently know if the dmix plugin is the only one with this error. Indeed, this is the only one I've been able to reproduce
        this error with. In the future, we may want to restrict the disabling of resampling to only known bad plugins.
        */

share/public_html/static/music_inc/src/miniaudio.h  view on Meta::CPAN

        pDeviceInfo->minChannels = bestFormat.mChannelsPerFrame;
        pDeviceInfo->maxChannels = bestFormat.mChannelsPerFrame;
    
        pDeviceInfo->formatCount = 1;
        result = ma_format_from_AudioStreamBasicDescription(&bestFormat, &pDeviceInfo->formats[0]);
        if (result != MA_SUCCESS) {
            return result;
        }
    
        /*
        It looks like Apple are wanting to push the whole AVAudioSession thing. Thus, we need to use that to determine device settings. To do
        this we just get the shared instance and inspect.
        */
        @autoreleasepool {
            AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
            MA_ASSERT(pAudioSession != NULL);

            pDeviceInfo->minSampleRate = (ma_uint32)pAudioSession.sampleRate;
            pDeviceInfo->maxSampleRate = pDeviceInfo->minSampleRate;
        }
    }

share/public_html/static/music_inc/src/miniaudio.h  view on Meta::CPAN


    return noErr;
}

static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, AudioUnitPropertyID propertyID, AudioUnitScope scope, AudioUnitElement element)
{
    ma_device* pDevice = (ma_device*)pUserData;
    MA_ASSERT(pDevice != NULL);
    
    /*
    There's been a report of a deadlock here when triggered by ma_device_uninit(). It looks like
    AudioUnitGetProprty (called below) and AudioComponentInstanceDispose (called in ma_device_uninit)
    can try waiting on the same lock. I'm going to try working around this by not calling any Core
    Audio APIs in the callback when the device has been stopped or uninitialized.
    */
    if (ma_device__get_state(pDevice) == MA_STATE_UNINITIALIZED || ma_device__get_state(pDevice) == MA_STATE_STOPPING || ma_device__get_state(pDevice) == MA_STATE_STOPPED) {
        ma_stop_proc onStop = pDevice->onStop;
        if (onStop) {
            onStop(pDevice);
        }
        

share/public_html/static/music_inc/src/miniaudio.h  view on Meta::CPAN

            The stop event is a bit annoying in Core Audio because it will be called when we automatically switch the default device. Some scenarios to consider:
            
            1) When the device is unplugged, this will be called _before_ the default device change notification.
            2) When the device is changed via the default device change notification, this will be called _after_ the switch.
            
            For case #1, we just check if there's a new default device available. If so, we just ignore the stop event. For case #2 we check a flag.
            */
            if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isDefaultPlaybackDevice) ||
                ((audioUnit == pDevice->coreaudio.audioUnitCapture)  && pDevice->coreaudio.isDefaultCaptureDevice)) {
                /*
                It looks like the device is switching through an external event, such as the user unplugging the device or changing the default device
                via the operating system's sound settings. If we're re-initializing the device, we just terminate because we want the stopping of the
                device to be seamless to the client (we don't want them receiving the onStop event and thinking that the device has stopped when it
                hasn't!).
                */
                if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isSwitchingPlaybackDevice) ||
                    ((audioUnit == pDevice->coreaudio.audioUnitCapture)  && pDevice->coreaudio.isSwitchingCaptureDevice)) {
                    return;
                }
                
                /*
                Getting here means the device is not reinitializing which means it may have been unplugged. From what I can see, it looks like Core Audio
                will try switching to the new default device seamlessly. We need to somehow find a way to determine whether or not Core Audio will most
                likely be successful in switching to the new device.
                
                TODO: Try to predict if Core Audio will switch devices. If not, the onStop callback needs to be posted.
                */
                return;
            }
            
            /* Getting here means we need to stop the device. */
            onStop = pDevice->onStop;

share/public_html/static/music_inc/src/miniaudio.h  view on Meta::CPAN

    
    /* Set the device to use with this audio unit. This is only used on desktop since we are using defaults on mobile. */
#if defined(MA_APPLE_DESKTOP)
    status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_I...
    if (status != noErr) {
        ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
        return ma_result_from_OSStatus(result);
    }
#else
    /*
    For some reason it looks like Apple is only allowing selection of the input device. There does not appear to be any way to change
    the default output route. I have no idea why this is like this, but for now we'll only be able to configure capture devices.
    */
    if (pDeviceID != NULL) {
        if (deviceType == ma_device_type_capture) {
            ma_bool32 found = MA_FALSE;
            NSArray *pInputs = [[[AVAudioSession sharedInstance] currentRoute] inputs];
            for (AVAudioSessionPortDescription* pPortDesc in pInputs) {
                if (strcmp(pDeviceID->coreaudio, [pPortDesc.UID UTF8String]) == 0) {
                    [[AVAudioSession sharedInstance] setPreferredInput:pPortDesc error:nil];
                    found = MA_TRUE;

share/public_html/static/music_inc/src/miniaudio.h  view on Meta::CPAN

        status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, &propSize);
        if (status != noErr) {
            ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
            return ma_result_from_OSStatus(status);
        }
        
        /*
        Sample rate is a little different here because for some reason kAudioUnitProperty_StreamFormat returns 0... Oh well. We need to instead try
        setting the sample rate to what the user has requested and then just see the results of it. Need to use some Objective-C here for this since
        it depends on Apple's AVAudioSession API. To do this we just get the shared AVAudioSession instance and then set it. Note that from what I
        can tell, it looks like the sample rate is shared between playback and capture for everything.
        */
        @autoreleasepool {
            AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
            MA_ASSERT(pAudioSession != NULL);
            
            [pAudioSession setPreferredSampleRate:(double)pData->sampleRateIn error:nil];
            bestFormat.mSampleRate = pAudioSession.sampleRate;

            /*
            I've had a report that the channel count returned by AudioUnitGetProperty above is inconsistent with

share/public_html/static/music_inc/src/miniaudio.h  view on Meta::CPAN

    }

    /* Clamp the channel count for safety. */
    if (pData->channelsOut > MA_MAX_CHANNELS) {
        pData->channelsOut = MA_MAX_CHANNELS;
    }
    
    /*
    Internal channel map. This is weird in my testing. If I use the AudioObject to get the
    channel map, the channel descriptions are set to "Unknown" for some reason. To work around
    this it looks like retrieving it from the AudioUnit will work. However, and this is where
    it gets weird, it doesn't seem to work with capture devices, nor at all on iOS... Therefore
    I'm going to fall back to a default assumption in these cases.
    */
#if defined(MA_APPLE_DESKTOP)
    result = ma_get_AudioUnit_channel_map(pContext, pData->audioUnit, deviceType, pData->channelMapOut, pData->channelsOut);
    if (result != MA_SUCCESS) {
    #if 0
        /* Try falling back to the channel map from the AudioObject. */
        result = ma_get_AudioObject_channel_map(pContext, deviceObjectID, deviceType, pData->channelMapOut, pData->channelsOut);
        if (result != MA_SUCCESS) {

share/public_html/static/music_inc/src/miniaudio.h  view on Meta::CPAN

        return MA_API_NOT_FOUND;
    }
    
    pContext->coreaudio.AudioObjectGetPropertyData        = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyData");
    pContext->coreaudio.AudioObjectGetPropertyDataSize    = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyDataSize");
    pContext->coreaudio.AudioObjectSetPropertyData        = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectSetPropertyData");
    pContext->coreaudio.AudioObjectAddPropertyListener    = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectAddPropertyListener");
    pContext->coreaudio.AudioObjectRemovePropertyListener = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectRemovePropertyListener");

    /*
    It looks like Apple has moved some APIs from AudioUnit into AudioToolbox on more recent versions of macOS. They are still
    defined in AudioUnit, but just in case they decide to remove them from there entirely I'm going to implement a fallback.
    The way it'll work is that it'll first try AudioUnit, and if the required symbols are not present there we'll fall back to
    AudioToolbox.
    */
    pContext->coreaudio.hAudioUnit = ma_dlopen(pContext, "AudioUnit.framework/AudioUnit");
    if (pContext->coreaudio.hAudioUnit == NULL) {
        ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
        ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
        return MA_API_NOT_FOUND;
    }

share/public_html/static/music_inc/src/miniaudio.h  view on Meta::CPAN

    ma_device* pDevice = (ma_device*)pUserData;
    size_t periodSizeInBytes;
    ma_uint8* pBuffer;
    SLresult resultSL;

    MA_ASSERT(pDevice != NULL);

    (void)pBufferQueue;

    /*
    For now, don't do anything unless the buffer was fully processed. From what I can tell, it looks like
    OpenSL|ES 1.1 improves on buffer queues to the point that we could much more intelligently handle this,
    but unfortunately it looks like Android is only supporting OpenSL|ES 1.0.1 for now :(
    */

    /* Don't do anything if the device is not started. */
    if (pDevice->state != MA_STATE_STARTED) {
        return;
    }

    /* Don't do anything if the device is being drained. */
    if (pDevice->opensl.isDrainingCapture) {
        return;

share/public_html/static/music_inc/src/miniaudio.h  view on Meta::CPAN


The implementation define is now "#define MINIAUDIO_IMPLEMENTATION". You can also use "#define MA_IMPLEMENTATION" if that's your preference.


Full-Duplex Support
-------------------
The major feature added to version 0.9 is full-duplex. This has necessitated a few API changes.

1) The data callback has now changed. Previously there was one type of callback for playback and another for capture. I wanted to avoid a third callback just
   for full-duplex so the decision was made to break this API and unify the callbacks. Now, there is just one callback which is the same for all three modes
   (playback, capture, duplex). The new callback looks like the following:

       void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);

   This callback allows you to move data straight out of the input buffer and into the output buffer in full-duplex mode. In playback-only mode, pInput will be
   null. Likewise, pOutput will be null in capture-only mode. The sample count is no longer returned from the callback since it's not necessary for miniaudio
   anymore.

2) The device config needed to change in order to support full-duplex. Full-duplex requires the ability to allow the client to choose a different PCM format
   for the playback and capture sides. The old ma_device_config object simply did not allow this and needed to change. With these changes you now specify the
   device ID, format, channels, channel map and share mode on a per-playback and per-capture basis (see example below). The sample rate must be the same for

share/public_html/static/music_inc/src/miniaudio.h  view on Meta::CPAN

In addition to the above, not all platforms have been absolutely thoroughly tested simply because I lack the hardware for such thorough testing. If you
experience a bug, an issue report on GitHub or an email would be greatly appreciated (and a sample program that reproduces the issue if possible).


Other API Changes
-----------------
In addition to the above, the following API changes have been made:

- The log callback is no longer passed to ma_context_config_init(). Instead you need to set it manually after initialization.
- The onLogCallback member of ma_context_config has been renamed to "logCallback".
- The log callback now takes a logLevel parameter. The new callback looks like: void log_callback(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message)
  - You can use ma_log_level_to_string() to convert the logLevel to human readable text if you want to log it.
- Some APIs have been renamed:
  - mal_decoder_read()          -> ma_decoder_read_pcm_frames()
  - mal_decoder_seek_to_frame() -> ma_decoder_seek_to_pcm_frame()
  - mal_sine_wave_read()        -> ma_sine_wave_read_f32()
  - mal_sine_wave_read_ex()     -> ma_sine_wave_read_f32_ex()
- Some APIs have been removed:
  - mal_device_get_buffer_size_in_bytes()
  - mal_device_set_recv_callback()
  - mal_device_set_send_callback()

share/public_html/static/music_inc/src/miniaudio.h  view on Meta::CPAN

    - All variations of ma_device_config_init_*() have been removed in favor of just ma_device_config_init().
    - ma_device_config_init() now takes only one parameter which is the device type. All other properties need
      to be set on the returned object directly.
    - The onDataCallback and onStopCallback members of ma_device_config have been renamed to "dataCallback"
      and "stopCallback".
    - The ID of the physical device is now split into two: one for the playback device and the other for the
      capture device. This is required for full-duplex. These are named "pPlaybackDeviceID" and "pCaptureDeviceID".
  - API CHANGE: The data callback has changed. It now uses a unified callback for all device types rather than
    being separate for each. It now takes two pointers - one containing input data and the other output data. This
    design in required for full-duplex. The return value is now void instead of the number of frames written. The
    new callback looks like the following:
        void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
  - API CHANGE: Remove the log callback parameter from ma_context_config_init(). With this change,
    ma_context_config_init() now takes no parameters and the log callback is set via the structure directly. The
    new policy for config initialization is that only mandatory settings are passed in to *_config_init(). The
    "onLog" member of ma_context_config has been renamed to "logCallback".
  - API CHANGE: Remove ma_device_get_buffer_size_in_bytes().
  - API CHANGE: Rename decoding APIs to "pcm_frames" convention.
    - mal_decoder_read()          -> ma_decoder_read_pcm_frames()
    - mal_decoder_seek_to_frame() -> ma_decoder_seek_to_pcm_frame()
  - API CHANGE: Rename sine wave reading APIs to f32 convention.

share/public_html/static/music_worklet_inprogress/decoder/deps/dr_libs/dr_flac.h  view on Meta::CPAN

                __cpuid(info, fid);
            }
        #else
            #define DRFLAC_NO_CPUID
        #endif
    #else
        #if defined(__GNUC__) || defined(__clang__)
            static void drflac__cpuid(int info[4], int fid)
            {
                /*
                It looks like the -fPIC option uses the ebx register which GCC complains about. We can work around this by just using a different register, the
                specific register of which I'm letting the compiler decide on. The "k" prefix is used to specify a 32-bit register. The {...} syntax is for
                supporting different assembly dialects.

                What's basically happening is that we're saving and restoring the ebx register manually.
                */
                #if defined(DRFLAC_X86) && defined(__PIC__)
                    __asm__ __volatile__ (
                        "xchg{l} {%%}ebx, %k1;"
                        "cpuid;"
                        "xchg{l} {%%}ebx, %k1;"

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

            {
                return _xgetbv(reg);
            }
        #else
            #define MA_NO_XGETBV
        #endif
    #elif (defined(__GNUC__) || defined(__clang__)) && !defined(MA_ANDROID)
        static MA_INLINE void ma_cpuid(int info[4], int fid)
        {
            /*
            It looks like the -fPIC option uses the ebx register which GCC complains about. We can work around this by just using a different register, the
            specific register of which I'm letting the compiler decide on. The "k" prefix is used to specify a 32-bit register. The {...} syntax is for
            supporting different assembly dialects.

            What's basically happening is that we're saving and restoring the ebx register manually.
            */
            #if defined(DRFLAC_X86) && defined(__PIC__)
                __asm__ __volatile__ (
                    "xchg{l} {%%}ebx, %k1;"
                    "cpuid;"
                    "xchg{l} {%%}ebx, %k1;"

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

        case ma_backend_webaudio:   return "Web Audio";
        case ma_backend_custom:     return "Custom";
        case ma_backend_null:       return "Null";
        default:                    return "Unknown";
    }
}

MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend)
{
    /*
    This looks a little bit gross, but we want all backends to be included in the switch to avoid warnings on some compilers
    about some enums not being handled by the switch statement.
    */
    switch (backend)
    {
        case ma_backend_wasapi:
        #if defined(MA_HAS_WASAPI)
            return MA_TRUE;
        #else
            return MA_FALSE;
        #endif

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN


    *pFrameCount = 0;

    if ((ma_ptr)pAudioClient != pDevice->wasapi.pAudioClientPlayback && (ma_ptr)pAudioClient != pDevice->wasapi.pAudioClientCapture) {
        return MA_INVALID_OPERATION;
    }

    /*
    I've had a report that GetCurrentPadding() is returning a frame count of 0 which is preventing
    higher level function calls from doing anything because it thinks nothing is available. I have
    taken a look at the documentation and it looks like this is unnecessary in exclusive mode.

    From Microsoft's documentation:

        For an exclusive-mode rendering or capture stream that was initialized with the
        AUDCLNT_STREAMFLAGS_EVENTCALLBACK flag, the client typically has no use for the padding
        value reported by GetCurrentPadding. Instead, the client accesses an entire buffer during
        each processing pass.

    Considering this, I'm going to skip GetCurrentPadding() for exclusive mode and just report the
    entire buffer. This depends on the caller making sure they wait on the event handler.

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

        }

        if (!isDeviceOpen) {
            ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed when trying to open an appropriate default device.");
            return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
        }
    } else {
        /*
        We're trying to open a specific device. There's a few things to consider here:

        miniaudio recongnizes a special format of device id that excludes the "hw", "dmix", etc. prefix. It looks like this: ":0,0", ":0,1", etc. When
        an ID of this format is specified, it indicates to miniaudio that it can try different combinations of plugins ("hw", "dmix", etc.) until it
        finds an appropriate one that works. This comes in very handy when trying to open a device in shared mode ("dmix"), vs exclusive mode ("hw").
        */

        /* May end up needing to make small adjustments to the ID, so make a copy. */
        ma_device_id deviceID = *pDeviceID;
        int resultALSA = -ENODEV;

        if (deviceID.alsa[0] != ':') {
            /* The ID is not in ":0,0" format. Use the ID exactly as-is. */

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

        }

        if (NAME != NULL) {
            if (pContext->alsa.useVerboseDeviceEnumeration) {
                /* Verbose mode. Use the name exactly as-is. */
                ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1);
            } else {
                /* Simplified mode. Use ":%d,%d" format. */
                if (ma_convert_device_name_to_hw_format__alsa(pContext, hwid, sizeof(hwid), NAME) == 0) {
                    /*
                    At this point, hwid looks like "hw:0,0". In simplified enumeration mode, we actually want to strip off the
                    plugin name so it looks like ":0,0". The reason for this is that this special format is detected at device
                    initialization time and is used as an indicator to try and use the most appropriate plugin depending on the
                    device type and sharing mode.
                    */
                    char* dst = hwid;
                    char* src = hwid+2;
                    while ((*dst++ = *src++));
                } else {
                    /* Conversion to "hw:%d,%d" failed. Just use the name as-is. */
                    ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1);
                }

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN


    /* Sample Rate */
    {
        unsigned int sampleRate;

        /*
        It appears there's either a bug in ALSA, a bug in some drivers, or I'm doing something silly; but having resampling enabled causes
        problems with some device configurations when used in conjunction with MMAP access mode. To fix this problem we need to disable
        resampling.

        To reproduce this problem, open the "plug:dmix" device, and set the sample rate to 44100. Internally, it looks like dmix uses a
        sample rate of 48000. The hardware parameters will get set correctly with no errors, but it looks like the 44100 -> 48000 resampling
        doesn't work properly - but only with MMAP access mode. You will notice skipping/crackling in the audio, and it'll run at a slightly
        faster rate.

        miniaudio has built-in support for sample rate conversion (albeit low quality at the moment), so disabling resampling should be fine
        for us. The only problem is that it won't be taking advantage of any kind of hardware-accelerated resampling and it won't be very
        good quality until I get a chance to improve the quality of miniaudio's software sample rate conversion.

        I don't currently know if the dmix plugin is the only one with this error. Indeed, this is the only one I've been able to reproduce
        this error with. In the future, we may want to restrict the disabling of resampling to only known bad plugins.
        */

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

        pDeviceInfo->nativeDataFormatCount = 1;

        result = ma_format_from_AudioStreamBasicDescription(&bestFormat, &pDeviceInfo->nativeDataFormats[0].format);
        if (result != MA_SUCCESS) {
            return result;
        }

        pDeviceInfo->nativeDataFormats[0].channels = bestFormat.mChannelsPerFrame;

        /*
        It looks like Apple are wanting to push the whole AVAudioSession thing. Thus, we need to use that to determine device settings. To do
        this we just get the shared instance and inspect.
        */
        @autoreleasepool {
            AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
            MA_ASSERT(pAudioSession != NULL);

            pDeviceInfo->nativeDataFormats[0].sampleRate = (ma_uint32)pAudioSession.sampleRate;
        }
    }
#endif

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

    (void)pUnusedBufferList;

    return noErr;
}

static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, AudioUnitPropertyID propertyID, AudioUnitScope scope, AudioUnitElement element)
{
    ma_device* pDevice = (ma_device*)pUserData;
    MA_ASSERT(pDevice != NULL);

    /* Don't do anything if it looks like we're just reinitializing due to a device switch. */
    if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isSwitchingPlaybackDevice) ||
        ((audioUnit == pDevice->coreaudio.audioUnitCapture)  && pDevice->coreaudio.isSwitchingCaptureDevice)) {
        return;
    }

    /*
    There's been a report of a deadlock here when triggered by ma_device_uninit(). It looks like
    AudioUnitGetProprty (called below) and AudioComponentInstanceDispose (called in ma_device_uninit)
    can try waiting on the same lock. I'm going to try working around this by not calling any Core
    Audio APIs in the callback when the device has been stopped or uninitialized.
    */
    if (ma_device_get_state(pDevice) == ma_device_state_uninitialized || ma_device_get_state(pDevice) == ma_device_state_stopping || ma_device_get_state(pDevice) == ma_device_state_stopped) {
        ma_device__on_notification_stopped(pDevice);
    } else {
        UInt32 isRunning;
        UInt32 isRunningSize = sizeof(isRunning);
        OSStatus status = ((ma_AudioUnitGetProperty_proc)pDevice->pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioOutputUnitProperty_IsRunning, scope, element, &isRunning, &isRunningSize);

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

            The stop event is a bit annoying in Core Audio because it will be called when we automatically switch the default device. Some scenarios to consider:

            1) When the device is unplugged, this will be called _before_ the default device change notification.
            2) When the device is changed via the default device change notification, this will be called _after_ the switch.

            For case #1, we just check if there's a new default device available. If so, we just ignore the stop event. For case #2 we check a flag.
            */
            if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isDefaultPlaybackDevice) ||
                ((audioUnit == pDevice->coreaudio.audioUnitCapture)  && pDevice->coreaudio.isDefaultCaptureDevice)) {
                /*
                It looks like the device is switching through an external event, such as the user unplugging the device or changing the default device
                via the operating system's sound settings. If we're re-initializing the device, we just terminate because we want the stopping of the
                device to be seamless to the client (we don't want them receiving the stopped event and thinking that the device has stopped when it
                hasn't!).
                */
                if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isSwitchingPlaybackDevice) ||
                    ((audioUnit == pDevice->coreaudio.audioUnitCapture)  && pDevice->coreaudio.isSwitchingCaptureDevice)) {
                    goto done;
                }

                /*
                Getting here means the device is not reinitializing which means it may have been unplugged. From what I can see, it looks like Core Audio
                will try switching to the new default device seamlessly. We need to somehow find a way to determine whether or not Core Audio will most
                likely be successful in switching to the new device.

                TODO: Try to predict if Core Audio will switch devices. If not, the stopped callback needs to be posted.
                */
                goto done;
            }

            /* Getting here means we need to stop the device. */
            ma_device__on_notification_stopped(pDevice);

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN


    /* Set the device to use with this audio unit. This is only used on desktop since we are using defaults on mobile. */
#if defined(MA_APPLE_DESKTOP)
    status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceObjectID, sizeof(deviceObjectID));
    if (status != noErr) {
        ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
        return ma_result_from_OSStatus(result);
    }
#else
    /*
    For some reason it looks like Apple is only allowing selection of the input device. There does not appear to be any way to change
    the default output route. I have no idea why this is like this, but for now we'll only be able to configure capture devices.
    */
    if (pDeviceID != NULL) {
        if (deviceType == ma_device_type_capture) {
            ma_bool32 found = MA_FALSE;
            NSArray *pInputs = [[[AVAudioSession sharedInstance] currentRoute] inputs];
            for (AVAudioSessionPortDescription* pPortDesc in pInputs) {
                if (strcmp(pDeviceID->coreaudio, [pPortDesc.UID UTF8String]) == 0) {
                    [[AVAudioSession sharedInstance] setPreferredInput:pPortDesc error:nil];
                    found = MA_TRUE;

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

            /* We failed to set the format, so fall back to the current format of the audio unit. */
            bestFormat = origFormat;
        }
    #else
        bestFormat = origFormat;

        /*
        Sample rate is a little different here because for some reason kAudioUnitProperty_StreamFormat returns 0... Oh well. We need to instead try
        setting the sample rate to what the user has requested and then just see the results of it. Need to use some Objective-C here for this since
        it depends on Apple's AVAudioSession API. To do this we just get the shared AVAudioSession instance and then set it. Note that from what I
        can tell, it looks like the sample rate is shared between playback and capture for everything.
        */
        @autoreleasepool {
            AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
            MA_ASSERT(pAudioSession != NULL);

            [pAudioSession setPreferredSampleRate:(double)pData->sampleRateIn error:nil];
            bestFormat.mSampleRate = pAudioSession.sampleRate;

            /*
            I've had a report that the channel count returned by AudioUnitGetProperty above is inconsistent with

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

    }

    /* Clamp the channel count for safety. */
    if (pData->channelsOut > MA_MAX_CHANNELS) {
        pData->channelsOut = MA_MAX_CHANNELS;
    }

    /*
    Internal channel map. This is weird in my testing. If I use the AudioObject to get the
    channel map, the channel descriptions are set to "Unknown" for some reason. To work around
    this it looks like retrieving it from the AudioUnit will work. However, and this is where
    it gets weird, it doesn't seem to work with capture devices, nor at all on iOS... Therefore
    I'm going to fall back to a default assumption in these cases.
    */
#if defined(MA_APPLE_DESKTOP)
    result = ma_get_AudioUnit_channel_map(pContext, pData->audioUnit, deviceType, pData->channelMapOut, pData->channelsOut);
    if (result != MA_SUCCESS) {
    #if 0
        /* Try falling back to the channel map from the AudioObject. */
        result = ma_get_AudioObject_channel_map(pContext, deviceObjectID, deviceType, pData->channelMapOut, pData->channelsOut);
        if (result != MA_SUCCESS) {

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

        return MA_API_NOT_FOUND;
    }

    pContext->coreaudio.AudioObjectGetPropertyData        = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyData");
    pContext->coreaudio.AudioObjectGetPropertyDataSize    = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyDataSize");
    pContext->coreaudio.AudioObjectSetPropertyData        = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectSetPropertyData");
    pContext->coreaudio.AudioObjectAddPropertyListener    = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectAddPropertyListener");
    pContext->coreaudio.AudioObjectRemovePropertyListener = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectRemovePropertyListener");

    /*
    It looks like Apple has moved some APIs from AudioUnit into AudioToolbox on more recent versions of macOS. They are still
    defined in AudioUnit, but just in case they decide to remove them from there entirely I'm going to implement a fallback.
    The way it'll work is that it'll first try AudioUnit, and if the required symbols are not present there we'll fall back to
    AudioToolbox.
    */
    pContext->coreaudio.hAudioUnit = ma_dlopen(pContext, "AudioUnit.framework/AudioUnit");
    if (pContext->coreaudio.hAudioUnit == NULL) {
        ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
        ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
        return MA_API_NOT_FOUND;
    }

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

    ma_device* pDevice = (ma_device*)pUserData;
    size_t periodSizeInBytes;
    ma_uint8* pBuffer;
    SLresult resultSL;

    MA_ASSERT(pDevice != NULL);

    (void)pBufferQueue;

    /*
    For now, don't do anything unless the buffer was fully processed. From what I can tell, it looks like
    OpenSL|ES 1.1 improves on buffer queues to the point that we could much more intelligently handle this,
    but unfortunately it looks like Android is only supporting OpenSL|ES 1.0.1 for now :(
    */

    /* Don't do anything if the device is not started. */
    if (ma_device_get_state(pDevice) != ma_device_state_started) {
        return;
    }

    /* Don't do anything if the device is being drained. */
    if (pDevice->opensl.isDrainingCapture) {
        return;

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

Delay
*/
MA_API ma_delay_config ma_delay_config_init(ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 delayInFrames, float decay)
{
    ma_delay_config config;

    MA_ZERO_OBJECT(&config);
    config.channels      = channels;
    config.sampleRate    = sampleRate;
    config.delayInFrames = delayInFrames;
    config.delayStart    = (decay == 0) ? MA_TRUE : MA_FALSE;   /* Delay the start if it looks like we're not configuring an echo. */
    config.wet           = 1;
    config.dry           = 1;
    config.decay         = decay;

    return config;
}


MA_API ma_result ma_delay_init(const ma_delay_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_delay* pDelay)
{



( run in 0.524 second using v1.01-cache-2.11-cpan-64827b87656 )