view src/audio/mme/SDL_mmeaudio.c @ 3487:24d13328c44a

Eric Wing to Sam, hfutrell This one is quite puzzling. I found a partial workaround, but I don't fully understand the reasons yet. First, the console is complaining about not finding a nib for MainWindow. I tried removing the entry for this in the info.plist, and the message went away, but it didn't really change anything. Second, I stepped through this with the debugger and broke up some lines. It seems that the basic act of calling view = [SDL_uikitopenglview alloc]; or even view = [SDL_uikitview alloc] will crash the program. The debugger messages plus the stack trace make me think it's not finding the SDL_uikitview classes for some reason. But I don't understand why this would be. view = [UIView alloc] will not crash the program. For kicks, I added a new definition of a class called SDL_object which subclasses NSObject in the same files as SDL_uikitopenglview and then call view = [SDL_object alloc]; This does not crash the program. So, then I modified SDL_object to subclass UIView. No crash. Next, I made SDL_object subclass UIView<UITextFieldDelegate> . This crashes. So it is the act of conforming to the UITextFieldDelegate protocol that is crashing things. I don't understand why it would crash on alloc though. I'm guessing either a delegate needs to be set somewhere or one of the required methods needs to be implemented. But in the former case, I would not expect a crash, but a silent message to nil and something else doesn't work. And in the latter case, I would expect a compiler warning and an exception thrown instead of a crash. Anyway, my temporary workaround is to change the interface declaration for SDL_uikitview to look like: #if SDL_IPHONE_KEYBOARD @interface SDL_uikitview : UIView<UITextFieldDelegate> { #else @interface SDL_uikitview : UIView { #endif And then disable the keyboard support in the SDL_config_iphoneos.h file. /* enable iPhone keyboard support */ #define SDL_IPHONE_KEYBOARD 0 -Eric On Nov 23, 2009, at 1:43 AM, Sam Lantinga wrote: > I ran into a blocking startup crash with the Happy demo on iPhone OS 3.1.2 on my new iPhone: > > #0 0x323fea14 in _class_isInitialized > #1 0x323fea68 in _class_initialize > #2 0x32403e92 in prepareForMethodLookup > #3 0x32401244 in lookUpMethod > #4 0x323fea10 in _class_lookupMethodAndLoadCache > #5 0x323fe746 in objc_msgSend_uncached > #6 0x323feb26 in _class_initialize > #7 0x323fea58 in _class_initialize > #8 0x32403e92 in prepareForMethodLookup > #9 0x32401244 in lookUpMethod > #10 0x323fea10 in _class_lookupMethodAndLoadCache > #11 0x323fe746 in objc_msgSend_uncached > #12 0x000554dc in UIKit_GL_CreateContext at SDL_uikitopengles.m:103 > #13 0x0004f89e in SDL_GL_CreateContext at SDL_video.c:3155 > #14 0x000579e8 in GLES_CreateRenderer at SDL_renderer_gles.c:282 > #15 0x0004d7b8 in SDL_CreateRenderer at SDL_video.c:1509 > #16 0x00002bc2 in SDL_main at happy.c:156 > #17 0x000571b2 in -[SDLUIKitDelegate postFinishLaunch] at > SDL_uikitappdelegate.m:77 > #18 0x313f9ef2 in __NSFireDelayedPerform > #19 0x32567bb2 in CFRunLoopRunSpecific > #20 0x3256735c in CFRunLoopRunInMode > #21 0x32912cbe in GSEventRunModal > #22 0x32912d6a in GSEventRun > #23 0x32b6276e in -[UIApplication _run] > #24 0x32b61472 in UIApplicationMain > #25 0x00057088 in main at SDL_uikitappdelegate.m:50 > > Any ideas? > > See ya! > -- > -Sam Lantinga, Founder and President, Galaxy Gameworks LLC
author Sam Lantinga <slouken@libsdl.org>
date Tue, 24 Nov 2009 08:12:32 +0000
parents 99210400e8b9
children f7b03b6838cb
line wrap: on
line source

