1 /**
2 * @file sess.c AudioUnit sound driver - session
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6 #include <AudioUnit/AudioUnit.h>
7 #include <AudioToolbox/AudioToolbox.h>
8 #include <re.h>
9 #include <baresip.h>
10 #include "audiounit.h"
11
12
13 struct audiosess {
14 struct list sessl;
15 };
16
17
18 struct audiosess_st {
19 struct audiosess *as;
20 struct le le;
21 audiosess_int_h *inth;
22 void *arg;
23 };
24
25
26 static struct audiosess *gas;
27
28
29 #if TARGET_OS_IPHONE
propListener(void * inClientData,AudioSessionPropertyID inID,UInt32 inDataSize,const void * inData)30 static void propListener(void *inClientData, AudioSessionPropertyID inID,
31 UInt32 inDataSize, const void *inData)
32 {
33 struct audiosess *sess = inClientData;
34 CFDictionaryRef dref = inData;
35 CFNumberRef nref;
36 SInt32 reason = 0;
37
38 (void)inDataSize;
39 (void)sess;
40
41 if (kAudioSessionProperty_AudioRouteChange != inID)
42 return;
43
44 nref = CFDictionaryGetValue(
45 dref,
46 CFSTR(kAudioSession_AudioRouteChangeKey_Reason)
47 );
48
49 CFNumberGetValue(nref, kCFNumberSInt32Type, &reason);
50
51 info("audiounit: AudioRouteChange - reason %d\n", reason);
52 }
53 #endif
54
55
sess_destructor(void * arg)56 static void sess_destructor(void *arg)
57 {
58 struct audiosess_st *st = arg;
59
60 list_unlink(&st->le);
61 mem_deref(st->as);
62 }
63
64
destructor(void * arg)65 static void destructor(void *arg)
66 {
67 struct audiosess *as = arg;
68 #if TARGET_OS_IPHONE
69 AudioSessionPropertyID id = kAudioSessionProperty_AudioRouteChange;
70
71 AudioSessionRemovePropertyListenerWithUserData(id, propListener, as);
72 AudioSessionSetActive(false);
73 #endif
74
75 list_flush(&as->sessl);
76
77 gas = NULL;
78 }
79
80
audiosess_alloc(struct audiosess_st ** stp,audiosess_int_h * inth,void * arg)81 int audiosess_alloc(struct audiosess_st **stp,
82 audiosess_int_h *inth, void *arg)
83 {
84 struct audiosess_st *st = NULL;
85 struct audiosess *as = NULL;
86 int err = 0;
87 bool created = false;
88 #if TARGET_OS_IPHONE
89 AudioSessionPropertyID id = kAudioSessionProperty_AudioRouteChange;
90 UInt32 category;
91 OSStatus ret;
92 #endif
93
94 if (!stp)
95 return EINVAL;
96
97 #if TARGET_OS_IPHONE
98 /* Must be done for all modules */
99 category = kAudioSessionCategory_PlayAndRecord;
100 ret = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,
101 sizeof(category), &category);
102 if (ret) {
103 warning("audiounit: Audio Category: %d\n", ret);
104 return EINVAL;
105 }
106 #endif
107
108 if (gas)
109 goto makesess;
110
111 as = mem_zalloc(sizeof(*as), destructor);
112 if (!as)
113 return ENOMEM;
114
115 #if TARGET_OS_IPHONE
116 ret = AudioSessionSetActive(true);
117 if (ret) {
118 warning("audiounit: AudioSessionSetActive: %d\n", ret);
119 err = ENOSYS;
120 goto out;
121 }
122
123 ret = AudioSessionAddPropertyListener(id, propListener, as);
124 if (ret) {
125 warning("audiounit: AudioSessionAddPropertyListener: %d\n",
126 ret);
127 err = EINVAL;
128 goto out;
129 }
130 #endif
131
132 gas = as;
133 created = true;
134
135 makesess:
136 st = mem_zalloc(sizeof(*st), sess_destructor);
137 if (!st) {
138 err = ENOMEM;
139 goto out;
140 }
141 st->inth = inth;
142 st->arg = arg;
143 st->as = created ? gas : mem_ref(gas);
144
145 list_append(&gas->sessl, &st->le, st);
146
147 out:
148 if (err) {
149 mem_deref(as);
150 mem_deref(st);
151 }
152 else {
153 *stp = st;
154 }
155
156 return err;
157 }
158
159
audiosess_interrupt(bool start)160 void audiosess_interrupt(bool start)
161 {
162 struct le *le;
163
164 if (!gas)
165 return;
166
167 for (le = gas->sessl.head; le; le = le->next) {
168
169 struct audiosess_st *st = le->data;
170
171 if (st->inth)
172 st->inth(start, st->arg);
173 }
174 }
175