I've been down this road before and it depends on what precisely you're trying to do with the walls, and whether you need interior walls etc.
Just Exterior Bounding Walls:
If you just need the exterior walls of the room, then the simplest method is to use the GetBoundarySegments method. Every room, space, and area in Revit inherits from the SpatialElement class which has this method, and will return a list of RoomBoundarySegments, each one containing the curve segment, and what element is creating it (wall, room boundary line, etc.). This will solve that whole wall centroid being outside of the room problem.
It's probably worth noting that this method will not work in precise situations with linked files, a bug I documented here. I haven't tested it since then but I would be very surprised if Revit actually fixed it since so it's worth watching out for.
All Walls Including Non Bounding Interior Walls:
Otherwise if you need walls that are non bounding and interior to the room, I found that in general, all of Revit's projection methods are somewhat slow (and algorithms using them often have edge cases that might be missed), but like others have said, I found both the BoundingBoxIntersector and the isPointInRoom methods to be very fast and performative. To get *all* of the walls associated with a room, including interior ones, I would first use the boundary segments method to get the bounding walls / walls that won't be *inside* the room. Then, use the bounding box intersector filter to get all the walls in the model that intersect your room (like you said, bounding boxes are rectangular and don't rotate so this will be rough and pick up walls from other rooms). Set aside the walls that you already know are the boundaries, then for the rest, check the coordinates of the end point and midpoint of each wall segment, to see if any of those points are in the room with the isPointInRoom method. If one of them is then that wall cuts through the interior of the room.
I believe the only situation that this might miss, is if you had a room that was bounded by room boundary lines, and a super long non-bounding wall cut entirely through the room without any end points or midpoints landing within the room.
Floors And Ceilings:
Getting the floors and ceiling are somewhat more complicated and I believe will likely necessitate projection if you want to be able to capture every bulk head / potential split level etc. What I would do is start with your room's bounding box. Then generate a grid of points with even spacing inside this box (maybe 0.5 - 1ft apart), halfway between the top and bottom. Test each point with the isPointInRoom method, and discard the ones that aren't. You'll now have an irregular grid of points all located within the bounds of your room. Now for each point project a ray upwards and one downwards and capture any floors or ceilings that they intersect before leaving your room bounds. This should reliably capture every single floor and ceiling associated with a room, and if it is missing any, you can just increase the resolution of your point grid.