src/audio/android/SDL_androidaudio.c
author Ryan C. Gordon
Tue, 24 Jan 2017 16:18:25 -0500
changeset 10850 c9dc0068b0e7
parent 10737 3406a0f8b041
child 11811 5d94cb6b24d3
permissions -rw-r--r--
configure: report libsamplerate support status.
paul@4718
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@10737
     3
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
paul@4718
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
paul@4718
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
paul@4718
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
paul@4718
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
paul@4718
    22
slouken@6044
    23
#if SDL_AUDIO_DRIVER_ANDROID
slouken@6044
    24
paul@4718
    25
/* Output audio to Android */
paul@4718
    26
icculus@10280
    27
#include "SDL_assert.h"
paul@4718
    28
#include "SDL_audio.h"
paul@4718
    29
#include "../SDL_audio_c.h"
paul@4718
    30
#include "SDL_androidaudio.h"
slouken@4995
    31
slouken@5090
    32
#include "../../core/android/SDL_android.h"
paul@4724
    33
paul@4718
    34
#include <android/log.h>
paul@4718
    35
gabomdq@9148
    36
static SDL_AudioDevice* audioDevice = NULL;
icculus@10280
    37
static SDL_AudioDevice* captureDevice = NULL;
slouken@4995
    38
paul@4718
    39
static int
icculus@10281
    40
ANDROIDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
paul@4718
    41
{
slouken@4995
    42
    SDL_AudioFormat test_format;
philipp@7130
    43
icculus@10280
    44
    SDL_assert((captureDevice == NULL) || !iscapture);
icculus@10280
    45
    SDL_assert((audioDevice == NULL) || iscapture);
icculus@10280
    46
slouken@4995
    47
    if (iscapture) {
icculus@10280
    48
        captureDevice = this;
icculus@10280
    49
    } else {
icculus@10280
    50
        audioDevice = this;
slouken@4995
    51
    }
slouken@4995
    52
gabomdq@9148
    53
    this->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *this->hidden));
gabomdq@9148
    54
    if (this->hidden == NULL) {
gabomdq@9148
    55
        return SDL_OutOfMemory();
gabomdq@9148
    56
    }
paul@4724
    57
slouken@4995
    58
    test_format = SDL_FirstAudioFormat(this->spec.format);
slouken@7191
    59
    while (test_format != 0) { /* no "UNKNOWN" constant */
slouken@4995
    60
        if ((test_format == AUDIO_U8) || (test_format == AUDIO_S16LSB)) {
slouken@4995
    61
            this->spec.format = test_format;
paul@4724
    62
            break;
paul@4724
    63
        }
slouken@4995
    64
        test_format = SDL_NextAudioFormat();
paul@4724
    65
    }
slouken@7191
    66
slouken@4995
    67
    if (test_format == 0) {
slouken@7191
    68
        /* Didn't find a compatible format :( */
slouken@7191
    69
        return SDL_SetError("No compatible audio format!");
slouken@4995
    70
    }
slouken@4995
    71
slouken@4995
    72
    if (this->spec.channels > 1) {
slouken@7191
    73
        this->spec.channels = 2;
slouken@4995
    74
    } else {
slouken@7191
    75
        this->spec.channels = 1;
slouken@4995
    76
    }
slouken@4995
    77
slouken@4995
    78
    if (this->spec.freq < 8000) {
slouken@7191
    79
        this->spec.freq = 8000;
slouken@4995
    80
    }
slouken@4995
    81
    if (this->spec.freq > 48000) {
slouken@7191
    82
        this->spec.freq = 48000;
slouken@4995
    83
    }
slouken@4995
    84
icculus@10280
    85
    /* TODO: pass in/return a (Java) device ID */
icculus@10280
    86
    this->spec.samples = Android_JNI_OpenAudioDevice(iscapture, this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples);
slouken@4995
    87
slouken@4995
    88
    if (this->spec.samples == 0) {
slouken@7191
    89
        /* Init failed? */
slouken@7191
    90
        return SDL_SetError("Java-side initialization failed!");
slouken@4995
    91
    }
