4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Seungbae Shin <seungbae.shin@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
32 #include "include/mm_sound_common.h"
36 #define PULSEAUDIO_READY "/tmp/.pulseaudio_ready"
39 #define PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_PLAY "SimplePlay"
40 #define PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP "SimpleStop"
41 #define PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP_ALL "SimpleStopAll"
43 #define AUDIO_VOLUME_CONFIG_TYPE(vol) (vol & 0x00FF)
44 #define AUDIO_VOLUME_CONFIG_GAIN(vol) (vol & 0xFF00)
46 #define USE_PIPE /* default is pipe now */
50 #define KEYTONE_PATH "/tmp/keytone"
51 #define FILENAME_LEN 1024
53 #define VOLUME_GAIN_TYPE_LEN 32
56 #define MAX_WRITE_RETRY 50
57 #define WRITE_RETRY_INTERVAL_MS 20
59 typedef struct ipc_data {
60 char filename[FILENAME_LEN];
62 char volume_gain_type[VOLUME_GAIN_TYPE_LEN];
63 char method[METHOD_LEN];
66 static int __mm_sound_simple_pipe(const char *filename, int volume_config, const char *method);
70 #define PA_BUS_NAME "org.pulseaudio.Server"
71 #define PA_SOUND_PLAYER_OBJECT_PATH "/org/pulseaudio/SoundPlayer"
72 #define PA_SOUND_PLAYER_INTERFACE "org.pulseaudio.SoundPlayer"
73 #define PA_SOUND_RESPONSE_TIMEOUT 2000
75 static int __mm_sound_simple_dbus(const char *filename, int volume_config, const char *method);
78 static const char* __convert_volume_type_to_role(int volume_type)
80 debug_log("volume_type(%d)", volume_type);
81 switch (volume_type) {
82 case VOLUME_TYPE_MEDIA:
84 case VOLUME_TYPE_SYSTEM:
86 case VOLUME_TYPE_NOTIFICATION:
87 return "notification";
88 case VOLUME_TYPE_ALARM:
90 case VOLUME_TYPE_VOICE:
92 case VOLUME_TYPE_RINGTONE:
93 return "ringtone-call";
95 debug_warning("not supported type(%d), we change it SYSTEM type forcibly", volume_type);
100 static const char* __convert_volume_gain_type_to_string(int volume_gain_type)
102 debug_log("volume_gain_type(0x%x)", volume_gain_type);
103 switch (volume_gain_type) {
104 case VOLUME_GAIN_DEFAULT:
106 case VOLUME_GAIN_DIALER:
108 case VOLUME_GAIN_TOUCH:
112 case VOLUME_GAIN_SHUTTER1:
114 case VOLUME_GAIN_SHUTTER2:
116 case VOLUME_GAIN_CAMCORDING:
118 case VOLUME_GAIN_MIDI:
120 case VOLUME_GAIN_BOOTING:
122 case VOLUME_GAIN_VIDEO:
124 case VOLUME_GAIN_TTS:
132 int mm_sound_play_keysound(const char *filename, int volume_config)
135 return __mm_sound_simple_pipe(filename, volume_config, PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_PLAY);
137 return __mm_sound_simple_dbus(filename, volume_config, PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_PLAY);
142 int mm_sound_stop_keysound(const char *filename)
145 return __mm_sound_simple_pipe(filename, 0,
146 (filename) ? PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP : PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP_ALL);
148 return __mm_sound_simple_dbus(filename, 0,
149 (filename) ? PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP : PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP_ALL);
154 static bool _mm_sound_check_pa_ready()
157 static bool is_pa_ready = false;
162 debug_msg("LwipcIsDone start >> ");
163 ret = LwipcIsDone(PULSEAUDIO_READY);
164 debug_msg("LwipcIsDone end << %d", ret);
166 is_pa_ready = (ret > 0) ? true : false;
172 static int __verify_input_file(const char *filename)
175 return MM_ERROR_SOUND_INVALID_FILE;
177 /* Check whether file exists */
178 if (access(filename, F_OK) == -1) {
181 strerror_r(errno, str_error, sizeof(str_error));
182 debug_error("file [%s] doesn't exists : [%s][%d]", filename, str_error, errno);
184 return MM_ERROR_SOUND_FILE_NOT_FOUND;
187 return MM_ERROR_NONE;
191 static int __mm_sound_simple_pipe(const char *filename, int volume_config, const char *method)
193 int ret = MM_ERROR_NONE;
194 int retry_remaining = MAX_WRITE_RETRY;
195 size_t size_to_write = sizeof(ipc_t);
201 if (!_mm_sound_check_pa_ready()) {
202 debug_error("Pulseaudio is not ready!");
203 return MM_ERROR_SOUND_INVALID_STATE;
208 return MM_ERROR_INVALID_ARGUMENT;
210 /* Prepare data to be send */
211 g_strlcpy(data.method, method, METHOD_LEN);
213 if (g_strcmp0(method, PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP_ALL) != 0) {
214 ret = __verify_input_file(filename);
215 if (ret != MM_ERROR_NONE)
218 g_strlcpy(data.filename, filename, FILENAME_LEN);
221 if (g_strcmp0(method, PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_PLAY) == 0) {
223 __convert_volume_type_to_role(AUDIO_VOLUME_CONFIG_TYPE(volume_config)),
225 g_strlcpy(data.volume_gain_type,
226 __convert_volume_gain_type_to_string(AUDIO_VOLUME_CONFIG_GAIN(volume_config)),
227 VOLUME_GAIN_TYPE_LEN);
230 debug_msg("filepath=[%s], role=[%s], volume_gain_type=[%s], method=[%s]",
231 data.filename, data.role, data.volume_gain_type, data.method);
234 fd = open(KEYTONE_PATH, O_WRONLY | O_NONBLOCK);
238 strerror_r(errno, str_error, sizeof(str_error));
239 debug_error("Fail to open pipe: [%s][%d]", str_error, errno);
241 return MM_ERROR_SOUND_INTERNAL;
246 written = write(fd, &data, size_to_write);
251 strerror_r(errsv, str_error, sizeof(str_error));
252 debug_error("[%d] Fail to write, written = %zd, [%s][%d]",
253 MAX_WRITE_RETRY - retry_remaining, written, str_error, errsv);
255 if (errsv != EAGAIN || --retry_remaining == 0) {
256 ret = MM_ERROR_SOUND_INTERNAL;
260 usleep(WRITE_RETRY_INTERVAL_MS * 1000);
261 } else if (retry_remaining != MAX_WRITE_RETRY) {
262 debug_msg("retry success!!");
264 } while (written != size_to_write);
273 static int __mm_sound_simple_dbus(const char *filename, int volume_config, const char *method)
275 int ret = MM_ERROR_NONE;
276 const char *role = NULL;
277 const char *vol_gain_type = NULL;
278 GVariant *result = NULL;
279 GDBusConnection *conn = NULL;
284 if (!_mm_sound_check_pa_ready()) {
285 debug_error("Pulseaudio is not ready!");
286 return MM_ERROR_SOUND_INVALID_STATE;
290 return MM_ERROR_INVALID_ARGUMENT;
292 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
294 debug_error("g_bus_get_sync() error (%s)", err ? err->message : NULL);
296 return MM_ERROR_SOUND_INTERNAL;
299 if (g_strcmp0(method, PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_PLAY) == 0) {
300 ret = __verify_input_file(filename);
301 if (ret != MM_ERROR_NONE)
304 role = __convert_volume_type_to_role(AUDIO_VOLUME_CONFIG_TYPE(volume_config));
305 vol_gain_type = __convert_volume_gain_type_to_string(AUDIO_VOLUME_CONFIG_GAIN(volume_config));
307 result = g_dbus_connection_call_sync(conn, PA_BUS_NAME,
308 PA_SOUND_PLAYER_OBJECT_PATH,
309 PA_SOUND_PLAYER_INTERFACE,
310 PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_PLAY,
311 g_variant_new("(sss)", filename, role, vol_gain_type),
312 NULL, G_DBUS_CALL_FLAGS_NONE, PA_SOUND_RESPONSE_TIMEOUT, NULL, &err);
313 if (!result || err) {
314 debug_error("g_dbus_connection_call_sync() for %s error (%s)", method, err ? err->message : NULL);
315 ret = MM_ERROR_SOUND_INTERNAL;
319 g_variant_get(result, "(i)", &idx);
321 debug_error("[%s] failure, filename(%s)/role(%s)/gain(%s)/stream idx(%d)",
322 method, filename, role, vol_gain_type, idx);
323 ret = MM_ERROR_SOUND_INTERNAL;
326 debug_msg("[%s] success, filename(%s)/role(%s)/gain(%s)/stream idx(%d)",
327 method, filename, role, vol_gain_type, idx);
329 } else if (g_strcmp0(method, PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP) == 0) {
330 ret = __verify_input_file(filename);
331 if (ret != MM_ERROR_NONE)
334 result = g_dbus_connection_call_sync(conn, PA_BUS_NAME,
335 PA_SOUND_PLAYER_OBJECT_PATH,
336 PA_SOUND_PLAYER_INTERFACE,
337 PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP,
338 g_variant_new("(s)", filename),
339 NULL, G_DBUS_CALL_FLAGS_NONE, PA_SOUND_RESPONSE_TIMEOUT, NULL, &err);
340 if (!result || err) {
341 debug_error("g_dbus_connection_call_sync() for %s error (%s)", method, err ? err->message : NULL);
342 ret = MM_ERROR_SOUND_INTERNAL;
345 debug_msg("[%s] done, filename(%s)", method, filename);
347 } else if (g_strcmp0(method, PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP_ALL) == 0) {
348 result = g_dbus_connection_call_sync(conn, PA_BUS_NAME,
349 PA_SOUND_PLAYER_OBJECT_PATH,
350 PA_SOUND_PLAYER_INTERFACE,
351 PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP_ALL,
353 NULL, G_DBUS_CALL_FLAGS_NONE, PA_SOUND_RESPONSE_TIMEOUT, NULL, &err);
354 if (!result || err) {
355 debug_error("g_dbus_connection_call_sync() for %s error (%s)", method, err ? err->message : NULL);
356 ret = MM_ERROR_SOUND_INTERNAL;
359 debug_msg("[%s] done", method);
362 debug_error("Invalid Method : %s", method);
363 ret = MM_ERROR_INVALID_ARGUMENT;
370 g_variant_unref(result);
372 g_object_unref(conn);
376 #endif /* USE_PIPE */