1 package org.daisy.pipeline.tts;
2
3 import java.util.concurrent.Semaphore;
4
5 import javax.sound.sampled.AudioInputStream;
6
7 import org.slf4j.Logger;
8 import org.slf4j.LoggerFactory;
9
10
11
12
13
14
15
16
17
18 public class AudioFootprintMonitor {
19
20 public class MemoryException extends Exception {
21 public MemoryException(String message) {
22 super(message);
23 }
24
25 public MemoryException(int bytes) {
26 super("tried to allocate " + bytes + " bytes (" + bytes / 1000000.0 + "MB)");
27 }
28 }
29
30 private Logger ServerLogger = LoggerFactory.getLogger(AudioFootprintMonitor.class);
31
32 public AudioFootprintMonitor() {
33 String maxMemProp = System.getProperty("org.daisy.pipeline.tts.maxmem");
34 long maxMem;
35 if (maxMemProp != null) {
36 maxMem = Long.valueOf(maxMemProp) * 1048576;
37 } else {
38 maxMem = Runtime.getRuntime().maxMemory();
39 if (maxMem == Long.MAX_VALUE)
40 maxMem = 500 * 1048576;
41 else
42 maxMem /= 2;
43 }
44 if (maxMem > Integer.MAX_VALUE)
45 maxMem = Integer.MAX_VALUE;
46
47 mSpaceForTTS = (int) (2 * maxMem / 3);
48 mSpaceForEncoding = (int) (maxMem - mSpaceForTTS);
49
50
51 mPaddedEncodingSpace = mSpaceForEncoding - mSpaceForEncoding / 10;
52
53 mTTSCounter = new Semaphore(mSpaceForTTS, false);
54 mEncodingCounter = new Semaphore(mSpaceForEncoding, false);
55 }
56
57 public void acquireTTSMemory(AudioInputStream audio) throws MemoryException {
58 acquireTTSMemory(getFootprint(audio));
59 }
60
61 public void acquireTTSMemory(int size) throws MemoryException {
62 if (!mTTSCounter.tryAcquire(size))
63 throw new MemoryException(size);
64 }
65
66
67
68
69
70 public void releaseTTSMemory(AudioInputStream audio) {
71 releaseTTSMemory(getFootprint(audio));
72 }
73
74 public void releaseTTSMemory(int size) {
75 mTTSCounter.release(size);
76 }
77
78 public int getSpaceForTTS() {
79 return mSpaceForTTS;
80 }
81
82 public int getUnreleasedTTSMem() {
83 return mSpaceForTTS - mTTSCounter.availablePermits();
84 }
85
86
87
88
89
90 public void transferToEncoding(int ttsMemSize, int encodingMemSize)
91 throws InterruptedException {
92 acquireEncodersMemory(encodingMemSize);
93 mTTSCounter.release(ttsMemSize);
94 }
95
96 public void acquireEncodersMemory(int size) throws InterruptedException {
97 if (size > mPaddedEncodingSpace) {
98 ServerLogger.debug("try to acquire " + size + " bytes, exceeding the max size = "
99 + mPaddedEncodingSpace + "MB");
100 mEncodingCounter.acquire(mPaddedEncodingSpace);
101 } else
102 mEncodingCounter.acquire(size);
103 }
104
105 public void releaseEncodersMemory(int size) {
106 if (size > mPaddedEncodingSpace)
107 mEncodingCounter.release(mPaddedEncodingSpace);
108 else
109 mEncodingCounter.release(size);
110 }
111
112 public int getSpaceForEncoding() {
113 return mSpaceForEncoding;
114 }
115
116 public int getUnreleasedEncondingMem() {
117 return mSpaceForEncoding - mEncodingCounter.availablePermits();
118 }
119
120 private int mPaddedEncodingSpace;
121 private int mSpaceForTTS;
122 private int mSpaceForEncoding;
123 private Semaphore mTTSCounter;
124 private Semaphore mEncodingCounter;
125
126
127
128
129 public static int getFootprint(AudioInputStream audio) {
130 return Math.multiplyExact(Math.toIntExact(audio.getFrameLength()),
131 audio.getFormat().getFrameSize());
132 }
133 }