static int init(struct ao *ao) { if (SDL_WasInit(SDL_INIT_AUDIO)) { mp_msg(MSGT_AO, MSGL_ERR, "[sdl] already initialized\n"); return -1; } struct priv *priv = ao->priv; if (SDL_InitSubSystem(SDL_INIT_AUDIO)) { if (!ao->probing) mp_msg(MSGT_AO, MSGL_ERR, "[sdl] SDL_Init failed\n"); uninit(ao, true); return -1; } struct mp_chmap_sel sel = {0}; mp_chmap_sel_add_waveext_def(&sel); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) { uninit(ao, true); return -1; } SDL_AudioSpec desired, obtained; switch (ao->format) { case AF_FORMAT_U8: desired.format = AUDIO_U8; break; case AF_FORMAT_S8: desired.format = AUDIO_S8; break; case AF_FORMAT_U16_LE: desired.format = AUDIO_U16LSB; break; case AF_FORMAT_U16_BE: desired.format = AUDIO_U16MSB; break; default: case AF_FORMAT_S16_LE: desired.format = AUDIO_S16LSB; break; case AF_FORMAT_S16_BE: desired.format = AUDIO_S16MSB; break; #ifdef AUDIO_S32LSB case AF_FORMAT_S32_LE: desired.format = AUDIO_S32LSB; break; #endif #ifdef AUDIO_S32MSB case AF_FORMAT_S32_BE: desired.format = AUDIO_S32MSB; break; #endif #ifdef AUDIO_F32LSB case AF_FORMAT_FLOAT_LE: desired.format = AUDIO_F32LSB; break; #endif #ifdef AUDIO_F32MSB case AF_FORMAT_FLOAT_BE: desired.format = AUDIO_F32MSB; break; #endif } desired.freq = ao->samplerate; desired.channels = ao->channels.num; desired.samples = FFMIN(32768, ceil_power_of_two(ao->samplerate * priv->buflen)); desired.callback = audio_callback; desired.userdata = ao; mp_msg(MSGT_AO, MSGL_V, "[sdl] requested format: %d Hz, %d channels, %x, " "buffer size: %d samples\n", (int) desired.freq, (int) desired.channels, (int) desired.format, (int) desired.samples); obtained = desired; if (SDL_OpenAudio(&desired, &obtained)) { if (!ao->probing) mp_msg(MSGT_AO, MSGL_ERR, "[sdl] could not open audio: %s\n", SDL_GetError()); uninit(ao, true); return -1; } mp_msg(MSGT_AO, MSGL_V, "[sdl] obtained format: %d Hz, %d channels, %x, " "buffer size: %d samples\n", (int) obtained.freq, (int) obtained.channels, (int) obtained.format, (int) obtained.samples); switch (obtained.format) { case AUDIO_U8: ao->format = AF_FORMAT_U8; break; case AUDIO_S8: ao->format = AF_FORMAT_S8; break; case AUDIO_S16LSB: ao->format = AF_FORMAT_S16_LE; break; case AUDIO_S16MSB: ao->format = AF_FORMAT_S16_BE; break; case AUDIO_U16LSB: ao->format = AF_FORMAT_U16_LE; break; case AUDIO_U16MSB: ao->format = AF_FORMAT_U16_BE; break; #ifdef AUDIO_S32LSB case AUDIO_S32LSB: ao->format = AF_FORMAT_S32_LE; break; #endif #ifdef AUDIO_S32MSB case AUDIO_S32MSB: ao->format = AF_FORMAT_S32_BE; break; #endif #ifdef AUDIO_F32LSB case AUDIO_F32LSB: ao->format = AF_FORMAT_FLOAT_LE; break; #endif #ifdef AUDIO_F32MSB case AUDIO_F32MSB: ao->format = AF_FORMAT_FLOAT_BE; break; #endif default: if (!ao->probing) mp_msg(MSGT_AO, MSGL_ERR, "[sdl] could not find matching format\n"); uninit(ao, true); return -1; } if (!ao_chmap_sel_get_def(ao, &sel, &ao->channels, obtained.channels)) { uninit(ao, true); return -1; } ao->samplerate = obtained.freq; priv->buffer = av_fifo_alloc(obtained.size * priv->bufcnt); priv->buffer_mutex = SDL_CreateMutex(); if (!priv->buffer_mutex) { mp_msg(MSGT_AO, MSGL_ERR, "[sdl] SDL_CreateMutex failed\n"); uninit(ao, true); return -1; } priv->underrun_cond = SDL_CreateCond(); if (!priv->underrun_cond) { mp_msg(MSGT_AO, MSGL_ERR, "[sdl] SDL_CreateCond failed\n"); uninit(ao, true); return -1; } priv->unpause = 1; priv->paused = 1; priv->callback_time0 = priv->callback_time1 = mp_time_us(); return 1; }
static int init(struct ao *ao) { if (SDL_WasInit(SDL_INIT_AUDIO)) { MP_ERR(ao, "already initialized\n"); return -1; } struct priv *priv = ao->priv; if (SDL_InitSubSystem(SDL_INIT_AUDIO)) { if (!ao->probing) MP_ERR(ao, "SDL_Init failed\n"); uninit(ao); return -1; } struct mp_chmap_sel sel = {0}; mp_chmap_sel_add_waveext_def(&sel); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) { uninit(ao); return -1; } ao->format = af_fmt_from_planar(ao->format); SDL_AudioSpec desired, obtained; desired.format = AUDIO_S16SYS; for (int n = 0; fmtmap[n][0]; n++) { if (ao->format == fmtmap[n][0]) { desired.format = fmtmap[n][1]; break; } } desired.freq = ao->samplerate; desired.channels = ao->channels.num; desired.samples = MPMIN(32768, ceil_power_of_two(ao->samplerate * priv->buflen)); desired.callback = audio_callback; desired.userdata = ao; MP_VERBOSE(ao, "requested format: %d Hz, %d channels, %x, " "buffer size: %d samples\n", (int) desired.freq, (int) desired.channels, (int) desired.format, (int) desired.samples); obtained = desired; if (SDL_OpenAudio(&desired, &obtained)) { if (!ao->probing) MP_ERR(ao, "could not open audio: %s\n", SDL_GetError()); uninit(ao); return -1; } MP_VERBOSE(ao, "obtained format: %d Hz, %d channels, %x, " "buffer size: %d samples\n", (int) obtained.freq, (int) obtained.channels, (int) obtained.format, (int) obtained.samples); // The sample count is usually the number of samples the callback requests, // which we assume is the period size. Normally, ao.c will allocate a large // enough buffer. But in case the period size should be pathologically // large, this will help. ao->device_buffer = 3 * obtained.samples; ao->format = 0; for (int n = 0; fmtmap[n][0]; n++) { if (obtained.format == fmtmap[n][1]) { ao->format = fmtmap[n][0]; break; } } if (!ao->format) { if (!ao->probing) MP_ERR(ao, "could not find matching format\n"); uninit(ao); return -1; } if (!ao_chmap_sel_get_def(ao, &sel, &ao->channels, obtained.channels)) { uninit(ao); return -1; } ao->samplerate = obtained.freq; priv->paused = 1; return 1; }