ALURE support has been enabled.
[platform/core/api/sound-pool.git] / src / source.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * @file source.c
19  * @brief This file include implementation of protected API
20  * for the sound sources(OpenAL buffers) as part of SoundPool.
21  */
22
23 #include "internal/source.h"
24 #include "internal/stream.h"
25
26 #include <AL/alut.h>
27 #ifdef ENABLE_ALURE
28 #       include <AL/alure.h>
29 #endif
30
31 static int __sound_pool_add_source(sound_pool_t *pool, sound_source_t *src);
32 static int __sound_pool_remove_source(sound_pool_t *pool, sound_source_t *src);
33
34 static int __sound_pool_add_source(sound_pool_t *pool, sound_source_t *src)
35 {
36         SP_DEBUG_FENTER();
37         SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
38         SP_INST_CHECK(src, SOUND_POOL_ERROR_INVALID_PARAMETER);
39         SP_RETVM_IF(!pool->sources, SOUND_POOL_ERROR_INVALID_OPERATION, "Sound "
40                         "pool to add the source is corrupted: NULL sources hash table");
41         SP_RETVM_IF(!src->tag_name, SOUND_POOL_ERROR_INVALID_OPERATION,
42                         "Source to be added to sound pool is corrupted: NULL tag name");
43         SP_RETVM_IF(src->parent_pool != pool, SOUND_POOL_ERROR_INVALID_OPERATION,
44                         "Sound source can't be added to the pool different to the pool for"
45                         " which sound source was created");
46         SP_RETVM_IF(g_hash_table_contains(pool->sources, src->tag_name),
47                         SOUND_POOL_ERROR_INVALID_PARAMETER,
48                         "Tag already exists in sources hash table.");
49
50         SP_RETVM_IF(!g_hash_table_insert(pool->sources, src->tag_name, src),
51                         SOUND_POOL_ERROR_INVALID_OPERATION, "Error occurred when adding "
52                         "the source tagged [%s] to the sound pool", src->tag_name);
53
54         SP_DEBUG_FLEAVE();
55         return SOUND_POOL_ERROR_NONE;
56 }
57
58 static int __sound_pool_remove_source(sound_pool_t *pool, sound_source_t *src)
59 {
60         SP_DEBUG_FENTER();
61         SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
62         SP_INST_CHECK(pool->sources, SOUND_POOL_ERROR_INVALID_PARAMETER);
63         SP_INST_CHECK(src, SOUND_POOL_ERROR_INVALID_PARAMETER);
64
65         if (src->parent_pool == pool && src->tag_name) {
66                 if (!g_hash_table_steal(pool->sources, src->tag_name)) {
67                         SP_DEBUG("Tag [%s] doesn't exist in sources hash table",
68                                         src->tag_name);
69                         SP_DEBUG_FLEAVE();
70                         return SOUND_POOL_ERROR_NONE;
71                 }
72                 GHashTableIter iter;
73                 gpointer key, value;
74                 g_hash_table_iter_init(&iter, pool->streams);
75                 while (g_hash_table_iter_next(&iter, &key, &value)) {
76                         guint size_before = g_hash_table_size(pool->streams);
77                         gchar *tag = (gchar*)key;
78                         sound_stream_t *stream = (sound_stream_t*)value;
79                         if (src == stream->parent_source)
80                                 _sound_stream_destroy((sound_stream_t*)value);
81                         guint size_after = g_hash_table_size(pool->streams);
82                         if (size_before != size_after)
83                                 g_hash_table_iter_init(&iter, pool->streams);
84                 }
85         } else {
86                         SP_DEBUG("Source wasn't removed from sound pool as it isn't known by "
87                                         "the pool for which operation is performed, or tag corrupted");
88         }
89
90         SP_DEBUG_FLEAVE();
91         return SOUND_POOL_ERROR_NONE;
92 }
93
94 sound_pool_error_e _sound_source_create(sound_pool_t *pool, const char *tag,
95                 sound_source_t **src)
96 {
97         SP_DEBUG_FENTER();
98         SP_RETVM_IF(!pool, SOUND_POOL_ERROR_INVALID_PARAMETER,
99                         "Can't create sound source in NULL sound pool");
100         SP_RETVM_IF(!tag, SOUND_POOL_ERROR_INVALID_PARAMETER,
101                         "Can't create sound source with NULL tag name");
102         SP_RETVM_IF(!src, SOUND_POOL_ERROR_INVALID_PARAMETER,
103                         "Can't create sound source. Source pointer is NULL");
104         SP_RETVM_IF(strnlen(tag, MAX_TAG_LEN + 1) == MAX_TAG_LEN + 1,
105                         SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't create sound source "
106                         "with tag name longer than %u", MAX_TAG_LEN);
107         SP_RETVM_IF(!pool->sources, SOUND_POOL_ERROR_INVALID_OPERATION, "Sound "
108                         "pool to create source is corrupted: NULL sources hash table.");
109         SP_RETVM_IF(g_hash_table_contains(pool->sources, tag),
110                         SOUND_POOL_ERROR_INVALID_PARAMETER,
111                         "Tag already exists in sources hash table.");
112
113         SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
114                         SOUND_POOL_ERROR_INVALID_OPERATION,
115                         "Can't set current context.");
116
117         sound_source_t *_src = NULL;
118         SP_RETVM_IF(!(_src = g_try_malloc0(sizeof(*_src))),
119                         SOUND_POOL_ERROR_OUT_OF_MEMORY,
120                         "Memory alloc failure. Can't create sound _src");
121
122         sound_pool_error_e ret = SOUND_POOL_ERROR_NONE;
123         alGenBuffers(1, &_src->al_buffer);
124         if (alGetError() != AL_NO_ERROR) {
125                 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
126                 GOTO_FAIL("OpenAL error occurred when trying to generate Buffer id", cfail);
127         }
128
129         _src->parent_pool = pool;
130         _src->tag_name = NULL;
131         _src->tag_name = g_strndup(tag, MAX_TAG_LEN);
132
133         ret = __sound_pool_add_source(pool, _src);
134         if (ret != SOUND_POOL_ERROR_NONE)
135                 GOTO_FAIL("Error occurred when trying to add source to pool", cfail);
136
137         *src = _src;
138         SP_DEBUG_FLEAVE();
139         return ret;
140
141 cfail:
142         ret = _sound_source_destroy(_src);
143         SP_RETVM_IF(SOUND_POOL_ERROR_NONE != ret, ret, "Error occurred during removal "
144                         "of sound source[%s].", tag);
145         SP_DEBUG_FLEAVE();
146         return ret;
147 }
148
149 sound_pool_error_e _sound_source_destroy(sound_source_t *src)
150 {
151         SP_DEBUG_FENTER();
152         SP_RETVM_IF(!src, SOUND_POOL_ERROR_INVALID_PARAMETER,
153                         "Can't destroy NULL sound source");
154
155         /* If parent pool exists, then source has to be removed from the pool */
156         if (src->parent_pool && __sound_pool_remove_source(src->parent_pool, src)
157                         != SOUND_POOL_ERROR_NONE)
158                 SP_DEBUG("Source wasn't removed from sound pool.");
159
160         SP_DEBUG("Deleting OpenAL buffer with id [%u]", src->al_buffer);
161         alDeleteBuffers(1, &src->al_buffer);
162
163         SP_SAFE_GFREE(src->tag_name);
164         SP_SAFE_GFREE(src);
165
166         SP_DEBUG_FLEAVE();
167         return SOUND_POOL_ERROR_NONE;
168 }
169
170 sound_pool_error_e _sound_source_load_from_file(sound_source_t *src,
171                 const char *fname)
172 {
173         SP_DEBUG_FENTER();
174         SP_INST_CHECK(src, SOUND_POOL_ERROR_INVALID_PARAMETER);
175         SP_INST_CHECK(fname, SOUND_POOL_ERROR_INVALID_PARAMETER);
176         SP_INST_CHECK(src->parent_pool, SOUND_POOL_ERROR_INVALID_OPERATION);
177         SP_RETVM_IF(!alcMakeContextCurrent(src->parent_pool->al_context),
178                         SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current AL context.");
179
180         sound_pool_error_e ret = SOUND_POOL_ERROR_NONE;
181         ALenum format;
182         ALsizei size;
183         ALvoid* data = NULL;
184         ALsizei freq;
185         ALboolean loop;
186
187         alutLoadWAVFile((ALbyte*)fname, &format, &data, &size, &freq, &loop);
188
189 #ifdef ENABLE_ALURE
190         if (alGetError() != AL_NO_ERROR || !data) {
191                 if (alureBufferDataFromFile(fname, src->al_buffer) == AL_FALSE) {
192                         src->al_buffer = AL_NONE;
193                         SP_ERROR("Can't load audio file. No such file [%s]", fname);
194                         ret = SOUND_POOL_ERROR_NO_SUCH_FILE;
195                 }
196                 SP_DEBUG_FLEAVE();
197                 return ret;
198         }
199 #else
200         SP_RETVM_IF(alGetError() != AL_NO_ERROR || !data,
201                         SOUND_POOL_ERROR_NO_SUCH_FILE, "Can't load audio file. No such "
202                         "file [%s]", fname);
203 #endif
204
205         alBufferData(src->al_buffer, format, data, size, freq);
206         if (alGetError() != AL_NO_ERROR) {
207                 SP_ERROR("Can't create audio buffer from file [%s]", fname);
208                 ret = SOUND_POOL_ERROR_INVALID_OPERATION;
209         }
210
211         alutUnloadWAV(format, data, size, freq);
212
213         SP_DEBUG_FLEAVE();
214         return ret;
215 }
216
217 sound_pool_error_e _sound_pool_get_source_by_tag(sound_pool_t *pool,
218                 const char *tag, sound_source_t **src)
219 {
220         SP_DEBUG_FENTER();
221         SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
222         SP_INST_CHECK(tag, SOUND_POOL_ERROR_INVALID_PARAMETER);
223         SP_INST_CHECK(src, SOUND_POOL_ERROR_INVALID_PARAMETER);
224         SP_RETVM_IF(!pool->sources, SOUND_POOL_ERROR_INVALID_PARAMETER, "Corrupted "
225                         "sound pool. Sources hash table is NULL");
226
227         *src = (sound_source_t *)g_hash_table_lookup(pool->sources, tag);
228         SP_RETVM_IF(!(*src), SOUND_POOL_ERROR_KEY_NOT_AVAILABLE, "Tag doesn't "
229                         "exist in sources hash table");
230
231         SP_DEBUG_FLEAVE();
232         return SOUND_POOL_ERROR_NONE;
233 }