slouken@4995
    92
icculus@10280
    93
    SDL_CalculateAudioSpec(&this->spec);
icculus@10280
    94
icculus@7038
    95
    return 0;
paul@4718
    96
}
paul@4718
    97
paul@4718
    98
static void
icculus@10281
    99
ANDROIDAUDIO_PlayDevice(_THIS)
paul@4718
   100
{
slouken@4996
   101
    Android_JNI_WriteAudioBuffer();
paul@4718
   102
}
paul@4718
   103
paul@4718
   104
static Uint8 *
icculus@10281
   105
ANDROIDAUDIO_GetDeviceBuf(_THIS)
paul@4718
   106
{
slouken@4996
   107
    return Android_JNI_GetAudioBuffer();
paul@4718
   108
}
paul@4718
   109
icculus@10280
   110
static int
icculus@10281
   111
ANDROIDAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
icculus@10280
   112
{
icculus@10280
   113
    return Android_JNI_CaptureAudioBuffer(buffer, buflen);
icculus@10280
   114
}
icculus@10280
   115
icculus@10280
   116
static void
icculus@10281
   117
ANDROIDAUDIO_FlushCapture(_THIS)
icculus@10280
   118
{
icculus@10280
   119
    Android_JNI_FlushCapturedAudio();
icculus@10280
   120
}
icculus@10280
   121
paul@4718
   122
static void
icculus@10281
   123
ANDROIDAUDIO_CloseDevice(_THIS)
paul@4718
   124
{
gabomdq@7612
   125
    /* At this point SDL_CloseAudioDevice via close_audio_device took care of terminating the audio thread
gabomdq@7612
   126
       so it's safe to terminate the Java side buffer and AudioTrack
gabomdq@7612
   127
     */
icculus@10280
   128
    Android_JNI_CloseAudioDevice(this->iscapture);
icculus@10280
   129
    if (this->iscapture) {
icculus@10280
   130
        SDL_assert(captureDevice == this);
icculus@10280
   131
        captureDevice = NULL;
icculus@10280
   132
    } else {
icculus@10280
   133
        SDL_assert(audioDevice == this);
slouken@7191
   134
        audioDevice = NULL;
slouken@4995
   135
    }
icculus@10280
   136
    SDL_free(this->hidden);
paul@4718
   137
}
paul@4718
   138
paul@4718
   139
static int
icculus@10281
   140
ANDROIDAUDIO_Init(SDL_AudioDriverImpl * impl)
paul@4718
   141
{
paul@4718
   142
    /* Set the function pointers */
icculus@10281
   143
    impl->OpenDevice = ANDROIDAUDIO_OpenDevice;
icculus@10281
   144
    impl->PlayDevice = ANDROIDAUDIO_PlayDevice;
icculus@10281
   145
    impl->GetDeviceBuf = ANDROIDAUDIO_GetDeviceBuf;
icculus@10281
   146
    impl->CloseDevice = ANDROIDAUDIO_CloseDevice;
icculus@10281
   147
    impl->CaptureFromDevice = ANDROIDAUDIO_CaptureFromDevice;
icculus@10281
   148
    impl->FlushCapture = ANDROIDAUDIO_FlushCapture;
paul@4718
   149
paul@4718
   150
    /* and the capabilities */
icculus@10280
   151
    impl->HasCaptureSupport = SDL_TRUE;
paul@4718
   152
    impl->OnlyHasDefaultOutputDevice = 1;
icculus@10258
   153
    impl->OnlyHasDefaultCaptureDevice = 1;
paul@4718
   154
paul@4718
   155
    return 1;   /* this audio target is available. */
paul@4718
   156
}
paul@4718
   157
icculus@10281
   158
AudioBootStrap ANDROIDAUDIO_bootstrap = {
icculus@10281
   159
    "android", "SDL Android audio driver", ANDROIDAUDIO_Init, 0
paul@4718
   160
};
paul@4718
   161
gabomdq@9148
   162
/* Pause (block) all non already paused audio devices by taking their mixer lock */
icculus@10281
   163
