1 // Copyright (c) 2012- PPSSPP Project.
2 
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0 or later versions.
6 
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 // GNU General Public License 2.0 for more details.
11 
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
14 
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17 
18 #include "Common/Serialize/Serializer.h"
19 #include "Common/Serialize/SerializeFuncs.h"
20 #include "Core/HLE/HLE.h"
21 #include "Core/HLE/FunctionWrappers.h"
22 #include "Core/HLE/sceAudiocodec.h"
23 #include "Core/MemMap.h"
24 #include "Core/Reporting.h"
25 #include "Core/HW/SimpleAudioDec.h"
26 
27 // Following kaien_fr's sample code https://github.com/hrydgard/ppsspp/issues/5620#issuecomment-37086024
28 // Should probably store the EDRAM get/release status somewhere within here, etc.
29 struct AudioCodecContext {
30 	u32_le unknown[6];
31 	u32_le inDataPtr;   // 6
32 	u32_le inDataSize;  // 7
33 	u32_le outDataPtr;  // 8
34 	u32_le audioSamplesPerFrame;  // 9
35 	u32_le inDataSizeAgain;  // 10  ??
36 };
37 
38 // audioList is to store current playing audios.
39 static std::map<u32, SimpleAudio *> audioList;
40 
41 static bool oldStateLoaded = false;
42 
43 // find the audio decoder for corresponding ctxPtr in audioList
findDecoder(u32 ctxPtr)44 static SimpleAudio *findDecoder(u32 ctxPtr) {
45 	auto it = audioList.find(ctxPtr);
46 	if (it != audioList.end()) {
47 		return it->second;
48 	}
49 	return NULL;
50 }
51 
52 // remove decoder from audioList
removeDecoder(u32 ctxPtr)53 static bool removeDecoder(u32 ctxPtr) {
54 	auto it = audioList.find(ctxPtr);
55 	if (it != audioList.end()) {
56 		delete it->second;
57 		audioList.erase(it);
58 		return true;
59 	}
60 	return false;
61 }
62 
clearDecoders()63 static void clearDecoders() {
64 	for (auto it = audioList.begin(), end = audioList.end(); it != end; it++) {
65 		delete it->second;
66 	}
67 	audioList.clear();
68 }
69 
__AudioCodecInit()70 void __AudioCodecInit() {
71 	oldStateLoaded = false;
72 }
73 
__AudioCodecShutdown()74 void __AudioCodecShutdown() {
75 	// We need to kill off any still opened codecs to not leak memory.
76 	clearDecoders();
77 }
78 
sceAudiocodecInit(u32 ctxPtr,int codec)79 static int sceAudiocodecInit(u32 ctxPtr, int codec) {
80 	if (IsValidCodec(codec)) {
81 		// Create audio decoder for given audio codec and push it into AudioList
82 		if (removeDecoder(ctxPtr)) {
83 			WARN_LOG_REPORT(HLE, "sceAudiocodecInit(%08x, %d): replacing existing context", ctxPtr, codec);
84 		}
85 		auto decoder = new SimpleAudio(codec);
86 		decoder->SetCtxPtr(ctxPtr);
87 		audioList[ctxPtr] = decoder;
88 		INFO_LOG(ME, "sceAudiocodecInit(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec));
89 		DEBUG_LOG(ME, "Number of playing sceAudioCodec audios : %d", (int)audioList.size());
90 		return 0;
91 	}
92 	ERROR_LOG_REPORT(ME, "sceAudiocodecInit(%08x, %i (%s)): Unknown audio codec %i", ctxPtr, codec, GetCodecName(codec), codec);
93 	return 0;
94 }
95 
sceAudiocodecDecode(u32 ctxPtr,int codec)96 static int sceAudiocodecDecode(u32 ctxPtr, int codec) {
97 	if (!ctxPtr){
98 		ERROR_LOG_REPORT(ME, "sceAudiocodecDecode(%08x, %i (%s)) got NULL pointer", ctxPtr, codec, GetCodecName(codec));
99 		return -1;
100 	}
101 
102 	if (IsValidCodec(codec)){
103 		// Use SimpleAudioDec to decode audio
104 		auto ctx = PSPPointer<AudioCodecContext>::Create(ctxPtr);  // On stack, no need to allocate.
105 		int outbytes = 0;
106 		// find a decoder in audioList
107 		auto decoder = findDecoder(ctxPtr);
108 
109 		if (!decoder && oldStateLoaded) {
110 			// We must have loaded an old state that did not have sceAudiocodec information.
111 			// Fake it by creating the desired context.
112 			decoder = new SimpleAudio(codec);
113 			decoder->SetCtxPtr(ctxPtr);
114 			audioList[ctxPtr] = decoder;
115 		}
116 
117 		if (decoder != NULL) {
118 			// Decode audio
119 			decoder->Decode(Memory::GetPointer(ctx->inDataPtr), ctx->inDataSize, Memory::GetPointer(ctx->outDataPtr), &outbytes);
120 		}
121 		DEBUG_LOG(ME, "sceAudiocodecDec(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec));
122 		return 0;
123 	}
124 	ERROR_LOG_REPORT(ME, "UNIMPL sceAudiocodecDecode(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec));
125 	return 0;
126 }
127 
sceAudiocodecGetInfo(u32 ctxPtr,int codec)128 static int sceAudiocodecGetInfo(u32 ctxPtr, int codec) {
129 	ERROR_LOG_REPORT(ME, "UNIMPL sceAudiocodecGetInfo(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec));
130 	return 0;
131 }
132 
sceAudiocodecCheckNeedMem(u32 ctxPtr,int codec)133 static int sceAudiocodecCheckNeedMem(u32 ctxPtr, int codec) {
134 	WARN_LOG(ME, "UNIMPL sceAudiocodecCheckNeedMem(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec));
135 	return 0;
136 }
137 
sceAudiocodecGetEDRAM(u32 ctxPtr,int codec)138 static int sceAudiocodecGetEDRAM(u32 ctxPtr, int codec) {
139 	WARN_LOG(ME, "UNIMPL sceAudiocodecGetEDRAM(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec));
140 	return 0;
141 }
142 
sceAudiocodecReleaseEDRAM(u32 ctxPtr,int id)143 static int sceAudiocodecReleaseEDRAM(u32 ctxPtr, int id) {
144 	if (removeDecoder(ctxPtr)){
145 		INFO_LOG(ME, "sceAudiocodecReleaseEDRAM(%08x, %i)", ctxPtr, id);
146 		return 0;
147 	}
148 	WARN_LOG(ME, "UNIMPL sceAudiocodecReleaseEDRAM(%08x, %i)", ctxPtr, id);
149 	return 0;
150 }
151 
152 const HLEFunction sceAudiocodec[] = {
153 	{0X70A703F8, &WrapI_UI<sceAudiocodecDecode>,       "sceAudiocodecDecode",       'i', "xi"},
154 	{0X5B37EB1D, &WrapI_UI<sceAudiocodecInit>,         "sceAudiocodecInit",         'i', "xi"},
155 	{0X8ACA11D5, &WrapI_UI<sceAudiocodecGetInfo>,      "sceAudiocodecGetInfo",      'i', "xi"},
156 	{0X3A20A200, &WrapI_UI<sceAudiocodecGetEDRAM>,     "sceAudiocodecGetEDRAM",     'i', "xi"},
157 	{0X29681260, &WrapI_UI<sceAudiocodecReleaseEDRAM>, "sceAudiocodecReleaseEDRAM", 'i', "xi"},
158 	{0X9D3F790C, &WrapI_UI<sceAudiocodecCheckNeedMem>, "sceAudiocodecCheckNeedMem", 'i', "xi"},
159 	{0X59176A0F, nullptr,                              "sceAudiocodec_59176A0F",    '?', ""  },
160 };
161 
Register_sceAudiocodec()162 void Register_sceAudiocodec()
163 {
164 	RegisterModule("sceAudiocodec", ARRAY_SIZE(sceAudiocodec), sceAudiocodec);
165 }
166 
__sceAudiocodecDoState(PointerWrap & p)167 void __sceAudiocodecDoState(PointerWrap &p){
168 	auto s = p.Section("AudioList", 0, 2);
169 	if (!s) {
170 		oldStateLoaded = true;
171 		return;
172 	}
173 
174 	int count = (int)audioList.size();
175 	Do(p, count);
176 
177 	if (count > 0) {
178 		if (p.mode == PointerWrap::MODE_READ) {
179 			clearDecoders();
180 
181 			// loadstate if audioList is nonempty
182 			auto codec_ = new int[count];
183 			auto ctxPtr_ = new u32[count];
184 			// These sizeof(pointers) are wrong, but kept to avoid breaking on old saves.
185 			// They're not used in new savestates.
186 #ifdef __clang__
187 #pragma clang diagnostic push
188 #pragma clang diagnostic ignored "-Wunknown-warning-option"
189 #pragma clang diagnostic ignored "-Wsizeof-pointer-div"
190 #endif
191 			DoArray(p, codec_, s >= 2 ? count : (int)ARRAY_SIZE(codec_));
192 			DoArray(p, ctxPtr_, s >= 2 ? count : (int)ARRAY_SIZE(ctxPtr_));
193 			for (int i = 0; i < count; i++) {
194 				auto decoder = new SimpleAudio(codec_[i]);
195 				decoder->SetCtxPtr(ctxPtr_[i]);
196 				audioList[ctxPtr_[i]] = decoder;
197 			}
198 #ifdef __clang__
199 #pragma clang diagnostic pop
200 #endif
201 			delete[] codec_;
202 			delete[] ctxPtr_;
203 		}
204 		else
205 		{
206 			// savestate if audioList is nonempty
207 			// Some of this is only necessary in Write but won't really hurt Measure.
208 			auto codec_ = new int[count];
209 			auto ctxPtr_ = new u32[count];
210 			int i = 0;
211 			for (auto it = audioList.begin(), end = audioList.end(); it != end; it++) {
212 				const SimpleAudio *decoder = it->second;
213 				codec_[i] = decoder->GetAudioType();
214 				ctxPtr_[i] = decoder->GetCtxPtr();
215 				i++;
216 			}
217 			DoArray(p, codec_, count);
218 			DoArray(p, ctxPtr_, count);
219 			delete[] codec_;
220 			delete[] ctxPtr_;
221 		}
222 	}
223 }
224