Added a sounds component that implements the Notifications interface and is used to
[harmattan/cameraplus] / imports / sounds.cpp
1 /*!
2  * This file is part of CameraPlus.
3  *
4  * Copyright (C) 2012 Mohammed Sameer <msameer@foolab.org>
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "sounds.h"
22 #include <QDebug>
23 #include "qtcamconfig.h"
24
25 #define CAMERA_IMAGE_START_SOUND_ID "camera-image-start"
26 #define CAMERA_IMAGE_END_SOUND_ID "camera-image-end"
27 #define CAMERA_VIDEO_START_SOUND_ID "camera-video-start"
28 #define CAMERA_VIDEO_STOP_SOUND_ID "camera-video-stop"
29
30 // TODO: video start sound should block
31 // TODO: video end sound should not appear in the video
32 // TODO: monitor pulse audio death and re-upload our samples
33 // TODO: if we are using headphones then sound volume might be loud. Detect and lower it.
34 Sounds::Sounds(QObject *parent) :
35   QObject(parent),
36   m_muted(false),
37   m_ctx(0),
38   m_conf(0) {
39
40   // No idea why but canberra will not cache without that!!!
41   setenv("CANBERRA_EVENT_LOOKUP", "1", 1);
42 }
43
44 Sounds::~Sounds() {
45   if (m_ctx) {
46     ca_context_destroy(m_ctx);
47     m_ctx = 0;
48   }
49 }
50
51 void Sounds::setConfig(QtCamConfig *conf) {
52   m_conf = conf;
53 }
54
55 void Sounds::imageCaptureStarted() {
56   if (isMuted() || !m_ctx) {
57     return;
58   }
59
60   play(CAMERA_IMAGE_START_SOUND_ID);
61 }
62
63 void Sounds::imageCaptureEnded() {
64   if (isMuted() || !m_ctx) {
65     return;
66   }
67
68   play(CAMERA_IMAGE_END_SOUND_ID);
69 }
70
71 void Sounds::videoRecordingStarted() {
72   if (isMuted() || !m_ctx) {
73     return;
74   }
75
76   play(CAMERA_VIDEO_START_SOUND_ID);
77 }
78
79 void Sounds::videoRecordingEnded() {
80   if (isMuted() || !m_ctx) {
81     return;
82   }
83
84   play(CAMERA_VIDEO_STOP_SOUND_ID);
85 }
86
87 bool Sounds::isMuted() const {
88   return m_muted;
89 }
90
91 void Sounds::setMuted(bool mute) {
92   if (mute != m_muted) {
93     m_muted = mute;
94     emit muteChanged();
95   }
96 }
97
98 void Sounds::reload() {
99   if (m_ctx) {
100     ca_context_destroy(m_ctx);
101     m_ctx = 0;
102   }
103
104   if (int code = ca_context_create(&m_ctx) != CA_SUCCESS) {
105     qWarning() << "Failed to create canberra context" << ca_strerror(code) << code;
106     return;
107   }
108
109   if (int code = ca_context_set_driver(m_ctx, "pulse") != CA_SUCCESS) {
110     qWarning() << "Failed to set canberra driver to pulse audio" << ca_strerror(code) << code;
111   }
112
113   if (int code = ca_context_change_props(m_ctx,
114                                          CA_PROP_MEDIA_ROLE, "camera-sound-effect",
115                                          NULL) != CA_SUCCESS) {
116     qWarning() << "Failed to set context properties" << ca_strerror(code) << code;
117   }
118
119   if (int code = ca_context_open(m_ctx) != CA_SUCCESS) {
120     qWarning() << "Failed to open canberra context" << ca_strerror(code) << code;
121     ca_context_destroy(m_ctx);
122     m_ctx = 0;
123     return;
124   }
125
126   cache(m_conf->imageCaptureStartedSound(), CAMERA_IMAGE_START_SOUND_ID);
127   cache(m_conf->imageCaptureEndedSound(), CAMERA_IMAGE_END_SOUND_ID);
128   cache(m_conf->videoRecordingStartedSound(), CAMERA_VIDEO_START_SOUND_ID);
129   cache(m_conf->videoRecordingEndedSound(), CAMERA_VIDEO_STOP_SOUND_ID);
130 }
131
132 void Sounds::cache(const QString& path, const char *id) {
133   if (path.isEmpty()) {
134     return;
135   }
136
137   if (int code = ca_context_cache(m_ctx,
138                                   CA_PROP_EVENT_ID, id,
139                                   CA_PROP_MEDIA_FILENAME, path.toLocal8Bit().data(),
140                                   CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
141                                   NULL) != CA_SUCCESS) {
142     qWarning() << "Failed to cache" << path << ca_strerror(code) << code;
143   }
144 }
145
146 void Sounds::play(const char *id) {
147   if (int code = ca_context_play(m_ctx, 0,
148                                  CA_PROP_CANBERRA_VOLUME, "0.0", // Odd, volume has to be a char *
149                                  CA_PROP_EVENT_ID, id,
150                                  CA_PROP_MEDIA_ROLE, "camera-sound-effect",
151                                  NULL) != CA_SUCCESS) {
152     qDebug() << "Failed to play sound" << ca_strerror(code) << code;
153   }
154 }