void ANDROIDAUDIO_PauseDevices(void)
gabomdq@9148
   164
{
gabomdq@9148
   165
    /* TODO: Handle multiple devices? */
gabomdq@9148
   166
    struct SDL_PrivateAudioData *private;
gabomdq@9148
   167
    if(audioDevice != NULL && audioDevice->hidden != NULL) {
gabomdq@9148
   168
        private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
icculus@10238
   169
        if (SDL_AtomicGet(&audioDevice->paused)) {
gabomdq@9148
   170
            /* The device is already paused, leave it alone */
gabomdq@9148
   171
            private->resume = SDL_FALSE;
gabomdq@9148
   172
        }
gabomdq@9148
   173
        else {
gabomdq@9148
   174
            SDL_LockMutex(audioDevice->mixer_lock);
icculus@10238
   175
            SDL_AtomicSet(&audioDevice->paused, 1);
gabomdq@9148
   176
            private->resume = SDL_TRUE;
gabomdq@9148
   177
        }
gabomdq@9148
   178
    }
icculus@10280
   179
icculus@10280
   180
    if(captureDevice != NULL && captureDevice->hidden != NULL) {
icculus@10280
   181
        private = (struct SDL_PrivateAudioData *) captureDevice->hidden;
icculus@10280
   182
        if (SDL_AtomicGet(&captureDevice->paused)) {
icculus@10280
   183
            /* The device is already paused, leave it alone */
icculus@10280
   184
            private->resume = SDL_FALSE;
icculus@10280
   185
        }
icculus@10280
   186
        else {
icculus@10280
   187
            SDL_LockMutex(captureDevice->mixer_lock);
icculus@10280
   188
            SDL_AtomicSet(&captureDevice->paused, 1);
icculus@10280
   189
            private->resume = SDL_TRUE;
icculus@10280
   190
        }
icculus@10280
   191
    }
gabomdq@9148
   192
}
gabomdq@9148
   193
gabomdq@9148
   194
/* Resume (unblock) all non already paused audio devices by releasing their mixer lock */
icculus@10281
   195
void ANDROIDAUDIO_ResumeDevices(void)
gabomdq@9148
   196
{
gabomdq@9148
   197
    /* TODO: Handle multiple devices? */
gabomdq@9148
   198
    struct SDL_PrivateAudioData *private;
gabomdq@9148
   199
    if(audioDevice != NULL && audioDevice->hidden != NULL) {
gabomdq@9148
   200
        private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
gabomdq@9148
   201
        if (private->resume) {
icculus@10238
   202
            SDL_AtomicSet(&audioDevice->paused, 0);
gabomdq@9148
   203
            private->resume = SDL_FALSE;
gabomdq@9148
   204
            SDL_UnlockMutex(audioDevice->mixer_lock);
gabomdq@9148
   205
        }
gabomdq@9148
   206
    }
icculus@10280
   207
icculus@10280
   208
    if(captureDevice != NULL && captureDevice->hidden != NULL) {
icculus@10280
   209
        private = (struct SDL_PrivateAudioData *) captureDevice->hidden;
icculus@10280
   210
        if (private->resume) {
icculus@10280
   211
            SDL_AtomicSet(&captureDevice->paused, 0);
icculus@10280
   212
            private->resume = SDL_FALSE;
icculus@10280
   213
            SDL_UnlockMutex(captureDevice->mixer_lock);
icculus@10280
   214
        }
icculus@10280
   215
    }
gabomdq@9148
   216
}
gabomdq@9148
   217
slouken@10672
   218
#else 
slouken@10672
   219
slouken@10672
   220
void ANDROIDAUDIO_ResumeDevices(void) {}
slouken@10672
   221
void ANDROIDAUDIO_PauseDevices(void) {}
gabomdq@9148
   222
slouken@6044
   223
#endif /* SDL_AUDIO_DRIVER_ANDROID */
slouken@6044
   224
paul@4718
   225
/* vi: set ts=4 sw=4 expandtab: */
gabomdq@7612
   226