/*
    SDL - Simple DirectMedia Layer
    Copyright (C) 1997-2009 Sam Lantinga

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Sam Lantinga
    slouken@libsdl.org
*/
#include "SDL_config.h"

/* Tru64 UNIX MME support */
#include <mme_api.h>

#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "SDL_mmeaudio.h"

static BOOL inUse[NUM_BUFFERS];

static void
SetMMerror(char *function, MMRESULT code)
{
    int len;
    char errbuf[MAXERRORLENGTH];

    SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: ", function);
    len = SDL_strlen(errbuf);
    waveOutGetErrorText(code, errbuf + len, MAXERRORLENGTH - len);
    SDL_SetError("%s", errbuf);
}

static void CALLBACK
MME_Callback(HWAVEOUT hwo,
             UINT uMsg, DWORD dwInstance, LPARAM dwParam1, LPARAM dwParam2)
{
    WAVEHDR *wp = (WAVEHDR *) dwParam1;

    if (uMsg == WOM_DONE)
        inUse[wp->dwUser] = FALSE;
}

static int
MME_OpenDevice(_THIS, const char *devname, int iscapture)
{
    int valid_format = 0;
    MMRESULT result;
    Uint8 *mixbuf = NULL;
    int i;

    /* Initialize all variables that we clean on shutdown */
    this->hidden = (struct SDL_PrivateAudioData *)
        SDL_malloc((sizeof *this->hidden));
    if (this->hidden == NULL) {
        SDL_OutOfMemory();
        return 0;
    }
    SDL_memset(this->hidden, 0, (sizeof *this->hidden));

    /* Set basic WAVE format parameters */
    this->hidden->shm = mmeAllocMem(sizeof(*this->hidden->shm));
    if (this->hidden->shm == NULL) {
        MME_CloseDevice(this);
        SDL_OutOfMemory();
        return 0;
    }

    SDL_memset(this->hidden->shm, '\0', sizeof(*this->hidden->shm));
    this->hidden->shm->sound = 0;
    this->hidden->shm->wFmt.wf.wFormatTag = WAVE_FORMAT_PCM;

    /* Determine the audio parameters from the AudioSpec */
    /* Try for a closest match on audio format */
    for (test_format = SDL_FirstAudioFormat(this->spec.format);
         !valid_format && test_format;) {
        valid_format = 1;
        switch (test_format) {
        case AUDIO_U8:
        case AUDIO_S16:
        case AUDIO_S32:
            break;
        default:
            valid_format = 0;
            test_format = SDL_NextAudioFormat();
        }
    }

    if (!valid_format) {
        MME_CloseDevice(this);
        SDL_SetError("Unsupported audio format");
        return 0;
    }

    this->spec.format = test_format;
    this->hidden->shm->wFmt.wBitsPerSample = SDL_AUDIO_BITSIZE(test_format);

    /* !!! FIXME: Can this handle more than stereo? */
    this->hidden->shm->wFmt.wf.nChannels = this->spec.channels;
    this->hidden->shm->wFmt.wf.nSamplesPerSec = this->spec.freq;
    this->hidden->shm->wFmt.wf.nBlockAlign =
        this->hidden->shm->wFmt.wf.nChannels *
        this->hidden->shm->wFmt.wBitsPerSample / 8;
    this->hidden->shm->wFmt.wf.nAvgBytesPerSec =
        this->hidden->shm->wFmt.wf.nSamplesPerSec *
        this->hidden->shm->wFmt.wf.nBlockAlign;

    /* Check the buffer size -- minimum of 1/4 second (word aligned) */
    if (this->spec.samples < (this->spec.freq / 4))
        this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;

    /* Update the fragment size as size in bytes */
    SDL_CalculateAudioSpec(&this->spec);

    /* Open the audio device */
    result = waveOutOpen(&(this->hidden->shm->sound),
                         WAVE_MAPPER,
                         &(this->hidden->shm->wFmt.wf),
                         MME_Callback,
                         NULL, (CALLBACK_FUNCTION | WAVE_OPEN_SHAREABLE));
    if (result != MMSYSERR_NOERROR) {
        MME_CloseDevice(this);
        SetMMerror("waveOutOpen()", result);
        return 0;
    }

    /* Create the sound buffers */
    mixbuf = (Uint8 *) mmeAllocBuffer(NUM_BUFFERS * (this->spec.size));
    if (mixbuf == NULL) {
        MME_CloseDevice(this);
        SDL_OutOfMemory();
        return 0;
    }
    this->hidden->mixbuf = mixbuf;

    for (i = 0; i < NUM_BUFFERS; i++) {
        this->hidden->shm->wHdr[i].lpData = &mixbuf[i * (this->spec.size)];
        this->hidden->shm->wHdr[i].dwBufferLength = this->spec.size;
        this->hidden->shm->wHdr[i].dwFlags = 0;
        this->hidden->shm->wHdr[i].dwUser = i;
        this->hidden->shm->wHdr[i].dwLoops = 0; /* loop control counter */
        this->hidden->shm->wHdr[i].lpNext = NULL;       /* reserved for driver */
        this->hidden->shm->wHdr[i].reserved = 0;
        inUse[i] = FALSE;
    }
    this->hidden->next_buffer = 0;

    return 1;
}

