Skip to content

Commit 6bf2950

Browse files
committed
apple: clean up coremidi lifetime a little bit
1 parent 9fdd60a commit 6bf2950

File tree

3 files changed

+54
-32
lines changed

3 files changed

+54
-32
lines changed

midi/drivers/coremidi.c

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,23 @@
2222
#include "../../verbosity.h"
2323

2424
#define CORE_MIDI_QUEUE_SIZE 1024
25+
#define CORE_MIDI_MAX_EVENT_SIZE 256
26+
27+
/* Persistent CoreMIDI client shared across all driver instances.
28+
* This avoids XPC race conditions from rapid client dispose/recreate cycles.
29+
* CoreMIDI clients are designed to be long-lived; ports are disposable. */
30+
static MIDIClientRef shared_midi_client = 0;
31+
32+
typedef struct
33+
{
34+
uint8_t data[CORE_MIDI_MAX_EVENT_SIZE]; /* Inline data buffer */
35+
size_t data_size;
36+
uint32_t delta_time;
37+
} coremidi_event_t;
2538

2639
typedef struct
2740
{
28-
midi_event_t events[CORE_MIDI_QUEUE_SIZE]; /* Event buffer */
41+
coremidi_event_t events[CORE_MIDI_QUEUE_SIZE]; /* Event buffer */
2942
int read_index; /* Current read position */
3043
int write_index; /* Current write position */
3144
} coremidi_queue_t;
@@ -43,11 +56,21 @@ typedef struct
4356
/* Write to the queue */
4457
static bool coremidi_queue_write(coremidi_queue_t *q, const midi_event_t *ev)
4558
{
59+
size_t copy_size;
4660
int next_write = (q->write_index + 1) % CORE_MIDI_QUEUE_SIZE;
4761
if (next_write == q->read_index) /* Queue full */
4862
return false;
4963

50-
memcpy(&q->events[q->write_index], ev, sizeof(*ev));
64+
/* Validate event data size */
65+
if (!ev->data || ev->data_size == 0 || ev->data_size > CORE_MIDI_MAX_EVENT_SIZE)
66+
return false;
67+
68+
/* Copy data inline instead of storing pointer */
69+
copy_size = ev->data_size;
70+
memcpy(q->events[q->write_index].data, ev->data, copy_size);
71+
q->events[q->write_index].data_size = copy_size;
72+
q->events[q->write_index].delta_time = ev->delta_time;
73+
5174
q->write_index = next_write;
5275
return true;
5376
}
@@ -92,23 +115,30 @@ static void midi_read_callback(const MIDIPacketList *pktlist,
92115
static void *coremidi_init(const char *input, const char *output)
93116
{
94117
OSStatus err;
95-
coremidi_t *d = (coremidi_t *)calloc(1, sizeof(coremidi_t));
96-
if (!d)
118+
coremidi_t *d;
119+
120+
/* Create persistent client on first call */
121+
if (!shared_midi_client)
97122
{
98-
RARCH_ERR("[MIDI] Out of memory.\n");
99-
return NULL;
123+
err = MIDIClientCreate(CFSTR("RetroArch MIDI Client"),
124+
NULL, NULL, &shared_midi_client);
125+
if (err != noErr)
126+
{
127+
RARCH_ERR("[MIDI] MIDIClientCreate failed: %d.\n", err);
128+
return NULL;
129+
}
130+
RARCH_LOG("[MIDI] Created persistent CoreMIDI client.\n");
100131
}
101132

102-
err = MIDIClientCreate(CFSTR("RetroArch MIDI Client"),
103-
NULL, NULL, &d->client);
104-
if (err != noErr)
133+
d = (coremidi_t *)calloc(1, sizeof(coremidi_t));
134+
if (!d)
105135
{
106-
RARCH_ERR("[MIDI] MIDIClientCreate failed: %d.\n", err);
107-
free(d);
136+
RARCH_ERR("[MIDI] Out of memory.\n");
108137
return NULL;
109138
}
110139

111-
RARCH_LOG("[MIDI] CoreMIDI client created successfully.\n");
140+
/* Store reference to shared client */
141+
d->client = shared_midi_client;
112142

113143
/* Create input port if specified */
114144
if (input)
@@ -118,13 +148,9 @@ static void *coremidi_init(const char *input, const char *output)
118148
if (err != noErr)
119149
{
120150
RARCH_ERR("[MIDI] MIDIInputPortCreate failed: %d.\n", err);
121-
MIDIClientDispose(d->client);
122151
free(d);
123152
return NULL;
124153
}
125-
}
126-
else
127-
{
128154
RARCH_LOG("[MIDI] CoreMIDI input port created successfully.\n");
129155
}
130156

@@ -138,13 +164,9 @@ static void *coremidi_init(const char *input, const char *output)
138164
RARCH_ERR("[MIDI] MIDIOutputPortCreate failed: %d.\n", err);
139165
if (d->input_port)
140166
MIDIPortDispose(d->input_port);
141-
MIDIClientDispose(d->client);
142167
free(d);
143168
return NULL;
144169
}
145-
}
146-
else
147-
{
148170
RARCH_LOG("[MIDI] CoreMIDI output port created successfully.\n");
149171
}
150172

