| | 1 | /** |
| | 2 | * OpenAL cross platform audio library |
| | 3 | * Copyright (C) 1999-2007 by authors. |
| | 4 | * This library is free software; you can redistribute it and/or |
| | 5 | * modify it under the terms of the GNU Library General Public |
| | 6 | * License as published by the Free Software Foundation; either |
| | 7 | * version 2 of the License, or (at your option) any later version. |
| | 8 | * |
| | 9 | * This library is distributed in the hope that it will be useful, |
| | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | 12 | * Library General Public License for more details. |
| | 13 | * |
| | 14 | * You should have received a copy of the GNU Library General Public |
| | 15 | * License along with this library; if not, write to the |
| | 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| | 17 | * Boston, MA 02111-1307, USA. |
| | 18 | * Or go to http://www.gnu.org/copyleft/lgpl.html |
| | 19 | */ |
| | 20 | |
| | 21 | #include "config.h" |
| | 22 | |
| | 23 | #include <sys/ioctl.h> |
| | 24 | #include <sys/types.h> |
| | 25 | #include <sys/stat.h> |
| | 26 | #include <fcntl.h> |
| | 27 | #include <stdlib.h> |
| | 28 | #include <stdio.h> |
| | 29 | #include <memory.h> |
| | 30 | #include <unistd.h> |
| | 31 | #include <errno.h> |
| | 32 | #include <math.h> |
| | 33 | |
| | 34 | #include "alMain.h" |
| | 35 | #include "AL/al.h" |
| | 36 | #include "AL/alc.h" |
| | 37 | |
| | 38 | #include <Application.h> |
| | 39 | #include <SoundPlayer.h> |
| | 40 | #include <signal.h> |
| | 41 | #include <OS.h> |
| | 42 | |
| | 43 | static const ALCchar haiku_device[] = "Haiku Software"; |
| | 44 | |
| | 45 | typedef struct { |
| | 46 | BSoundPlayer *player; |
| | 47 | ALCdevice *device; |
| | 48 | } haiku_data; |
| | 49 | |
| | 50 | static void |
| | 51 | BufferProc(void *theCookie, void *buffer, size_t size, |
| | 52 | const media_raw_audio_format &format) { |
| | 53 | |
| | 54 | haiku_data *data = (haiku_data *) theCookie; |
| | 55 | |
| | 56 | if (!data) { |
| | 57 | memset(buffer, size, 0); // fill with silence cookie bad |
| | 58 | return; |
| | 59 | } |
| | 60 | |
| | 61 | if (!data->device) { |
| | 62 | memset(buffer, size, 0); // fill with silence device not setup |
| | 63 | return; |
| | 64 | } |
| | 65 | |
| | 66 | if (data->device->Connected) { |
| | 67 | if (data->device->UpdateSize >= size) { |
| | 68 | // Now fill the buffer with sound! |
| | 69 | aluMixData(data->device, buffer, size); |
| | 70 | } else { |
| | 71 | memset(buffer, size, 0); // fill with silence not enough data for a buffer |
| | 72 | } |
| | 73 | } else { |
| | 74 | memset(buffer, size, 0); // fill with silence device not connected |
| | 75 | } |
| | 76 | } |
| | 77 | |
| | 78 | static ALCboolean haiku_open_playback(ALCdevice *device, const ALCchar *deviceName) |
| | 79 | { |
| | 80 | haiku_data *data; |
| | 81 | |
| | 82 | if (!deviceName) |
| | 83 | deviceName = haiku_device; |
| | 84 | else if (strcmp(deviceName, haiku_device) != 0) |
| | 85 | return ALC_FALSE; |
| | 86 | |
| | 87 | data = (haiku_data*)calloc(1, sizeof(haiku_data)); |
| | 88 | |
| | 89 | data->device = device; |
| | 90 | |
| | 91 | device->szDeviceName = strdup(deviceName); |
| | 92 | device->ExtraData = data; |
| | 93 | |
| | 94 | return ALC_TRUE; |
| | 95 | } |
| | 96 | |
| | 97 | static void haiku_close_playback(ALCdevice *device) |
| | 98 | { |
| | 99 | haiku_data *data = (haiku_data*)device->ExtraData; |
| | 100 | |
| | 101 | data->device = NULL; |
| | 102 | |
| | 103 | if (data->player) { |
| | 104 | data->player->Stop(); |
| | 105 | delete data->player; |
| | 106 | data->player = NULL; |
| | 107 | } |
| | 108 | |
| | 109 | free(data); |
| | 110 | device->ExtraData = NULL; |
| | 111 | } |
| | 112 | |
| | 113 | static ALCboolean haiku_reset_playback(ALCdevice *device) |
| | 114 | { |
| | 115 | haiku_data *data = (haiku_data*)device->ExtraData; |
| | 116 | ALuint frameSize; |
| | 117 | int numChannels; |
| | 118 | |
| | 119 | numChannels = aluChannelsFromFormat(device->Format); |
| | 120 | frameSize = numChannels * aluBytesFromFormat(device->Format); |
| | 121 | |
| | 122 | media_raw_audio_format format; |
| | 123 | format = media_raw_audio_format::wildcard; |
| | 124 | format.frame_rate = device->Frequency; |
| | 125 | format.channel_count = numChannels; |
| | 126 | |
| | 127 | switch(aluBytesFromFormat(device->Format)) { |
| | 128 | case 1: |
| | 129 | format.format = media_raw_audio_format::B_AUDIO_UCHAR; // port audio suggests uchar |
| | 130 | format.byte_order = B_MEDIA_LITTLE_ENDIAN; // Not relevant for single byte types |
| | 131 | break; |
| | 132 | case 2: |
| | 133 | format.format = media_raw_audio_format::B_AUDIO_SHORT; |
| | 134 | format.byte_order = B_MEDIA_LITTLE_ENDIAN; // Important here but this is a guess |
| | 135 | break; |
| | 136 | case 4: |
| | 137 | format.format = media_raw_audio_format::B_AUDIO_FLOAT; |
| | 138 | format.byte_order = B_MEDIA_LITTLE_ENDIAN; // Important here but this is a guess |
| | 139 | break; |
| | 140 | default: |
| | 141 | return ALC_FALSE; |
| | 142 | } |
| | 143 | |
| | 144 | format.buffer_size = device->UpdateSize * device->NumUpdates * frameSize; |
| | 145 | |
| | 146 | printf("Setup format of Rate(%.0f) Channels (%ld) ByteSize(%d) Buffer(%ld)\n", |
| | 147 | format.frame_rate, format.channel_count, aluBytesFromFormat(device->Format), format.buffer_size); |
| | 148 | |
| | 149 | data->player = new BSoundPlayer(&format, "ALplayer", BufferProc, NULL, &data); |
| | 150 | data->player->SetVolume(1.0); |
| | 151 | data->player->SetHasData(true); |
| | 152 | data->player->Start(); |
| | 153 | |
| | 154 | return ALC_TRUE; |
| | 155 | } |
| | 156 | |
| | 157 | static void haiku_stop_playback(ALCdevice *device) |
| | 158 | { |
| | 159 | haiku_data *data = (haiku_data*)device->ExtraData; |
| | 160 | |
| | 161 | if (!data->player) |
| | 162 | return; |
| | 163 | |
| | 164 | data->player->Stop(); |
| | 165 | delete data->player; |
| | 166 | data->player = NULL; |
| | 167 | } |
| | 168 | |
| | 169 | |
| | 170 | static ALCboolean haiku_open_capture(ALCdevice *device, const ALCchar *deviceName) |
| | 171 | { |
| | 172 | (void)device; |
| | 173 | (void)deviceName; |
| | 174 | return ALC_FALSE; |
| | 175 | } |
| | 176 | |
| | 177 | static void haiku_close_capture(ALCdevice *device) |
| | 178 | { |
| | 179 | (void)device; |
| | 180 | } |
| | 181 | |
| | 182 | static void haiku_start_capture(ALCdevice *pDevice) |
| | 183 | { |
| | 184 | (void)pDevice; |
| | 185 | } |
| | 186 | |
| | 187 | static void haiku_stop_capture(ALCdevice *pDevice) |
| | 188 | { |
| | 189 | (void)pDevice; |
| | 190 | } |
| | 191 | |
| | 192 | static void haiku_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples) |
| | 193 | { |
| | 194 | (void)pDevice; |
| | 195 | (void)pBuffer; |
| | 196 | (void)lSamples; |
| | 197 | } |
| | 198 | |
| | 199 | static ALCuint haiku_available_samples(ALCdevice *pDevice) |
| | 200 | { |
| | 201 | (void)pDevice; |
| | 202 | return 0; |
| | 203 | } |
| | 204 | |
| | 205 | BackendFuncs haiku_funcs = { |
| | 206 | haiku_open_playback, |
| | 207 | haiku_close_playback, |
| | 208 | haiku_reset_playback, |
| | 209 | haiku_stop_playback, |
| | 210 | haiku_open_capture, |
| | 211 | haiku_close_capture, |
| | 212 | haiku_start_capture, |
| | 213 | haiku_stop_capture, |
| | 214 | haiku_capture_samples, |
| | 215 | haiku_available_samples |
| | 216 | }; |
| | 217 | |
| | 218 | void alc_haiku_init(BackendFuncs *func_list) |
| | 219 | { |
| | 220 | /* BSoundPlayer requires a BApplication object */ |
| | 221 | new BApplication("application/x-vnd.ALplayer"); |
| | 222 | |
| | 223 | *func_list = haiku_funcs; |
| | 224 | } |
| | 225 | |
| | 226 | void alc_haiku_deinit(void) |
| | 227 | { |
| | 228 | } |
| | 229 | |
| | 230 | void alc_haiku_probe(int type) |
| | 231 | { |
| | 232 | #ifdef HAVE_STAT |
| | 233 | struct stat buf; |
| | 234 | if(stat(GetConfigValue("haiku", "device", "/dev/audio"), &buf) != 0) |
| | 235 | return; |
| | 236 | #endif |
| | 237 | |
| | 238 | if(type == DEVICE_PROBE) |
| | 239 | AppendDeviceList(haiku_device); |
| | 240 | else if(type == ALL_DEVICE_PROBE) |
| | 241 | AppendAllDeviceList(haiku_device); |
| | 242 | } |