static void
MME_WaitDevice(_THIS)
{
    while (inUse[this->hidden->next_buffer]) {
        mmeWaitForCallbacks();
        mmeProcessCallbacks();
    }
}

static Uint8 *
MME_GetDeviceBuf(_THIS)
{
    void *retval = this->hidden->shm->wHdr[this->hidden->next_buffer].lpData;
    inUse[this->hidden->next_buffer] = TRUE;
    return (Uint8 *) retval;
}

static void
MME_PlayDevice(_THIS)
{
    /* Queue it up */
    waveOutWrite(this->hidden->shm->sound,
                 &(this->hidden->shm->wHdr[this->hidden->next_buffer]),
                 sizeof(WAVEHDR));
    this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
}

static void
MME_WaitDone(_THIS)
{
    MMRESULT result;
    int i;

    if (this->hidden->shm->sound) {
        for (i = 0; i < NUM_BUFFERS; i++)
            while (inUse[i]) {
                mmeWaitForCallbacks();
                mmeProcessCallbacks();
            }
        result = waveOutReset(this->hidden->shm->sound);
        if (result != MMSYSERR_NOERROR)
            SetMMerror("waveOutReset()", result);
        mmeProcessCallbacks();
    }
}

static void
MME_CloseDevice(_THIS)
{
    if (this->hidden != NULL) {
        MMRESULT result;

        if (this->hidden->mixbuf) {
            result = mmeFreeBuffer(this->hidden->mixbuf);
            if (result != MMSYSERR_NOERROR)
                SetMMerror("mmeFreeBuffer", result);
            this->hidden->mixbuf = NULL;
        }

        if (this->hidden->shm) {
            if (this->hidden->shm->sound) {
                result = waveOutClose(this->hidden->shm->sound);
                if (result != MMSYSERR_NOERROR)
                    SetMMerror("waveOutClose()", result);
                mmeProcessCallbacks();
            }
            result = mmeFreeMem(this->hidden->shm);
            if (result != MMSYSERR_NOERROR)
                SetMMerror("mmeFreeMem()", result);
            this->hidden->shm = NULL;
        }

        SDL_free(this->hidden);
        this->hidden = NULL;
    }
}

static int
MME_Init(SDL_AudioDriverImpl * impl)
{
    /* Set the function pointers */
    impl->OpenDevice = MME_OpenDevice;
    impl->WaitDevice = MME_WaitDevice;
    impl->WaitDone = MME_WaitDone;
    impl->PlayDevice = MME_PlayDevice;
    impl->GetDeviceBuf = MME_GetDeviceBuf;
    impl->CloseDevice = MME_CloseDevice;
    impl->OnlyHasDefaultOutputDevice = 1;

    return 1;
}

/* !!! FIXME: Windows "windib" driver is called waveout, too */
AudioBootStrap MMEAUDIO_bootstrap = {
    "waveout", "Tru64 MME WaveOut", MME_Init, 0
};

/* vi: set ts=4 sw=4 expandtab: */