2 * This file is part of CameraPlus.
4 * Copyright (C) 2012 Mohammed Sameer <msameer@foolab.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "qtcamconfig.h"
25 #include <QWaitCondition>
27 #define CAMERA_IMAGE_START_SOUND_ID "camera-image-start"
28 #define CAMERA_IMAGE_END_SOUND_ID "camera-image-end"
29 #define CAMERA_VIDEO_START_SOUND_ID "camera-video-start"
30 #define CAMERA_VIDEO_STOP_SOUND_ID "camera-video-stop"
31 #define CAMERA_FOCUS_SOUND_ID "camera-focus"
33 // Odd, volume has to be a char *
34 #define CANBERRA_FULL_VOLUME "0.0"
36 // TODO: monitor pulse audio death and re-upload our samples
37 // TODO: if we are using headphones then sound volume might be loud. Detect and lower it.
39 Sounds::Sounds(QObject *parent) :
45 // No idea why but canberra will not cache without that!!!
46 setenv("CANBERRA_EVENT_LOOKUP", "1", 1);
51 ca_context_destroy(m_ctx);
56 void Sounds::setConfig(QtCamConfig *conf) {
60 void Sounds::imageCaptureStarted() {
61 if (isMuted() || !m_ctx) {
65 play(CAMERA_IMAGE_START_SOUND_ID);
68 void Sounds::imageCaptureEnded() {
69 if (isMuted() || !m_ctx) {
73 play(CAMERA_IMAGE_END_SOUND_ID);
76 void Sounds::videoRecordingStarted() {
77 if (isMuted() || !m_ctx) {
81 playAndBlock(CAMERA_VIDEO_START_SOUND_ID);
84 void Sounds::videoRecordingEnded() {
85 if (isMuted() || !m_ctx) {
89 play(CAMERA_VIDEO_STOP_SOUND_ID);
92 void Sounds::autoFocusAcquired() {
93 if (isMuted() || !m_ctx) {
97 play(CAMERA_FOCUS_SOUND_ID);
100 bool Sounds::isMuted() const {
104 void Sounds::setMuted(bool mute) {
105 if (mute != m_muted) {
111 void Sounds::reload() {
113 ca_context_destroy(m_ctx);
117 int code = CA_SUCCESS;
119 code = ca_context_create(&m_ctx);
120 if (code != CA_SUCCESS) {
121 qWarning() << "Failed to create canberra context" << ca_strerror(code) << code;
125 code = ca_context_set_driver(m_ctx, "pulse");
126 if (code != CA_SUCCESS) {
127 qWarning() << "Failed to set canberra driver to pulse audio" << ca_strerror(code) << code;
130 code = ca_context_change_props(m_ctx,
131 CA_PROP_MEDIA_ROLE, "camera-sound-effect",
133 if (code != CA_SUCCESS) {
134 qWarning() << "Failed to set context properties" << ca_strerror(code) << code;
137 code = ca_context_open(m_ctx);
138 if (code != CA_SUCCESS) {
139 qWarning() << "Failed to open canberra context" << ca_strerror(code) << code;
140 ca_context_destroy(m_ctx);
145 cache(m_conf->imageCaptureStartedSound(), CAMERA_IMAGE_START_SOUND_ID);
146 cache(m_conf->imageCaptureEndedSound(), CAMERA_IMAGE_END_SOUND_ID);
147 cache(m_conf->videoRecordingStartedSound(), CAMERA_VIDEO_START_SOUND_ID);
148 cache(m_conf->videoRecordingEndedSound(), CAMERA_VIDEO_STOP_SOUND_ID);
149 cache(m_conf->autoFocusAcquiredSound(), CAMERA_FOCUS_SOUND_ID);
152 void Sounds::cache(const QString& path, const char *id) {
153 if (path.isEmpty()) {
157 int code = ca_context_cache(m_ctx,
158 CA_PROP_EVENT_ID, id,
159 CA_PROP_MEDIA_FILENAME, path.toLocal8Bit().data(),
160 CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
162 if (code != CA_SUCCESS) {
163 qWarning() << "Failed to cache" << path << ca_strerror(code) << code;
167 void Sounds::play(const char *id) {
168 int code = ca_context_play(m_ctx, 0,
169 CA_PROP_CANBERRA_VOLUME, CANBERRA_FULL_VOLUME,
170 CA_PROP_EVENT_ID, id,
171 CA_PROP_MEDIA_ROLE, "camera-sound-effect",
173 if (code != CA_SUCCESS) {
174 qDebug() << "Failed to play sound" << ca_strerror(code) << code;
178 void ca_finish_callback(ca_context *c, uint32_t id, int error_code, void *userdata) {
181 Q_UNUSED(error_code);
183 QPair<QMutex *, QWaitCondition *> *data =
184 static_cast<QPair<QMutex *, QWaitCondition *> *>(userdata);
186 data->second->wakeAll();
189 void Sounds::playAndBlock(const char *id) {
193 if (ca_proplist_create(&p) != CA_SUCCESS) {
194 qDebug() << "Failed to create proplist";
198 ca_proplist_sets(p, CA_PROP_CANBERRA_VOLUME, CANBERRA_FULL_VOLUME);
199 ca_proplist_sets(p, CA_PROP_EVENT_ID, id);
200 ca_proplist_sets(p, CA_PROP_MEDIA_ROLE, "camera-sound-effect");
202 QPair<QMutex *, QWaitCondition *> data = qMakePair<QMutex *, QWaitCondition *>(&mutex, &cond);
206 int code = ca_context_play_full(m_ctx, 0, p, ca_finish_callback, &data);
208 if (code != CA_SUCCESS) {
209 qDebug() << "Failed to play sound" << ca_strerror(code) << code;
211 ca_proplist_destroy(p);
217 ca_proplist_destroy(p);