@@ -331,7 +353,11 @@ static bool coremidi_queue_read(coremidi_queue_t *q, midi_event_t *ev)
331353
if (q->read_index == q->write_index) /* Queue empty */
332354
return false;
333355

334-
memcpy(ev, &q->events[q->read_index], sizeof(*ev));
356+
/* Return pointer to inline data buffer */
357+
ev->data = q->events[q->read_index].data;
358+
ev->data_size = q->events[q->read_index].data_size;
359+
ev->delta_time = q->events[q->read_index].delta_time;
360+
335361
q->read_index = (q->read_index + 1) % CORE_MIDI_QUEUE_SIZE;
336362
return true;
337363
}
@@ -443,23 +469,18 @@ static void coremidi_free(void *p)
443469
/* Clean up MIDI resources */
444470
if (d->input_port)
445471
{
446-
RARCH_LOG("[MIDI] Disconnecting input port...\n");
447-
MIDIPortDisconnectSource(d->input_port, d->input_endpoint);
472+
RARCH_LOG("[MIDI] Disconnecting and disposing input port...\n");
473+
if (d->input_endpoint)
474+
MIDIPortDisconnectSource(d->input_port, d->input_endpoint);
448475
MIDIPortDispose(d->input_port);
449476
}
450477

451478
if (d->output_port)
452479
{
453-
RARCH_LOG("[MIDI] Disconnecting output port...\n");
454-
MIDIPortDisconnectSource(d->output_port, d->output_endpoint);
480+
RARCH_LOG("[MIDI] Disposing output port...\n");
455481
MIDIPortDispose(d->output_port);
456482
}
457483

458-
if (d->client)
459-
{
460-
RARCH_LOG("[MIDI] Disposing of CoreMIDI client...\n");
461-
MIDIClientDispose(d->client);
462-
}
463484

464485
/* Free the driver instance */
465486
free(d);

pkg/apple/RetroArch_iOS13.xcodeproj/xcshareddata/xcschemes/RetroArch iOS Debug.xcscheme

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
4646
customLLDBInitFile = "$(SRCROOT)/LLDBInitFile"
4747
disableMainThreadChecker = "YES"
48-
disablePerformanceAntipatternChecker = "YES"
4948
launchStyle = "0"
5049
useCustomWorkingDirectory = "NO"
5150
ignoresPersistentStateOnLaunch = "NO"
@@ -55,7 +54,8 @@
5554
enableGPUValidationMode = "1"
5655
allowLocationSimulation = "NO"
5756
viewDebuggingEnabled = "No"
58-
queueDebuggingEnabled = "No">
57+
queueDebuggingEnabled = "No"
58+
disablePerformanceAntipatternChecker = "YES">
5959
<BuildableProductRunnable
6060
runnableDebuggingMode = "0">
6161
<BuildableReference

pkg/apple/RetroArch_iOS13.xcodeproj/xcshareddata/xcschemes/RetroArch iOS Release.xcscheme

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
debugDocumentVersioning = "NO"
5252
debugXPCServices = "NO"
5353
debugServiceExtension = "internal"
54+
enableGPUFrameCaptureMode = "3"
5455
enableGPUValidationMode = "1"
5556
allowLocationSimulation = "NO"
5657
viewDebuggingEnabled = "No"

0 commit comments

Comments
 (0)