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.
34 #include "include/mm_sound_common.h"
38 #define PULSEAUDIO_READY "/tmp/.pulseaudio_ready"
41 #define PA_BUS_NAME "org.pulseaudio.Server"
42 #define PA_SOUND_PLAYER_OBJECT_PATH "/org/pulseaudio/SoundPlayer"
43 #define PA_SOUND_PLAYER_INTERFACE "org.pulseaudio.SoundPlayer"
44 #define PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_PLAY "SimplePlay"
46 #define KEYTONE_PATH "/tmp/keytone" /* Keytone pipe path */
47 #define FILE_FULL_PATH 1024 /* File path length */
48 #define ROLE_NAME_LEN 64 /* Role name length */
49 #define VOLUME_GAIN_TYPE_LEN 64 /* Volume gain type length */
51 #define AUDIO_VOLUME_CONFIG_TYPE(vol) (vol & 0x00FF)
52 #define AUDIO_VOLUME_CONFIG_GAIN(vol) (vol & 0xFF00)
54 #define MAX_WRITE_RETRY 50
55 #define WRITE_RETRY_INTERVAL_MS 20
57 typedef struct ipc_data {
58 char filename[FILE_FULL_PATH];
59 char role[ROLE_NAME_LEN];
60 char volume_gain_type[VOLUME_GAIN_TYPE_LEN];
68 static int _mm_sound_play_keysound(const char *filename, int volume_config, ipc_type_t ipc_type);
70 static const char* convert_volume_type_to_role(int volume_type)
72 debug_log("volume_type(%d)", volume_type);
73 switch (volume_type) {
74 case VOLUME_TYPE_MEDIA:
76 case VOLUME_TYPE_SYSTEM:
78 case VOLUME_TYPE_NOTIFICATION:
79 return "notification";
80 case VOLUME_TYPE_ALARM:
82 case VOLUME_TYPE_VOICE:
84 case VOLUME_TYPE_RINGTONE:
85 return "ringtone-call";
87 debug_warning("not supported type(%d), we change it SYSTEM type forcibly", volume_type);
92 static const char* convert_volume_gain_type_to_string(int volume_gain_type)
94 debug_log("volume_gain_type(0x%x)", volume_gain_type);
95 switch (volume_gain_type) {
96 case VOLUME_GAIN_DEFAULT:
98 case VOLUME_GAIN_DIALER:
100 case VOLUME_GAIN_TOUCH:
104 case VOLUME_GAIN_SHUTTER1:
106 case VOLUME_GAIN_SHUTTER2:
108 case VOLUME_GAIN_CAMCORDING:
110 case VOLUME_GAIN_MIDI:
112 case VOLUME_GAIN_BOOTING:
114 case VOLUME_GAIN_VIDEO:
116 case VOLUME_GAIN_TTS:
124 int mm_sound_play_keysound(const char *filename, int volume_config)
126 return _mm_sound_play_keysound(filename, volume_config, IPC_TYPE_PIPE);
130 static bool _mm_sound_check_pa_ready()
133 static bool is_pa_ready = false;
138 debug_msg("LwipcIsDone start >> ");
139 ret = LwipcIsDone(PULSEAUDIO_READY);
140 debug_msg("LwipcIsDone end << %d", ret);
142 is_pa_ready = (ret > 0) ? true : false;
148 static int _mm_sound_play_keysound(const char *filename, int volume_config, ipc_type_t ipc_type)
150 int ret = MM_ERROR_NONE;
151 const char *role = NULL;
152 const char *vol_gain_type = NULL;
153 int retry_remaining = MAX_WRITE_RETRY;
156 if (!_mm_sound_check_pa_ready()) {
157 debug_error("Pulseaudio is not ready!");
158 return MM_ERROR_SOUND_INVALID_STATE;
163 return MM_ERROR_SOUND_INVALID_FILE;
165 /* Check whether file exists */
166 if (access(filename, F_OK) == -1) {
169 strerror_r(errno, str_error, sizeof(str_error));
170 debug_error("file [%s] doesn't exists : [%s][%d]", filename, str_error, errno);
172 return MM_ERROR_SOUND_FILE_NOT_FOUND;
175 /* convert volume type to role/volume gain */
176 role = convert_volume_type_to_role(AUDIO_VOLUME_CONFIG_TYPE(volume_config));
178 vol_gain_type = convert_volume_gain_type_to_string(AUDIO_VOLUME_CONFIG_GAIN(volume_config));
180 if (ipc_type == IPC_TYPE_PIPE) {
181 size_t size_to_write = sizeof(ipc_t);
184 ipc_t data = { { 0, }, { 0, }, { 0, } };
187 fd = open(KEYTONE_PATH, O_WRONLY | O_NONBLOCK);
191 strerror_r(errno, str_error, sizeof(str_error));
192 debug_error("Fail to open pipe: [%s][%d]", str_error, errno);
194 return MM_ERROR_SOUND_INTERNAL;
197 /* convert volume type to role/volume gain */
199 MMSOUND_STRNCPY(data.role, role, ROLE_NAME_LEN);
201 MMSOUND_STRNCPY(data.volume_gain_type, vol_gain_type, VOLUME_GAIN_TYPE_LEN);
202 MMSOUND_STRNCPY(data.filename, filename, FILE_FULL_PATH);
204 debug_msg("filepath=[%s], role=[%s], volume_gain_type=[%s]", data.filename, data.role, data.volume_gain_type);
208 written = write(fd, &data, size_to_write);
213 strerror_r(errsv, str_error, sizeof(str_error));
214 debug_error("[%d] Fail to write, written = %zd, [%s][%d]",
215 MAX_WRITE_RETRY - retry_remaining, written, str_error, errsv);
217 if (errsv != EAGAIN || --retry_remaining == 0) {
218 ret = MM_ERROR_SOUND_INTERNAL;
222 usleep(WRITE_RETRY_INTERVAL_MS * 1000);
223 } else if (retry_remaining != MAX_WRITE_RETRY) {
224 debug_msg("retry success!!");
226 } while (written != size_to_write);
231 } else if (ipc_type == IPC_TYPE_DBUS) {
232 GVariant *result = NULL;
233 GDBusConnection *conn = NULL;
237 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
239 debug_error("g_bus_get_sync() error (%s)", err ? err->message : NULL);
240 ret = MM_ERROR_SOUND_INTERNAL;
242 result = g_dbus_connection_call_sync(conn,
244 PA_SOUND_PLAYER_OBJECT_PATH,
245 PA_SOUND_PLAYER_INTERFACE,
246 PA_SOUND_PLAYER_METHOD_NAME_SIMPLE_PLAY,
247 g_variant_new("(sss)", filename, role, vol_gain_type),
249 G_DBUS_CALL_FLAGS_NONE,
253 if (!result || err) {
254 debug_error("g_dbus_connection_call_sync() for SIMPLE_PLAY error (%s)", err ? err->message : NULL);
255 ret = MM_ERROR_SOUND_INTERNAL;
257 g_variant_get(result, "(i)", &idx);
259 debug_error("SIMPLE_PLAY failure, filename(%s)/role(%s)/gain(%s)/stream idx(%d)", filename, role, vol_gain_type, idx);
260 ret = MM_ERROR_SOUND_INTERNAL;
262 debug_msg("SIMPLE_PLAY success, filename(%s)/role(%s)/gain(%s)/stream idx(%d)", filename, role, vol_gain_type, idx);
264 g_variant_unref(result);
266 g_object_unref(conn);